From 62d269e956361e43e4ca5e940fea8a56505dd97b Mon Sep 17 00:00:00 2001 From: Graham Barber Date: Sat, 22 Mar 2025 19:24:49 -0700 Subject: [PATCH] feat: add startup sync toggle and sync command --- actors/plugin.ts | 23 ++++++-- deno.lock | 137 +++++++++++++++++++++++++++++++++++++++++++++++ main.ts | 23 +++++++- settings.ts | 24 ++++++++- 4 files changed, 200 insertions(+), 7 deletions(-) diff --git a/actors/plugin.ts b/actors/plugin.ts index 763f032..51c7322 100644 --- a/actors/plugin.ts +++ b/actors/plugin.ts @@ -18,10 +18,15 @@ export type Input = LimitlessPluginSettings & { vault: Vault; }; +export type Events = { + type: "lifelogs::sync"; +}; + export const pluginActor = setup({ types: { context: {} as Context, input: {} as Input, + events: {} as Events, }, actors: { queryLifelogs, @@ -34,13 +39,15 @@ export const pluginActor = setup({ hasCursor: ({ context }) => Boolean(context.cursor), }, actions: { + persistLatestLog: (_, _params: { endDate: Date }) => { + // Write back to settings + throw new Error("This action must be provided!"); + }, updateLatestLog: assign(({ context }, params: { endDate: Date }) => { if (context.latestLog && isAfter(context.latestLog, params.endDate)) { return context; } - // TODO: Write back to settings - return { latestLog: params.endDate, }; @@ -68,7 +75,7 @@ export const pluginActor = setup({ }, }).createMachine({ id: "obsidian-limitless-plugin", - initial: "querying", + initial: "idle", context: ({ input }) => ({ apiKey: input.apiKey, latestLog: input.latestLog ? parse(input.latestLog) : undefined, @@ -79,8 +86,8 @@ export const pluginActor = setup({ }), states: { idle: { - after: { - [10 * 60 * 1000]: { + on: { + "lifelogs::sync": { target: "querying", }, }, @@ -140,6 +147,12 @@ export const pluginActor = setup({ endDate: event.output, }), }, + { + type: "persistLatestLog", + params: ({ event }) => ({ + endDate: event.output, + }), + }, ], }, }, diff --git a/deno.lock b/deno.lock index 61cbedb..11fee75 100644 --- a/deno.lock +++ b/deno.lock @@ -1,10 +1,36 @@ { "version": "4", "specifiers": { + "jsr:@luca/esbuild-deno-loader@~0.11.1": "0.11.1", + "jsr:@std/bytes@^1.0.2": "1.0.5", + "jsr:@std/encoding@^1.0.5": "1.0.7", + "jsr:@std/path@^1.0.6": "1.0.8", "npm:@formkit/tempo@~0.1.2": "0.1.2", + "npm:builtin-modules@5": "5.0.0", + "npm:esbuild@~0.25.1": "0.25.1", + "npm:ky@^1.7.5": "1.7.5", "npm:obsidian@^1.8.7": "1.8.7_@codemirror+state@6.5.2_@codemirror+view@6.36.4", "npm:xstate@^5.19.2": "5.19.2" }, + "jsr": { + "@luca/esbuild-deno-loader@0.11.1": { + "integrity": "dc020d16d75b591f679f6b9288b10f38bdb4f24345edb2f5732affa1d9885267", + "dependencies": [ + "jsr:@std/bytes", + "jsr:@std/encoding", + "jsr:@std/path" + ] + }, + "@std/bytes@1.0.5": { + "integrity": "4465dd739d7963d964c809202ebea6d5c6b8e3829ef25c6a224290fbb8a1021e" + }, + "@std/encoding@1.0.7": { + "integrity": "f631247c1698fef289f2de9e2a33d571e46133b38d042905e3eac3715030a82d" + }, + "@std/path@1.0.8": { + "integrity": "548fa456bb6a04d3c1a1e7477986b6cffbce95102d0bb447c67c4ee70e0364be" + } + }, "npm": { "@codemirror/state@6.5.2": { "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", @@ -20,6 +46,81 @@ "w3c-keyname" ] }, + "@esbuild/aix-ppc64@0.25.1": { + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==" + }, + "@esbuild/android-arm64@0.25.1": { + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==" + }, + "@esbuild/android-arm@0.25.1": { + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==" + }, + "@esbuild/android-x64@0.25.1": { + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==" + }, + "@esbuild/darwin-arm64@0.25.1": { + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==" + }, + "@esbuild/darwin-x64@0.25.1": { + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==" + }, + "@esbuild/freebsd-arm64@0.25.1": { + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==" + }, + "@esbuild/freebsd-x64@0.25.1": { + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==" + }, + "@esbuild/linux-arm64@0.25.1": { + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==" + }, + "@esbuild/linux-arm@0.25.1": { + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==" + }, + "@esbuild/linux-ia32@0.25.1": { + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==" + }, + "@esbuild/linux-loong64@0.25.1": { + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==" + }, + "@esbuild/linux-mips64el@0.25.1": { + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==" + }, + "@esbuild/linux-ppc64@0.25.1": { + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==" + }, + "@esbuild/linux-riscv64@0.25.1": { + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==" + }, + "@esbuild/linux-s390x@0.25.1": { + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==" + }, + "@esbuild/linux-x64@0.25.1": { + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==" + }, + "@esbuild/netbsd-arm64@0.25.1": { + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==" + }, + "@esbuild/netbsd-x64@0.25.1": { + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==" + }, + "@esbuild/openbsd-arm64@0.25.1": { + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==" + }, + "@esbuild/openbsd-x64@0.25.1": { + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==" + }, + "@esbuild/sunos-x64@0.25.1": { + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==" + }, + "@esbuild/win32-arm64@0.25.1": { + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==" + }, + "@esbuild/win32-ia32@0.25.1": { + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==" + }, + "@esbuild/win32-x64@0.25.1": { + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==" + }, "@formkit/tempo@0.1.2": { "integrity": "sha512-jNPPbjL8oj7hK3eHX++CwbR6X4GKQt+x00/q4yeXkwynXHGKL27dylYhpEgwrmediPP4y7s0XtN1if/M/JYujg==" }, @@ -41,6 +142,42 @@ "@types/estree" ] }, + "builtin-modules@5.0.0": { + "integrity": "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==" + }, + "esbuild@0.25.1": { + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "dependencies": [ + "@esbuild/aix-ppc64", + "@esbuild/android-arm", + "@esbuild/android-arm64", + "@esbuild/android-x64", + "@esbuild/darwin-arm64", + "@esbuild/darwin-x64", + "@esbuild/freebsd-arm64", + "@esbuild/freebsd-x64", + "@esbuild/linux-arm", + "@esbuild/linux-arm64", + "@esbuild/linux-ia32", + "@esbuild/linux-loong64", + "@esbuild/linux-mips64el", + "@esbuild/linux-ppc64", + "@esbuild/linux-riscv64", + "@esbuild/linux-s390x", + "@esbuild/linux-x64", + "@esbuild/netbsd-arm64", + "@esbuild/netbsd-x64", + "@esbuild/openbsd-arm64", + "@esbuild/openbsd-x64", + "@esbuild/sunos-x64", + "@esbuild/win32-arm64", + "@esbuild/win32-ia32", + "@esbuild/win32-x64" + ] + }, + "ky@1.7.5": { + "integrity": "sha512-HzhziW6sc5m0pwi5M196+7cEBtbt0lCYi67wNsiwMUmz833wloE0gbzJPWKs1gliFKQb34huItDQX97LyOdPdA==" + }, "moment@2.29.4": { "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, diff --git a/main.ts b/main.ts index 0781f1b..8af344f 100644 --- a/main.ts +++ b/main.ts @@ -15,7 +15,16 @@ export default class LimitlessPlugin extends Plugin { this.addSettingTab(new LimitlessSettingTab(this.app, this)); - const actor = createActor(pluginActor, { + const readyActor = pluginActor.provide({ + actions: { + persistLatestLog: async (_, params) => { + this.settings.latestLog = params.endDate.toISOString(); + await this.saveSettings(); + }, + }, + }); + + const actor = createActor(readyActor, { input: { ...this.settings, vault: this.app.vault, @@ -27,6 +36,18 @@ export default class LimitlessPlugin extends Plugin { }); actor.start(); + + this.addCommand({ + id: "limitless-lifelogs-sync", + name: "Sync Lifelogs Now", + callback: () => { + actor.send({ type: "lifelogs::sync" }); + }, + }); + + if (this.settings.syncAtStart) { + actor.send({ type: "lifelogs::sync" }); + } } override onunload() { diff --git a/settings.ts b/settings.ts index fc0bcaa..570c91e 100644 --- a/settings.ts +++ b/settings.ts @@ -2,12 +2,14 @@ import { App, PluginSettingTab, Setting } from "obsidian"; import LimitlessPlugin from "./main.ts"; export interface LimitlessPluginSettings { + syncAtStart: boolean; apiKey: string; lifelogsDir: string; latestLog?: string; } export const DEFAULT_SETTINGS: LimitlessPluginSettings = { + syncAtStart: false, apiKey: "", lifelogsDir: "", latestLog: undefined, @@ -26,9 +28,15 @@ export class LimitlessSettingTab extends PluginSettingTab { containerEl.empty(); + containerEl.createEl("h1", { text: "Unofficial Limitless Plugin" }); + containerEl.createEl("p", { + text: + "Please note that you must own a Limitless Pendant to use this plugin, for now.", + }); + new Setting(containerEl) .setName("API Key") - .setDesc("It's a secret") + .setDesc("Retrieve this from your Developer settings on desktop or web") .addText((text) => { text.inputEl.type = "password"; @@ -41,6 +49,20 @@ export class LimitlessSettingTab extends PluginSettingTab { }); }); + containerEl.createEl("h2", { text: "Lifelogs" }); + + new Setting(containerEl) + .setName("Sync at Start") + .setDesc("Whether or not to sync lifelogs when Obsidian opens") + .addToggle((toggle) => { + return toggle + .setValue(this.plugin.settings.syncAtStart) + .onChange(async (value) => { + this.plugin.settings.syncAtStart = value; + await this.plugin.saveSettings(); + }); + }); + new Setting(containerEl) .setName("Lifelogs Directory") .setDesc("The directory where you want Lifelogs placed")