@xopcai/xopc 0.0.101 → 0.0.102
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
- package/dist/extensions/telegram/src/inbound-processor.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/update-offset-store.js +1 -1
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/assets/{agents-u8cmUfGQ.js → agents-DQ0mQxIA.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-DF8m9cUE.js → apps-page-Uv4kOmDE.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-BM3doRvi.js → channels-settings-BEtP53V6.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-ah4zWEIP.js → channels-status-swr-CxTtS1hI.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-DgMuL_2b.js → cron-api-CznlPIZT.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-COfUPKfq.js → cron-page-Dx6dE3eD.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-Dzy3Q0ZH.js → dist-DH4IuRV0.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-kyxxefKh.js → extension-debug-page-BNkhvRQW.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BVbCBHoI.js → extension-page-CcIGQah2.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-t1lb2A7v.js → extension-settings-page-DuDCSb3J.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-6Vo1Yga4.js → field-primitives-BUwUiDf5.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-BF3psu4O.js → heartbeat-config-api-BjFW1cl-.js} +1 -1
- package/dist/gateway/static/root/assets/{index-WAyKAilR.js → index-DKgHC1Ta.js} +4 -4
- package/dist/gateway/static/root/assets/{logs-page-BTVPXcHV.js → logs-page-CiG0m81R.js} +1 -1
- package/dist/gateway/static/root/assets/{note-detail-page-DqSAg_5Z.js → note-detail-page-DG3DVFTf.js} +2 -2
- package/dist/gateway/static/root/assets/{note-time-FSOjchic.js → note-time-DjlllCF3.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-DkRX7BE2.js → notes-page-D40ZpS0Y.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-Khdw35Zk.js → sessions-page-BvtdbmW8.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-advanced-gate-DspC8oEm.js → settings-advanced-gate-BQamRjkV.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-DuxvUuur.js → settings-form-section-C3_sEFfD.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-DN8JBZ8F.js → settings-page-D972_jaS.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-UNAcbiMb.js → share-preview-page-CKCTMo0_.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-ByYT0fXZ.js → skills-page-QwFCB4yV.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-DK_1H47k.js → utils-DCm11_KW.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-BYN2EIMs.js → voice-api-key-field-CywiB7Dw.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-page.utils-Bi19YNTr.js → workflow-page.utils-g57BRfEd.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-DP57FEKW.js → workflows-page-Be7l_SWw.js} +1 -1
- package/dist/gateway/static/root/index.html +1 -1
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +7 -7
- package/dist/src/agent/agent-scope.js +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/context/workspace-state.js +1 -1
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-service.js +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/memory-flush.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service.js +4 -4
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +2 -2
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/auth/credentials.js +3 -3
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +3 -3
- package/dist/src/browser/providers/cloakbrowser.js +4 -4
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/chat-commands/agent-edit.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +3 -3
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/commands/agents.config.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +5 -5
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.js +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/loader.js +1 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/agents-admin.js +3 -3
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/oauth-async.js +1 -1
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/agents.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/notes.js +9 -22
- package/dist/src/gateway/hono/routes/notes.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +2 -2
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/agent-runner.js +2 -2
- package/dist/src/gateway/service/marketplace-service.js +2 -2
- package/dist/src/gateway/service.js +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/brew.js +1 -1
- package/dist/src/infra/package-json.js +1 -1
- package/dist/src/infra/package-update-steps.js +1 -1
- package/dist/src/infra/path-env.js +2 -2
- package/dist/src/infra/restart.js +2 -2
- package/dist/src/infra/stable-node-path.js +1 -1
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.js +1 -1
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/media/store.js +1 -1
- package/dist/src/notes/note-attachment-sync.d.ts +2 -3
- package/dist/src/notes/note-attachment-sync.js +2 -27
- package/dist/src/notes/note-attachment-sync.js.map +1 -1
- package/dist/src/notes/note-index-meta.d.ts +6 -2
- package/dist/src/notes/note-index-meta.js +11 -16
- package/dist/src/notes/note-index-meta.js.map +1 -1
- package/dist/src/notes/note-markdown.d.ts +61 -0
- package/dist/src/notes/note-markdown.js +177 -0
- package/dist/src/notes/note-markdown.js.map +1 -0
- package/dist/src/notes/service.d.ts +9 -7
- package/dist/src/notes/service.js +163 -312
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/notes/store.js +4 -5
- package/dist/src/notes/store.js.map +1 -1
- package/dist/src/notes/types.d.ts +29 -58
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/init-session-turn.js +2 -2
- package/dist/src/session/resolve-session.js +3 -3
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.js +2 -2
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/storage/sqlite/connection.js +2 -2
- package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
- package/dist/src/storage/sqlite/migrations/003_add_note_markdown_meta.sql +4 -0
- package/dist/src/storage/sqlite/migrations/discover.js +1 -1
- package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
- package/dist/src/storage/sqlite/migrations/runner.js +5 -5
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
- package/dist/src/storage/sqlite/notes-repository.js +18 -6
- package/dist/src/storage/sqlite/notes-repository.js.map +1 -1
- package/dist/src/storage/sqlite/schema.js +4 -4
- package/dist/src/storage/sqlite/schema.sql +5 -1
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui.js +3 -3
- package/dist/src/tunnel/frpc-binary.js +3 -3
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
1
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
3
|
//#region src/storage/sqlite/migrations/discover.ts
|
|
4
4
|
/** Matches `002_add_notes_index.sql` → target version 2. */
|
|
5
5
|
const MIGRATION_FILENAME = /^(\d{3})_[\w-]+\.sql$/;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { DatabaseSync } from 'node:sqlite';
|
|
2
2
|
import type { ApplyMigrationsOptions } from './types.js';
|
|
3
3
|
/** Baseline schema version applied from schema.sql on first open. */
|
|
4
|
-
export declare const XOPC_DB_BASELINE_SCHEMA_VERSION =
|
|
4
|
+
export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 3;
|
|
5
5
|
/** Latest schema version this release supports (increment when adding migrations). */
|
|
6
|
-
export declare const XOPC_DB_SCHEMA_VERSION =
|
|
6
|
+
export declare const XOPC_DB_SCHEMA_VERSION = 3;
|
|
7
7
|
export declare function resolveMigrationsDir(override?: string): string;
|
|
8
8
|
/**
|
|
9
9
|
* Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
|
|
@@ -3,16 +3,16 @@ import { init_logger } from "../../../utils/logger.js";
|
|
|
3
3
|
import { readSchemaVersion, setSchemaVersion } from "../schema-version.js";
|
|
4
4
|
import { discoverSqlMigrations } from "./discover.js";
|
|
5
5
|
import { DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError } from "./errors.js";
|
|
6
|
-
import { dirname, join } from "node:path";
|
|
7
6
|
import { existsSync } from "node:fs";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
//#region src/storage/sqlite/migrations/runner.ts
|
|
10
10
|
init_logger();
|
|
11
11
|
const log = createLogger("Sqlite:Migrations");
|
|
12
12
|
/** Baseline schema version applied from schema.sql on first open. */
|
|
13
|
-
const XOPC_DB_BASELINE_SCHEMA_VERSION =
|
|
13
|
+
const XOPC_DB_BASELINE_SCHEMA_VERSION = 3;
|
|
14
14
|
/** Latest schema version this release supports (increment when adding migrations). */
|
|
15
|
-
const XOPC_DB_SCHEMA_VERSION =
|
|
15
|
+
const XOPC_DB_SCHEMA_VERSION = 3;
|
|
16
16
|
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
17
17
|
function resolveMigrationsDir(override) {
|
|
18
18
|
if (override) return override;
|
|
@@ -46,7 +46,7 @@ function applySingleMigration(db, migration) {
|
|
|
46
46
|
* Each step runs in its own transaction and updates schema_meta on success.
|
|
47
47
|
*/
|
|
48
48
|
function applyPendingMigrations(db, options = {}) {
|
|
49
|
-
const targetVersion = options.targetVersion ??
|
|
49
|
+
const targetVersion = options.targetVersion ?? 3;
|
|
50
50
|
let currentVersion = readSchemaVersion(db);
|
|
51
51
|
if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
|
|
52
52
|
if (currentVersion >= targetVersion) return currentVersion;
|
|
@@ -62,7 +62,7 @@ function applyPendingMigrations(db, options = {}) {
|
|
|
62
62
|
}
|
|
63
63
|
/** Inspect schema version without mutating the database. */
|
|
64
64
|
function inspectSchemaMigrationStatus(db, options = {}) {
|
|
65
|
-
const appVersion = options.targetVersion ??
|
|
65
|
+
const appVersion = options.targetVersion ?? 3;
|
|
66
66
|
const dbVersion = readSchemaVersion(db);
|
|
67
67
|
if (dbVersion > appVersion) return {
|
|
68
68
|
dbVersion,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","names":[],"sources":["../../../../../src/storage/sqlite/migrations/runner.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { DatabaseSync } from 'node:sqlite';\n\nimport { createLogger } from '../../../utils/logger.js';\nimport { readSchemaVersion, setSchemaVersion } from '../schema-version.js';\nimport { discoverSqlMigrations } from './discover.js';\nimport {\n DatabaseSchemaMigrationGapError,\n DatabaseSchemaTooNewError,\n} from './errors.js';\nimport type { ApplyMigrationsOptions, SqlMigration } from './types.js';\n\nconst log = createLogger('Sqlite:Migrations');\n\n/** Baseline schema version applied from schema.sql on first open. */\nexport const XOPC_DB_BASELINE_SCHEMA_VERSION =
|
|
1
|
+
{"version":3,"file":"runner.js","names":[],"sources":["../../../../../src/storage/sqlite/migrations/runner.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { DatabaseSync } from 'node:sqlite';\n\nimport { createLogger } from '../../../utils/logger.js';\nimport { readSchemaVersion, setSchemaVersion } from '../schema-version.js';\nimport { discoverSqlMigrations } from './discover.js';\nimport {\n DatabaseSchemaMigrationGapError,\n DatabaseSchemaTooNewError,\n} from './errors.js';\nimport type { ApplyMigrationsOptions, SqlMigration } from './types.js';\n\nconst log = createLogger('Sqlite:Migrations');\n\n/** Baseline schema version applied from schema.sql on first open. */\nexport const XOPC_DB_BASELINE_SCHEMA_VERSION = 3;\n\n/** Latest schema version this release supports (increment when adding migrations). */\nexport const XOPC_DB_SCHEMA_VERSION = 3;\n\nconst MODULE_DIR = dirname(fileURLToPath(import.meta.url));\n\nexport function resolveMigrationsDir(override?: string): string {\n if (override) {\n return override;\n }\n // Packaged Electron gateway bundle: `out/server/index.js` + `out/server/migrations/`.\n const siblingDir = join(MODULE_DIR, 'migrations');\n if (existsSync(siblingDir)) {\n return siblingDir;\n }\n // Dev / dist: SQL files live next to `migrations/runner.js`.\n return MODULE_DIR;\n}\n\nfunction migrationByTarget(\n migrations: SqlMigration[],\n targetVersion: number,\n): SqlMigration | undefined {\n return migrations.find((migration) => migration.targetVersion === targetVersion);\n}\n\nfunction applySingleMigration(db: DatabaseSync, migration: SqlMigration): void {\n log.info({ targetVersion: migration.targetVersion, file: migration.filename }, 'Applying SQLite migration');\n db.exec('BEGIN IMMEDIATE');\n try {\n db.exec(migration.sql);\n setSchemaVersion(db, migration.targetVersion);\n db.exec('COMMIT');\n } catch (error) {\n try {\n db.exec('ROLLBACK');\n } catch {\n /* preserve original error */\n }\n const em = error instanceof Error ? error.message : String(error);\n throw new Error(\n `SQLite migration to v${migration.targetVersion} (${migration.filename}) failed: ${em}`,\n { cause: error },\n );\n }\n}\n\n/**\n * Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.\n * Each step runs in its own transaction and updates schema_meta on success.\n */\nexport function applyPendingMigrations(\n db: DatabaseSync,\n options: ApplyMigrationsOptions = {},\n): number {\n const targetVersion = options.targetVersion ?? XOPC_DB_SCHEMA_VERSION;\n let currentVersion = readSchemaVersion(db);\n\n if (currentVersion > targetVersion) {\n throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);\n }\n\n if (currentVersion >= targetVersion) {\n return currentVersion;\n }\n\n const migrations = discoverSqlMigrations(resolveMigrationsDir(options.migrationsDir));\n\n while (currentVersion < targetVersion) {\n const nextVersion = currentVersion + 1;\n const migration = migrationByTarget(migrations, nextVersion);\n if (!migration) {\n throw new DatabaseSchemaMigrationGapError(currentVersion, targetVersion, nextVersion);\n }\n applySingleMigration(db, migration);\n currentVersion = nextVersion;\n }\n\n return currentVersion;\n}\n\nexport type SchemaMigrationStatus = {\n dbVersion: number;\n appVersion: number;\n pendingVersions: number[];\n isTooNew: boolean;\n hasMigrationGap: boolean;\n missingVersion: number | null;\n};\n\n/** Inspect schema version without mutating the database. */\nexport function inspectSchemaMigrationStatus(\n db: DatabaseSync,\n options: Pick<ApplyMigrationsOptions, 'migrationsDir' | 'targetVersion'> = {},\n): SchemaMigrationStatus {\n const appVersion = options.targetVersion ?? XOPC_DB_SCHEMA_VERSION;\n const dbVersion = readSchemaVersion(db);\n const isTooNew = dbVersion > appVersion;\n\n if (isTooNew) {\n return {\n dbVersion,\n appVersion,\n pendingVersions: [],\n isTooNew: true,\n hasMigrationGap: false,\n missingVersion: null,\n };\n }\n\n const migrations = discoverSqlMigrations(resolveMigrationsDir(options.migrationsDir));\n const pendingVersions: number[] = [];\n let hasMigrationGap = false;\n let missingVersion: number | null = null;\n\n for (let version = dbVersion + 1; version <= appVersion; version++) {\n if (migrationByTarget(migrations, version)) {\n pendingVersions.push(version);\n } else {\n hasMigrationGap = true;\n missingVersion = version;\n break;\n }\n }\n\n return {\n dbVersion,\n appVersion,\n pendingVersions,\n isTooNew: false,\n hasMigrationGap,\n missingVersion,\n };\n}\n"],"mappings":";;;;;;;;;aAMwD;AASxD,MAAM,MAAM,aAAa,oBAAoB;;AAG7C,MAAa,kCAAkC;;AAG/C,MAAa,yBAAyB;AAEtC,MAAM,aAAa,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAE1D,SAAgB,qBAAqB,UAA2B;AAC9D,KAAI,SACF,QAAO;CAGT,MAAM,aAAa,KAAK,YAAY,aAAa;AACjD,KAAI,WAAW,WAAW,CACxB,QAAO;AAGT,QAAO;;AAGT,SAAS,kBACP,YACA,eAC0B;AAC1B,QAAO,WAAW,MAAM,cAAc,UAAU,kBAAkB,cAAc;;AAGlF,SAAS,qBAAqB,IAAkB,WAA+B;AAC7E,KAAI,KAAK;EAAE,eAAe,UAAU;EAAe,MAAM,UAAU;EAAU,EAAE,4BAA4B;AAC3G,IAAG,KAAK,kBAAkB;AAC1B,KAAI;AACF,KAAG,KAAK,UAAU,IAAI;AACtB,mBAAiB,IAAI,UAAU,cAAc;AAC7C,KAAG,KAAK,SAAS;UACV,OAAO;AACd,MAAI;AACF,MAAG,KAAK,WAAW;UACb;EAGR,MAAM,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACjE,QAAM,IAAI,MACR,wBAAwB,UAAU,cAAc,IAAI,UAAU,SAAS,YAAY,MACnF,EAAE,OAAO,OAAO,CACjB;;;;;;;AAQL,SAAgB,uBACd,IACA,UAAkC,EAAE,EAC5B;CACR,MAAM,gBAAgB,QAAQ,iBAAA;CAC9B,IAAI,iBAAiB,kBAAkB,GAAG;AAE1C,KAAI,iBAAiB,cACnB,OAAM,IAAI,0BAA0B,gBAAgB,cAAc;AAGpE,KAAI,kBAAkB,cACpB,QAAO;CAGT,MAAM,aAAa,sBAAsB,qBAAqB,QAAQ,cAAc,CAAC;AAErF,QAAO,iBAAiB,eAAe;EACrC,MAAM,cAAc,iBAAiB;EACrC,MAAM,YAAY,kBAAkB,YAAY,YAAY;AAC5D,MAAI,CAAC,UACH,OAAM,IAAI,gCAAgC,gBAAgB,eAAe,YAAY;AAEvF,uBAAqB,IAAI,UAAU;AACnC,mBAAiB;;AAGnB,QAAO;;;AAaT,SAAgB,6BACd,IACA,UAA2E,EAAE,EACtD;CACvB,MAAM,aAAa,QAAQ,iBAAA;CAC3B,MAAM,YAAY,kBAAkB,GAAG;AAGvC,KAFiB,YAAY,WAG3B,QAAO;EACL;EACA;EACA,iBAAiB,EAAE;EACnB,UAAU;EACV,iBAAiB;EACjB,gBAAgB;EACjB;CAGH,MAAM,aAAa,sBAAsB,qBAAqB,QAAQ,cAAc,CAAC;CACrF,MAAM,kBAA4B,EAAE;CACpC,IAAI,kBAAkB;CACtB,IAAI,iBAAgC;AAEpC,MAAK,IAAI,UAAU,YAAY,GAAG,WAAW,YAAY,UACvD,KAAI,kBAAkB,YAAY,QAAQ,CACxC,iBAAgB,KAAK,QAAQ;MACxB;AACL,oBAAkB;AAClB,mBAAiB;AACjB;;AAIJ,QAAO;EACL;EACA;EACA;EACA,UAAU;EACV;EACA;EACD"}
|
|
@@ -16,10 +16,10 @@ import type { ApplyMigrationsOptions, SqlMigration } from './types.js';
|
|
|
16
16
|
const log = createLogger('Sqlite:Migrations');
|
|
17
17
|
|
|
18
18
|
/** Baseline schema version applied from schema.sql on first open. */
|
|
19
|
-
export const XOPC_DB_BASELINE_SCHEMA_VERSION =
|
|
19
|
+
export const XOPC_DB_BASELINE_SCHEMA_VERSION = 3;
|
|
20
20
|
|
|
21
21
|
/** Latest schema version this release supports (increment when adding migrations). */
|
|
22
|
-
export const XOPC_DB_SCHEMA_VERSION =
|
|
22
|
+
export const XOPC_DB_SCHEMA_VERSION = 3;
|
|
23
23
|
|
|
24
24
|
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
25
25
|
|
|
@@ -37,7 +37,11 @@ function rowToIndexEntry(row) {
|
|
|
37
37
|
groupId: row.group_id ?? void 0,
|
|
38
38
|
lastOpenedAt: row.last_opened_at ?? void 0,
|
|
39
39
|
taskDone: row.task_done != null ? Boolean(row.task_done) : void 0,
|
|
40
|
-
taskDueAt: row.task_due_at ?? void 0
|
|
40
|
+
taskDueAt: row.task_due_at ?? void 0,
|
|
41
|
+
headingCount: row.heading_count ?? void 0,
|
|
42
|
+
taskCount: row.task_count ?? void 0,
|
|
43
|
+
uncheckedTaskCount: row.unchecked_task_count ?? void 0,
|
|
44
|
+
linkCount: row.link_count ?? void 0
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
47
|
function noteSearchContent(note) {
|
|
@@ -72,7 +76,11 @@ function noteToRow(note) {
|
|
|
72
76
|
group_id: note.groupId ?? null,
|
|
73
77
|
last_opened_at: note.lastOpenedAt ?? null,
|
|
74
78
|
task_done: note.taskMeta?.done != null ? note.taskMeta.done ? 1 : 0 : null,
|
|
75
|
-
task_due_at: note.taskMeta?.dueAt ?? null
|
|
79
|
+
task_due_at: note.taskMeta?.dueAt ?? null,
|
|
80
|
+
heading_count: meta.headingCount ?? null,
|
|
81
|
+
task_count: meta.taskCount ?? null,
|
|
82
|
+
unchecked_task_count: meta.uncheckedTaskCount ?? null,
|
|
83
|
+
link_count: meta.linkCount ?? null
|
|
76
84
|
};
|
|
77
85
|
}
|
|
78
86
|
function upsertNoteFts(db, note) {
|
|
@@ -88,8 +96,8 @@ function upsertNoteRecord(note) {
|
|
|
88
96
|
note_id, title, kind, status, payload_json, created_at, updated_at,
|
|
89
97
|
pinned, tags_json, snippet, cover_attachment_id, voice_attachment_id,
|
|
90
98
|
voice_duration_sec, attachment_names_json, group_id, last_opened_at,
|
|
91
|
-
task_done, task_due_at
|
|
92
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
99
|
+
task_done, task_due_at, heading_count, task_count, unchecked_task_count, link_count
|
|
100
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
93
101
|
ON CONFLICT(note_id) DO UPDATE SET
|
|
94
102
|
title = excluded.title,
|
|
95
103
|
kind = excluded.kind,
|
|
@@ -106,7 +114,11 @@ function upsertNoteRecord(note) {
|
|
|
106
114
|
group_id = excluded.group_id,
|
|
107
115
|
last_opened_at = excluded.last_opened_at,
|
|
108
116
|
task_done = excluded.task_done,
|
|
109
|
-
task_due_at = excluded.task_due_at
|
|
117
|
+
task_due_at = excluded.task_due_at,
|
|
118
|
+
heading_count = excluded.heading_count,
|
|
119
|
+
task_count = excluded.task_count,
|
|
120
|
+
unchecked_task_count = excluded.unchecked_task_count,
|
|
121
|
+
link_count = excluded.link_count`).run(row.note_id, row.title, row.kind, row.status, row.payload_json, row.created_at, row.updated_at, row.pinned, row.tags_json, row.snippet, row.cover_attachment_id, row.voice_attachment_id, row.voice_duration_sec, row.attachment_names_json, row.group_id, row.last_opened_at, row.task_done, row.task_due_at, row.heading_count, row.task_count, row.unchecked_task_count, row.link_count);
|
|
110
122
|
upsertNoteFts(db, note);
|
|
111
123
|
});
|
|
112
124
|
}
|
|
@@ -156,7 +168,7 @@ function listNoteRecords(query = {}) {
|
|
|
156
168
|
let entries = db.prepare(`SELECT note_id, title, kind, status, payload_json, created_at, updated_at,
|
|
157
169
|
pinned, tags_json, snippet, cover_attachment_id, voice_attachment_id,
|
|
158
170
|
voice_duration_sec, attachment_names_json, group_id, last_opened_at,
|
|
159
|
-
task_done, task_due_at
|
|
171
|
+
task_done, task_due_at, heading_count, task_count, unchecked_task_count, link_count
|
|
160
172
|
FROM notes ${where}`).all(...params).map(rowToIndexEntry);
|
|
161
173
|
if (query.tag) entries = entries.filter((entry) => entry.tags?.includes(query.tag));
|
|
162
174
|
if (query.search) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notes-repository.js","names":[],"sources":["../../../../src/storage/sqlite/notes-repository.ts"],"sourcesContent":["import type { Note, NoteIndexEntry, NotesListQuery } from '../../notes/types.js';\nimport { buildNoteIndexMeta, extractAttachmentFileNames, notePlainText } from '../../notes/note-index-meta.js';\nimport { escapeFts5Query } from './fts.js';\nimport { getSqliteDatabase, runSqliteWriteTransaction } from './transaction.js';\n\ntype NoteRow = {\n note_id: string;\n title: string | null;\n kind: string;\n status: string;\n payload_json: string;\n created_at: number;\n updated_at: number;\n pinned: number;\n tags_json: string;\n snippet: string | null;\n cover_attachment_id: string | null;\n voice_attachment_id: string | null;\n voice_duration_sec: number | null;\n attachment_names_json: string | null;\n group_id: string | null;\n last_opened_at: number | null;\n task_done: number | null;\n task_due_at: number | null;\n};\n\nfunction parseTags(json: string): string[] {\n try {\n const parsed = JSON.parse(json) as unknown;\n return Array.isArray(parsed) ? parsed.filter((t): t is string => typeof t === 'string') : [];\n } catch {\n return [];\n }\n}\n\nfunction parseAttachmentNames(json: string | null): string[] | undefined {\n if (!json) return undefined;\n try {\n const parsed = JSON.parse(json) as unknown;\n return Array.isArray(parsed) ? parsed.filter((n): n is string => typeof n === 'string') : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction rowToIndexEntry(row: NoteRow): NoteIndexEntry {\n return {\n id: row.note_id,\n title: row.title ?? undefined,\n kind: row.kind as NoteIndexEntry['kind'],\n status: row.status as NoteIndexEntry['status'],\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n pinned: row.pinned ? true : undefined,\n tags: parseTags(row.tags_json),\n snippet: row.snippet ?? undefined,\n coverAttachmentId: row.cover_attachment_id ?? undefined,\n voiceAttachmentId: row.voice_attachment_id ?? undefined,\n voiceDurationSec: row.voice_duration_sec ?? undefined,\n attachmentNames: parseAttachmentNames(row.attachment_names_json),\n groupId: row.group_id ?? undefined,\n lastOpenedAt: row.last_opened_at ?? undefined,\n taskDone: row.task_done != null ? Boolean(row.task_done) : undefined,\n taskDueAt: row.task_due_at ?? undefined,\n };\n}\n\nfunction noteSearchContent(note: Note): string {\n const plain = notePlainText(note);\n const attachmentText = note.attachments?.map((a) => a.transcript).filter(Boolean).join(' ') ?? '';\n const attachmentNames = extractAttachmentFileNames(note)?.join(' ') ?? '';\n return [note.title, plain, attachmentText, attachmentNames, ...(note.tags ?? [])].filter(Boolean).join('\\n');\n}\n\nfunction noteToRow(note: Note): Omit<NoteRow, 'payload_json'> & { payload_json: string } {\n const meta = buildNoteIndexMeta(note);\n return {\n note_id: note.id,\n title: note.title ?? null,\n kind: note.kind,\n status: note.status,\n payload_json: JSON.stringify(note),\n created_at: note.createdAt,\n updated_at: note.updatedAt,\n pinned: note.pinned ? 1 : 0,\n tags_json: JSON.stringify(note.tags ?? []),\n snippet: meta.snippet ?? null,\n cover_attachment_id: meta.coverAttachmentId ?? null,\n voice_attachment_id: meta.voiceAttachmentId ?? null,\n voice_duration_sec: meta.voiceDurationSec ?? null,\n attachment_names_json: meta.attachmentNames ? JSON.stringify(meta.attachmentNames) : null,\n group_id: note.groupId ?? null,\n last_opened_at: note.lastOpenedAt ?? null,\n task_done: note.taskMeta?.done != null ? (note.taskMeta.done ? 1 : 0) : null,\n task_due_at: note.taskMeta?.dueAt ?? null,\n };\n}\n\nfunction upsertNoteFts(db: ReturnType<typeof getSqliteDatabase>, note: Note): void {\n db.prepare(`DELETE FROM notes_fts WHERE note_id = ?`).run(note.id);\n const content = noteSearchContent(note);\n if (!content.trim()) {\n return;\n }\n db.prepare(`INSERT INTO notes_fts (content, note_id) VALUES (?, ?)`).run(content, note.id);\n}\n\nexport function upsertNoteRecord(note: Note): void {\n const row = noteToRow(note);\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO notes (\n note_id, title, kind, status, payload_json, created_at, updated_at,\n pinned, tags_json, snippet, cover_attachment_id, voice_attachment_id,\n voice_duration_sec, attachment_names_json, group_id, last_opened_at,\n task_done, task_due_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(note_id) DO UPDATE SET\n title = excluded.title,\n kind = excluded.kind,\n status = excluded.status,\n payload_json = excluded.payload_json,\n updated_at = excluded.updated_at,\n pinned = excluded.pinned,\n tags_json = excluded.tags_json,\n snippet = excluded.snippet,\n cover_attachment_id = excluded.cover_attachment_id,\n voice_attachment_id = excluded.voice_attachment_id,\n voice_duration_sec = excluded.voice_duration_sec,\n attachment_names_json = excluded.attachment_names_json,\n group_id = excluded.group_id,\n last_opened_at = excluded.last_opened_at,\n task_done = excluded.task_done,\n task_due_at = excluded.task_due_at`,\n ).run(\n row.note_id,\n row.title,\n row.kind,\n row.status,\n row.payload_json,\n row.created_at,\n row.updated_at,\n row.pinned,\n row.tags_json,\n row.snippet,\n row.cover_attachment_id,\n row.voice_attachment_id,\n row.voice_duration_sec,\n row.attachment_names_json,\n row.group_id,\n row.last_opened_at,\n row.task_done,\n row.task_due_at,\n );\n upsertNoteFts(db, note);\n });\n}\n\nexport function getNoteRecord(noteId: string): Note | null {\n const db = getSqliteDatabase();\n const row = db.prepare(`SELECT payload_json FROM notes WHERE note_id = ?`).get(noteId) as\n | { payload_json: string }\n | undefined;\n if (!row?.payload_json) {\n return null;\n }\n try {\n return JSON.parse(row.payload_json) as Note;\n } catch {\n return null;\n }\n}\n\nexport function deleteNoteRecord(noteId: string): boolean {\n return runSqliteWriteTransaction((db) => {\n const existing = db.prepare(`SELECT note_id FROM notes WHERE note_id = ?`).get(noteId);\n if (!existing) {\n return false;\n }\n db.prepare(`DELETE FROM notes_fts WHERE note_id = ?`).run(noteId);\n db.prepare(`DELETE FROM notes WHERE note_id = ?`).run(noteId);\n return true;\n });\n}\n\nexport function listNoteRecords(\n query: NotesListQuery = {},\n): { items: NoteIndexEntry[]; total: number; limit: number; offset: number; hasMore: boolean } {\n const db = getSqliteDatabase();\n const conditions: string[] = [];\n const params: Array<string | number> = [];\n\n if (query.status) {\n conditions.push(`status = ?`);\n params.push(query.status);\n } else {\n conditions.push(`status != ?`);\n params.push('trashed');\n }\n if (query.kind) {\n conditions.push(`kind = ?`);\n params.push(query.kind);\n }\n if (query.pinned !== undefined) {\n conditions.push(`pinned = ?`);\n params.push(query.pinned ? 1 : 0);\n }\n if (query.groupId !== undefined) {\n if (query.groupId === 'ungrouped') {\n conditions.push(`(group_id IS NULL OR group_id = '')`);\n } else {\n conditions.push(`group_id = ?`);\n params.push(query.groupId);\n }\n }\n if (query.pendingTasksOnly) {\n conditions.push(`kind = 'task' AND (task_done IS NULL OR task_done = 0)`);\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n const rows = db\n .prepare(\n `SELECT note_id, title, kind, status, payload_json, created_at, updated_at,\n pinned, tags_json, snippet, cover_attachment_id, voice_attachment_id,\n voice_duration_sec, attachment_names_json, group_id, last_opened_at,\n task_done, task_due_at\n FROM notes ${where}`,\n )\n .all(...params) as NoteRow[];\n\n let entries = rows.map(rowToIndexEntry);\n\n if (query.tag) {\n entries = entries.filter((entry) => entry.tags?.includes(query.tag!));\n }\n\n if (query.search) {\n const ftsQuery = escapeFts5Query(query.search);\n const ftsIds = new Set<string>();\n if (ftsQuery) {\n const ftsRows = db\n .prepare(\n `SELECT note_id FROM notes_fts WHERE notes_fts MATCH ? ORDER BY rank`,\n )\n .all(ftsQuery) as Array<{ note_id: string }>;\n for (const row of ftsRows) {\n ftsIds.add(row.note_id);\n }\n }\n entries = entries.filter((entry) => ftsIds.has(entry.id));\n }\n\n const sortField = query.sortBy || 'createdAt';\n const sortDir = query.sortOrder === 'asc' ? 1 : -1;\n entries = [...entries].sort((a, b) => {\n const aVal = (a[sortField] as number | undefined) ?? 0;\n const bVal = (b[sortField] as number | undefined) ?? 0;\n return (aVal - bVal) * sortDir;\n });\n\n const total = entries.length;\n const offset = query.offset || 0;\n const limit = Math.min(query.limit || 50, 200);\n const items = entries.slice(offset, offset + limit);\n const hasMore = offset + items.length < total;\n\n return { items, total, limit, offset, hasMore };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"notes-repository.js","names":[],"sources":["../../../../src/storage/sqlite/notes-repository.ts"],"sourcesContent":["import type { Note, NoteIndexEntry, NotesListQuery } from '../../notes/types.js';\nimport { buildNoteIndexMeta, extractAttachmentFileNames, notePlainText } from '../../notes/note-index-meta.js';\nimport { escapeFts5Query } from './fts.js';\nimport { getSqliteDatabase, runSqliteWriteTransaction } from './transaction.js';\n\ntype NoteRow = {\n note_id: string;\n title: string | null;\n kind: string;\n status: string;\n payload_json: string;\n created_at: number;\n updated_at: number;\n pinned: number;\n tags_json: string;\n snippet: string | null;\n cover_attachment_id: string | null;\n voice_attachment_id: string | null;\n voice_duration_sec: number | null;\n attachment_names_json: string | null;\n group_id: string | null;\n last_opened_at: number | null;\n task_done: number | null;\n task_due_at: number | null;\n heading_count: number | null;\n task_count: number | null;\n unchecked_task_count: number | null;\n link_count: number | null;\n};\n\nfunction parseTags(json: string): string[] {\n try {\n const parsed = JSON.parse(json) as unknown;\n return Array.isArray(parsed) ? parsed.filter((t): t is string => typeof t === 'string') : [];\n } catch {\n return [];\n }\n}\n\nfunction parseAttachmentNames(json: string | null): string[] | undefined {\n if (!json) return undefined;\n try {\n const parsed = JSON.parse(json) as unknown;\n return Array.isArray(parsed) ? parsed.filter((n): n is string => typeof n === 'string') : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction rowToIndexEntry(row: NoteRow): NoteIndexEntry {\n return {\n id: row.note_id,\n title: row.title ?? undefined,\n kind: row.kind as NoteIndexEntry['kind'],\n status: row.status as NoteIndexEntry['status'],\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n pinned: row.pinned ? true : undefined,\n tags: parseTags(row.tags_json),\n snippet: row.snippet ?? undefined,\n coverAttachmentId: row.cover_attachment_id ?? undefined,\n voiceAttachmentId: row.voice_attachment_id ?? undefined,\n voiceDurationSec: row.voice_duration_sec ?? undefined,\n attachmentNames: parseAttachmentNames(row.attachment_names_json),\n groupId: row.group_id ?? undefined,\n lastOpenedAt: row.last_opened_at ?? undefined,\n taskDone: row.task_done != null ? Boolean(row.task_done) : undefined,\n taskDueAt: row.task_due_at ?? undefined,\n headingCount: row.heading_count ?? undefined,\n taskCount: row.task_count ?? undefined,\n uncheckedTaskCount: row.unchecked_task_count ?? undefined,\n linkCount: row.link_count ?? undefined,\n };\n}\n\nfunction noteSearchContent(note: Note): string {\n const plain = notePlainText(note);\n const attachmentText = note.attachments?.map((a) => a.transcript).filter(Boolean).join(' ') ?? '';\n const attachmentNames = extractAttachmentFileNames(note)?.join(' ') ?? '';\n return [note.title, plain, attachmentText, attachmentNames, ...(note.tags ?? [])].filter(Boolean).join('\\n');\n}\n\nfunction noteToRow(note: Note): Omit<NoteRow, 'payload_json'> & { payload_json: string } {\n const meta = buildNoteIndexMeta(note);\n return {\n note_id: note.id,\n title: note.title ?? null,\n kind: note.kind,\n status: note.status,\n payload_json: JSON.stringify(note),\n created_at: note.createdAt,\n updated_at: note.updatedAt,\n pinned: note.pinned ? 1 : 0,\n tags_json: JSON.stringify(note.tags ?? []),\n snippet: meta.snippet ?? null,\n cover_attachment_id: meta.coverAttachmentId ?? null,\n voice_attachment_id: meta.voiceAttachmentId ?? null,\n voice_duration_sec: meta.voiceDurationSec ?? null,\n attachment_names_json: meta.attachmentNames ? JSON.stringify(meta.attachmentNames) : null,\n group_id: note.groupId ?? null,\n last_opened_at: note.lastOpenedAt ?? null,\n task_done: note.taskMeta?.done != null ? (note.taskMeta.done ? 1 : 0) : null,\n task_due_at: note.taskMeta?.dueAt ?? null,\n heading_count: meta.headingCount ?? null,\n task_count: meta.taskCount ?? null,\n unchecked_task_count: meta.uncheckedTaskCount ?? null,\n link_count: meta.linkCount ?? null,\n };\n}\n\nfunction upsertNoteFts(db: ReturnType<typeof getSqliteDatabase>, note: Note): void {\n db.prepare(`DELETE FROM notes_fts WHERE note_id = ?`).run(note.id);\n const content = noteSearchContent(note);\n if (!content.trim()) {\n return;\n }\n db.prepare(`INSERT INTO notes_fts (content, note_id) VALUES (?, ?)`).run(content, note.id);\n}\n\nexport function upsertNoteRecord(note: Note): void {\n const row = noteToRow(note);\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO notes (\n note_id, title, kind, status, payload_json, created_at, updated_at,\n pinned, tags_json, snippet, cover_attachment_id, voice_attachment_id,\n voice_duration_sec, attachment_names_json, group_id, last_opened_at,\n task_done, task_due_at, heading_count, task_count, unchecked_task_count, link_count\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(note_id) DO UPDATE SET\n title = excluded.title,\n kind = excluded.kind,\n status = excluded.status,\n payload_json = excluded.payload_json,\n updated_at = excluded.updated_at,\n pinned = excluded.pinned,\n tags_json = excluded.tags_json,\n snippet = excluded.snippet,\n cover_attachment_id = excluded.cover_attachment_id,\n voice_attachment_id = excluded.voice_attachment_id,\n voice_duration_sec = excluded.voice_duration_sec,\n attachment_names_json = excluded.attachment_names_json,\n group_id = excluded.group_id,\n last_opened_at = excluded.last_opened_at,\n task_done = excluded.task_done,\n task_due_at = excluded.task_due_at,\n heading_count = excluded.heading_count,\n task_count = excluded.task_count,\n unchecked_task_count = excluded.unchecked_task_count,\n link_count = excluded.link_count`,\n ).run(\n row.note_id,\n row.title,\n row.kind,\n row.status,\n row.payload_json,\n row.created_at,\n row.updated_at,\n row.pinned,\n row.tags_json,\n row.snippet,\n row.cover_attachment_id,\n row.voice_attachment_id,\n row.voice_duration_sec,\n row.attachment_names_json,\n row.group_id,\n row.last_opened_at,\n row.task_done,\n row.task_due_at,\n row.heading_count,\n row.task_count,\n row.unchecked_task_count,\n row.link_count,\n );\n upsertNoteFts(db, note);\n });\n}\n\nexport function getNoteRecord(noteId: string): Note | null {\n const db = getSqliteDatabase();\n const row = db.prepare(`SELECT payload_json FROM notes WHERE note_id = ?`).get(noteId) as\n | { payload_json: string }\n | undefined;\n if (!row?.payload_json) {\n return null;\n }\n try {\n return JSON.parse(row.payload_json) as Note;\n } catch {\n return null;\n }\n}\n\nexport function deleteNoteRecord(noteId: string): boolean {\n return runSqliteWriteTransaction((db) => {\n const existing = db.prepare(`SELECT note_id FROM notes WHERE note_id = ?`).get(noteId);\n if (!existing) {\n return false;\n }\n db.prepare(`DELETE FROM notes_fts WHERE note_id = ?`).run(noteId);\n db.prepare(`DELETE FROM notes WHERE note_id = ?`).run(noteId);\n return true;\n });\n}\n\nexport function listNoteRecords(\n query: NotesListQuery = {},\n): { items: NoteIndexEntry[]; total: number; limit: number; offset: number; hasMore: boolean } {\n const db = getSqliteDatabase();\n const conditions: string[] = [];\n const params: Array<string | number> = [];\n\n if (query.status) {\n conditions.push(`status = ?`);\n params.push(query.status);\n } else {\n conditions.push(`status != ?`);\n params.push('trashed');\n }\n if (query.kind) {\n conditions.push(`kind = ?`);\n params.push(query.kind);\n }\n if (query.pinned !== undefined) {\n conditions.push(`pinned = ?`);\n params.push(query.pinned ? 1 : 0);\n }\n if (query.groupId !== undefined) {\n if (query.groupId === 'ungrouped') {\n conditions.push(`(group_id IS NULL OR group_id = '')`);\n } else {\n conditions.push(`group_id = ?`);\n params.push(query.groupId);\n }\n }\n if (query.pendingTasksOnly) {\n conditions.push(`kind = 'task' AND (task_done IS NULL OR task_done = 0)`);\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n const rows = db\n .prepare(\n `SELECT note_id, title, kind, status, payload_json, created_at, updated_at,\n pinned, tags_json, snippet, cover_attachment_id, voice_attachment_id,\n voice_duration_sec, attachment_names_json, group_id, last_opened_at,\n task_done, task_due_at, heading_count, task_count, unchecked_task_count, link_count\n FROM notes ${where}`,\n )\n .all(...params) as NoteRow[];\n\n let entries = rows.map(rowToIndexEntry);\n\n if (query.tag) {\n entries = entries.filter((entry) => entry.tags?.includes(query.tag!));\n }\n\n if (query.search) {\n const ftsQuery = escapeFts5Query(query.search);\n const ftsIds = new Set<string>();\n if (ftsQuery) {\n const ftsRows = db\n .prepare(\n `SELECT note_id FROM notes_fts WHERE notes_fts MATCH ? ORDER BY rank`,\n )\n .all(ftsQuery) as Array<{ note_id: string }>;\n for (const row of ftsRows) {\n ftsIds.add(row.note_id);\n }\n }\n entries = entries.filter((entry) => ftsIds.has(entry.id));\n }\n\n const sortField = query.sortBy || 'createdAt';\n const sortDir = query.sortOrder === 'asc' ? 1 : -1;\n entries = [...entries].sort((a, b) => {\n const aVal = (a[sortField] as number | undefined) ?? 0;\n const bVal = (b[sortField] as number | undefined) ?? 0;\n return (aVal - bVal) * sortDir;\n });\n\n const total = entries.length;\n const offset = query.offset || 0;\n const limit = Math.min(query.limit || 50, 200);\n const items = entries.slice(offset, offset + limit);\n const hasMore = offset + items.length < total;\n\n return { items, total, limit, offset, hasMore };\n}\n"],"mappings":";;;;AA8BA,SAAS,UAAU,MAAwB;AACzC,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,SAAO,MAAM,QAAQ,OAAO,GAAG,OAAO,QAAQ,MAAmB,OAAO,MAAM,SAAS,GAAG,EAAE;SACtF;AACN,SAAO,EAAE;;;AAIb,SAAS,qBAAqB,MAA2C;AACvE,KAAI,CAAC,KAAM,QAAO,KAAA;AAClB,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,SAAO,MAAM,QAAQ,OAAO,GAAG,OAAO,QAAQ,MAAmB,OAAO,MAAM,SAAS,GAAG,KAAA;SACpF;AACN;;;AAIJ,SAAS,gBAAgB,KAA8B;AACrD,QAAO;EACL,IAAI,IAAI;EACR,OAAO,IAAI,SAAS,KAAA;EACpB,MAAM,IAAI;EACV,QAAQ,IAAI;EACZ,WAAW,IAAI;EACf,WAAW,IAAI;EACf,QAAQ,IAAI,SAAS,OAAO,KAAA;EAC5B,MAAM,UAAU,IAAI,UAAU;EAC9B,SAAS,IAAI,WAAW,KAAA;EACxB,mBAAmB,IAAI,uBAAuB,KAAA;EAC9C,mBAAmB,IAAI,uBAAuB,KAAA;EAC9C,kBAAkB,IAAI,sBAAsB,KAAA;EAC5C,iBAAiB,qBAAqB,IAAI,sBAAsB;EAChE,SAAS,IAAI,YAAY,KAAA;EACzB,cAAc,IAAI,kBAAkB,KAAA;EACpC,UAAU,IAAI,aAAa,OAAO,QAAQ,IAAI,UAAU,GAAG,KAAA;EAC3D,WAAW,IAAI,eAAe,KAAA;EAC9B,cAAc,IAAI,iBAAiB,KAAA;EACnC,WAAW,IAAI,cAAc,KAAA;EAC7B,oBAAoB,IAAI,wBAAwB,KAAA;EAChD,WAAW,IAAI,cAAc,KAAA;EAC9B;;AAGH,SAAS,kBAAkB,MAAoB;CAC7C,MAAM,QAAQ,cAAc,KAAK;CACjC,MAAM,iBAAiB,KAAK,aAAa,KAAK,MAAM,EAAE,WAAW,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;CAC/F,MAAM,kBAAkB,2BAA2B,KAAK,EAAE,KAAK,IAAI,IAAI;AACvE,QAAO;EAAC,KAAK;EAAO;EAAO;EAAgB;EAAiB,GAAI,KAAK,QAAQ,EAAE;EAAE,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;;AAG9G,SAAS,UAAU,MAAsE;CACvF,MAAM,OAAO,mBAAmB,KAAK;AACrC,QAAO;EACL,SAAS,KAAK;EACd,OAAO,KAAK,SAAS;EACrB,MAAM,KAAK;EACX,QAAQ,KAAK;EACb,cAAc,KAAK,UAAU,KAAK;EAClC,YAAY,KAAK;EACjB,YAAY,KAAK;EACjB,QAAQ,KAAK,SAAS,IAAI;EAC1B,WAAW,KAAK,UAAU,KAAK,QAAQ,EAAE,CAAC;EAC1C,SAAS,KAAK,WAAW;EACzB,qBAAqB,KAAK,qBAAqB;EAC/C,qBAAqB,KAAK,qBAAqB;EAC/C,oBAAoB,KAAK,oBAAoB;EAC7C,uBAAuB,KAAK,kBAAkB,KAAK,UAAU,KAAK,gBAAgB,GAAG;EACrF,UAAU,KAAK,WAAW;EAC1B,gBAAgB,KAAK,gBAAgB;EACrC,WAAW,KAAK,UAAU,QAAQ,OAAQ,KAAK,SAAS,OAAO,IAAI,IAAK;EACxE,aAAa,KAAK,UAAU,SAAS;EACrC,eAAe,KAAK,gBAAgB;EACpC,YAAY,KAAK,aAAa;EAC9B,sBAAsB,KAAK,sBAAsB;EACjD,YAAY,KAAK,aAAa;EAC/B;;AAGH,SAAS,cAAc,IAA0C,MAAkB;AACjF,IAAG,QAAQ,0CAA0C,CAAC,IAAI,KAAK,GAAG;CAClE,MAAM,UAAU,kBAAkB,KAAK;AACvC,KAAI,CAAC,QAAQ,MAAM,CACjB;AAEF,IAAG,QAAQ,yDAAyD,CAAC,IAAI,SAAS,KAAK,GAAG;;AAG5F,SAAgB,iBAAiB,MAAkB;CACjD,MAAM,MAAM,UAAU,KAAK;AAC3B,4BAA2B,OAAO;AAChC,KAAG,QACD;;;;;;;;;;;;;;;;;;;;;;;;;;0CA2BD,CAAC,IACA,IAAI,SACJ,IAAI,OACJ,IAAI,MACJ,IAAI,QACJ,IAAI,cACJ,IAAI,YACJ,IAAI,YACJ,IAAI,QACJ,IAAI,WACJ,IAAI,SACJ,IAAI,qBACJ,IAAI,qBACJ,IAAI,oBACJ,IAAI,uBACJ,IAAI,UACJ,IAAI,gBACJ,IAAI,WACJ,IAAI,aACJ,IAAI,eACJ,IAAI,YACJ,IAAI,sBACJ,IAAI,WACL;AACD,gBAAc,IAAI,KAAK;GACvB;;AAGJ,SAAgB,cAAc,QAA6B;CAEzD,MAAM,MADK,mBACG,CAAC,QAAQ,mDAAmD,CAAC,IAAI,OAAO;AAGtF,KAAI,CAAC,KAAK,aACR,QAAO;AAET,KAAI;AACF,SAAO,KAAK,MAAM,IAAI,aAAa;SAC7B;AACN,SAAO;;;AAIX,SAAgB,iBAAiB,QAAyB;AACxD,QAAO,2BAA2B,OAAO;AAEvC,MAAI,CADa,GAAG,QAAQ,8CAA8C,CAAC,IAAI,OAClE,CACX,QAAO;AAET,KAAG,QAAQ,0CAA0C,CAAC,IAAI,OAAO;AACjE,KAAG,QAAQ,sCAAsC,CAAC,IAAI,OAAO;AAC7D,SAAO;GACP;;AAGJ,SAAgB,gBACd,QAAwB,EAAE,EACmE;CAC7F,MAAM,KAAK,mBAAmB;CAC9B,MAAM,aAAuB,EAAE;CAC/B,MAAM,SAAiC,EAAE;AAEzC,KAAI,MAAM,QAAQ;AAChB,aAAW,KAAK,aAAa;AAC7B,SAAO,KAAK,MAAM,OAAO;QACpB;AACL,aAAW,KAAK,cAAc;AAC9B,SAAO,KAAK,UAAU;;AAExB,KAAI,MAAM,MAAM;AACd,aAAW,KAAK,WAAW;AAC3B,SAAO,KAAK,MAAM,KAAK;;AAEzB,KAAI,MAAM,WAAW,KAAA,GAAW;AAC9B,aAAW,KAAK,aAAa;AAC7B,SAAO,KAAK,MAAM,SAAS,IAAI,EAAE;;AAEnC,KAAI,MAAM,YAAY,KAAA,EACpB,KAAI,MAAM,YAAY,YACpB,YAAW,KAAK,sCAAsC;MACjD;AACL,aAAW,KAAK,eAAe;AAC/B,SAAO,KAAK,MAAM,QAAQ;;AAG9B,KAAI,MAAM,iBACR,YAAW,KAAK,yDAAyD;CAG3E,MAAM,QAAQ,WAAW,SAAS,IAAI,SAAS,WAAW,KAAK,QAAQ,KAAK;CAW5E,IAAI,UAVS,GACV,QACC;;;;oBAIc,QACf,CACA,IAAI,GAAG,OAEQ,CAAC,IAAI,gBAAgB;AAEvC,KAAI,MAAM,IACR,WAAU,QAAQ,QAAQ,UAAU,MAAM,MAAM,SAAS,MAAM,IAAK,CAAC;AAGvE,KAAI,MAAM,QAAQ;EAChB,MAAM,WAAW,gBAAgB,MAAM,OAAO;EAC9C,MAAM,yBAAS,IAAI,KAAa;AAChC,MAAI,UAAU;GACZ,MAAM,UAAU,GACb,QACC,sEACD,CACA,IAAI,SAAS;AAChB,QAAK,MAAM,OAAO,QAChB,QAAO,IAAI,IAAI,QAAQ;;AAG3B,YAAU,QAAQ,QAAQ,UAAU,OAAO,IAAI,MAAM,GAAG,CAAC;;CAG3D,MAAM,YAAY,MAAM,UAAU;CAClC,MAAM,UAAU,MAAM,cAAc,QAAQ,IAAI;AAChD,WAAU,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,MAAM;AAGpC,WAFc,EAAE,cAAqC,MACvC,EAAE,cAAqC,MAC9B;GACvB;CAEF,MAAM,QAAQ,QAAQ;CACtB,MAAM,SAAS,MAAM,UAAU;CAC/B,MAAM,QAAQ,KAAK,IAAI,MAAM,SAAS,IAAI,IAAI;CAC9C,MAAM,QAAQ,QAAQ,MAAM,QAAQ,SAAS,MAAM;AAGnD,QAAO;EAAE;EAAO;EAAO;EAAO;EAAQ,SAFtB,SAAS,MAAM,SAAS;EAEO"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SCHEMA_META_SCHEMA_VERSION_KEY, ensureSchemaMetaTable, readSchemaVersion, readSchemaVersionForTest, setSchemaVersion } from "./schema-version.js";
|
|
2
2
|
import { XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_SCHEMA_VERSION, applyPendingMigrations } from "./migrations/runner.js";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
3
|
import { readFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
//#region src/storage/sqlite/schema.ts
|
|
7
7
|
const SCHEMA_DIR = dirname(fileURLToPath(import.meta.url));
|
|
@@ -12,7 +12,7 @@ function bootstrapFreshDatabase(db) {
|
|
|
12
12
|
db.exec("BEGIN IMMEDIATE");
|
|
13
13
|
try {
|
|
14
14
|
db.exec(readSchemaSql());
|
|
15
|
-
setSchemaVersion(db,
|
|
15
|
+
setSchemaVersion(db, 3);
|
|
16
16
|
db.exec("COMMIT");
|
|
17
17
|
} catch (error) {
|
|
18
18
|
try {
|
|
@@ -29,9 +29,9 @@ function ensureXopcDatabaseSchema(db) {
|
|
|
29
29
|
let currentVersion = readSchemaVersion(db);
|
|
30
30
|
if (currentVersion === 0) {
|
|
31
31
|
bootstrapFreshDatabase(db);
|
|
32
|
-
currentVersion =
|
|
32
|
+
currentVersion = 3;
|
|
33
33
|
}
|
|
34
|
-
applyPendingMigrations(db, { targetVersion:
|
|
34
|
+
applyPendingMigrations(db, { targetVersion: 3 });
|
|
35
35
|
}
|
|
36
36
|
//#endregion
|
|
37
37
|
export { SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_SCHEMA_VERSION, ensureSchemaMetaTable, ensureXopcDatabaseSchema, readSchemaVersion, readSchemaVersionForTest, setSchemaVersion };
|
|
@@ -149,7 +149,11 @@ CREATE TABLE IF NOT EXISTS notes (
|
|
|
149
149
|
group_id TEXT,
|
|
150
150
|
last_opened_at INTEGER,
|
|
151
151
|
task_done INTEGER,
|
|
152
|
-
task_due_at INTEGER
|
|
152
|
+
task_due_at INTEGER,
|
|
153
|
+
heading_count INTEGER,
|
|
154
|
+
task_count INTEGER,
|
|
155
|
+
unchecked_task_count INTEGER,
|
|
156
|
+
link_count INTEGER
|
|
153
157
|
);
|
|
154
158
|
|
|
155
159
|
CREATE INDEX IF NOT EXISTS idx_notes_status_updated
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { tmpdir } from "node:os";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
5
|
import { spawnSync } from "node:child_process";
|
|
6
6
|
//#region src/tui/clipboard-image.ts
|
|
7
7
|
const SUPPORTED_IMAGE_MIME_TYPES = [
|
|
@@ -2,8 +2,8 @@ import { resolveStateDir } from "../config/paths-state.js";
|
|
|
2
2
|
import { init_paths } from "../config/paths.js";
|
|
3
3
|
import { palette } from "./theme/dark.js";
|
|
4
4
|
import { palette as palette$1 } from "./theme/light.js";
|
|
5
|
-
import { join } from "node:path";
|
|
6
5
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
7
|
import chalk from "chalk";
|
|
8
8
|
//#region src/tui/theme-manager.ts
|
|
9
9
|
init_paths();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { resolveStateDir } from "../config/paths-state.js";
|
|
2
2
|
import { init_paths } from "../config/paths.js";
|
|
3
3
|
import { XOPC_TUI_KEYBINDINGS } from "./xopc-tui-keybindings.js";
|
|
4
|
-
import { join } from "node:path";
|
|
5
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
6
|
import { KeybindingsManager } from "@earendil-works/pi-tui";
|
|
7
7
|
//#region src/tui/tui-keybindings-file.ts
|
|
8
8
|
init_paths();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { homedir } from "node:os";
|
|
2
|
-
import { join } from "node:path";
|
|
3
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
4
|
//#region src/tui/tui-scoped-models.ts
|
|
5
5
|
const STORE_PATH = join(homedir(), ".xopc", "tui-scoped-models.json");
|
|
6
6
|
function normalizeWorkspaceKey(cwd) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveStateDir } from "../config/paths-state.js";
|
|
2
2
|
import { init_paths } from "../config/paths.js";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
5
|
//#region src/tui/tui-settings.ts
|
|
6
6
|
init_paths();
|
|
7
7
|
const DEFAULT_TUI_SETTINGS = {
|
package/dist/src/tui/tui.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { version } from "../../package.js";
|
|
2
|
+
import { loadConfig } from "../config/loader.js";
|
|
2
3
|
import { parseAgentSessionKey } from "../routing/session-key-utils.js";
|
|
3
4
|
import { init_agent_session_key } from "../routing/agent-session-key.js";
|
|
4
|
-
import { loadConfig } from "../config/loader.js";
|
|
5
5
|
import "../config/index.js";
|
|
6
6
|
import { resolveTuiSessionKey, resolveTuiStartupSessionKey } from "../routing/resolve-tui-session-key.js";
|
|
7
7
|
import { saveClipboardImageToTempFile } from "./clipboard-image.js";
|
|
@@ -31,9 +31,9 @@ import { TuiBottomBar } from "./components/tui-bottom-bar.js";
|
|
|
31
31
|
import { TuiHeader } from "./components/tui-header.js";
|
|
32
32
|
import { loadExtensionsForTuiLocalMode } from "./extension-host/load-extensions.js";
|
|
33
33
|
import { createTuiExtensionRuntime } from "./extension-host/runtime.js";
|
|
34
|
-
import { tmpdir } from "node:os";
|
|
35
|
-
import { join } from "node:path";
|
|
36
34
|
import { mkdtempSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
35
|
+
import { join } from "node:path";
|
|
36
|
+
import { tmpdir } from "node:os";
|
|
37
37
|
import { spawnSync } from "node:child_process";
|
|
38
38
|
import { Container, Loader, ProcessTerminal, TUI, setKeybindings } from "@earendil-works/pi-tui";
|
|
39
39
|
//#region src/tui/tui.ts
|
|
@@ -2,10 +2,10 @@ import { createLogger } from "../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
3
|
import { init_paths, resolveBinDir } from "../config/paths.js";
|
|
4
4
|
import { extractFrpcFromReleaseArchive, frpcReleaseArchiveExtension, nodePlatformForFrpTarget } from "./frpc-extract.js";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
6
|
-
import { join } from "node:path";
|
|
7
|
-
import { chmodSync, createWriteStream, existsSync, mkdirSync, rmSync } from "node:fs";
|
|
8
5
|
import { randomBytes } from "node:crypto";
|
|
6
|
+
import { chmodSync, createWriteStream, existsSync, mkdirSync, rmSync } from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
9
|
import { Readable } from "node:stream";
|
|
10
10
|
import { pipeline } from "node:stream/promises";
|
|
11
11
|
//#region src/tunnel/frpc-binary.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveStateDir } from "../config/paths-state.js";
|
|
2
2
|
import { init_paths } from "../config/paths.js";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
5
|
//#region src/tunnel/frpc-config.ts
|
|
6
6
|
init_paths();
|
|
7
7
|
function resolveFrpcConfigPath(tunnelId) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
3
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import AdmZip from "adm-zip";
|
|
7
7
|
import { gunzipSync } from "node:zlib";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveStateDir } from "../config/paths-state.js";
|
|
2
2
|
import { init_paths } from "../config/paths.js";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
5
|
//#region src/tunnel/tunnel-state.ts
|
|
6
6
|
init_paths();
|
|
7
7
|
const TUNNEL_STATE_FILE = "tunnel.json";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { __esmMin } from "../../../_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { getLogDir, init_config } from "./config.js";
|
|
3
|
+
import { appendFile } from "fs/promises";
|
|
3
4
|
import path from "path";
|
|
4
5
|
import { existsSync, mkdirSync } from "fs";
|
|
5
|
-
import { appendFile } from "fs/promises";
|
|
6
6
|
//#region src/utils/logger/audit.ts
|
|
7
7
|
/**
|
|
8
8
|
* Audit Log
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { init_pino_record, logEntrySearchText, pinoRecordToLogEntry } from "./pino-record.js";
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
2
3
|
import { basename, join } from "path";
|
|
3
4
|
import { createReadStream, existsSync, mkdirSync, readdirSync, statSync } from "fs";
|
|
4
5
|
import { Readable } from "stream";
|
|
5
|
-
import { readFile } from "fs/promises";
|
|
6
6
|
import { gunzip } from "zlib";
|
|
7
7
|
import { promisify } from "util";
|
|
8
8
|
import { createInterface } from "readline";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { __esmMin } from "../../../_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { config, getLogDir, init_config } from "./config.js";
|
|
3
|
+
import { writeFile } from "fs/promises";
|
|
3
4
|
import { join } from "path";
|
|
4
5
|
import { readFileSync, readdirSync, statSync, unlinkSync } from "fs";
|
|
5
|
-
import { writeFile } from "fs/promises";
|
|
6
6
|
import { gzip } from "zlib";
|
|
7
7
|
import { promisify } from "util";
|
|
8
8
|
//#region src/utils/logger/rotation.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
-
import { join } from "path";
|
|
4
3
|
import { unlink, writeFile } from "fs/promises";
|
|
4
|
+
import { join } from "path";
|
|
5
5
|
import { spawn } from "child_process";
|
|
6
6
|
import { tmpdir } from "os";
|
|
7
7
|
//#region src/voice/tts/audio.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createLogger } from "../../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../../utils/logger.js";
|
|
3
3
|
import { registerSpeechProvider } from "../speech-registry.js";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
4
|
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
7
|
//#region src/voice/tts/providers/edge-speech.ts
|
|
8
8
|
/**
|
|
9
9
|
* Edge TTS provider — wraps the `node-edge-tts` package. Requires no API key
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { resolveWorkflowRunEventsPath, resolveWorkflowRunsDir } from "./paths.js";
|
|
4
|
-
import { dirname } from "node:path";
|
|
5
4
|
import { randomUUID } from "node:crypto";
|
|
6
5
|
import { appendFile, mkdir, readFile, readdir } from "node:fs/promises";
|
|
6
|
+
import { dirname } from "node:path";
|
|
7
7
|
//#region src/workflows/store/event-store.ts
|
|
8
8
|
init_logger();
|
|
9
9
|
const log = createLogger("WorkflowEventStore");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
|
|
1
2
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
3
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
-
import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
|
|
4
4
|
import { projectWorkflowRunView } from "../engine/projector.js";
|
|
5
5
|
import { resolveWorkflowRunViewPath } from "./paths.js";
|
|
6
6
|
import { WorkflowEventStore } from "./event-store.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xopcai/xopc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.102",
|
|
4
4
|
"description": "The OPC workstation that grows with you: AI assistant for One Person Companies — CLI, gateway, multi-channel (Telegram/WeChat), 20+ LLM providers via pi-ai, extensions and skills.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|