@tt-a1i/hive 1.7.0 → 2.0.2
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/CHANGELOG.md +60 -0
- package/README.en.md +73 -11
- package/README.md +41 -8
- package/dist/src/cli/hive-remote.d.ts +46 -0
- package/dist/src/cli/hive-remote.js +257 -0
- package/dist/src/cli/hive-update.js +7 -2
- package/dist/src/cli/hive.d.ts +6 -0
- package/dist/src/cli/hive.js +64 -0
- package/dist/src/cli/team.d.ts +22 -0
- package/dist/src/cli/team.js +255 -5
- package/dist/src/server/agent-command-resolver.js +10 -3
- package/dist/src/server/agent-exit-classification.d.ts +6 -0
- package/dist/src/server/agent-exit-classification.js +6 -0
- package/dist/src/server/agent-manager-support.d.ts +2 -1
- package/dist/src/server/agent-manager-support.js +59 -15
- package/dist/src/server/agent-manager.d.ts +3 -0
- package/dist/src/server/agent-manager.js +22 -7
- package/dist/src/server/agent-run-bootstrap.d.ts +14 -0
- package/dist/src/server/agent-run-bootstrap.js +11 -4
- package/dist/src/server/agent-run-exit-handler.js +14 -8
- package/dist/src/server/agent-run-starter.d.ts +3 -1
- package/dist/src/server/agent-run-starter.js +22 -5
- package/dist/src/server/agent-run-sync.js +13 -5
- package/dist/src/server/agent-runtime-types.d.ts +1 -0
- package/dist/src/server/agent-runtime.d.ts +2 -1
- package/dist/src/server/agent-runtime.js +9 -2
- package/dist/src/server/agent-startup-instructions.d.ts +2 -1
- package/dist/src/server/agent-startup-instructions.js +8 -4
- package/dist/src/server/agent-stdin-dispatcher.d.ts +4 -2
- package/dist/src/server/agent-stdin-dispatcher.js +35 -3
- package/dist/src/server/command-preset-defaults.d.ts +6 -1
- package/dist/src/server/command-preset-defaults.js +56 -0
- package/dist/src/server/fs-browse.d.ts +2 -0
- package/dist/src/server/fs-browse.js +165 -31
- package/dist/src/server/fs-pick-folder.js +6 -69
- package/dist/src/server/fs-sandbox.d.ts +5 -3
- package/dist/src/server/fs-sandbox.js +5 -3
- package/dist/src/server/hive-team-guidance.js +18 -6
- package/dist/src/server/machine-name.d.ts +2 -0
- package/dist/src/server/machine-name.js +13 -0
- package/dist/src/server/open-target-commands.d.ts +1 -0
- package/dist/src/server/open-target-commands.js +4 -1
- package/dist/src/server/orchestrator-autostart.js +1 -1
- package/dist/src/server/platform-path.d.ts +1 -0
- package/dist/src/server/platform-path.js +14 -1
- package/dist/src/server/post-start-input-writer.js +50 -13
- package/dist/src/server/preset-launch-support.js +1 -0
- package/dist/src/server/recovery-summary.d.ts +2 -1
- package/dist/src/server/recovery-summary.js +2 -1
- package/dist/src/server/remote-audit-store.d.ts +51 -0
- package/dist/src/server/remote-audit-store.js +108 -0
- package/dist/src/server/remote-config-keys.d.ts +17 -0
- package/dist/src/server/remote-config-keys.js +27 -0
- package/dist/src/server/remote-control-constants.d.ts +30 -0
- package/dist/src/server/remote-control-constants.js +29 -0
- package/dist/src/server/remote-device-session.d.ts +40 -0
- package/dist/src/server/remote-device-session.js +22 -0
- package/dist/src/server/remote-device-store.d.ts +36 -0
- package/dist/src/server/remote-device-store.js +67 -0
- package/dist/src/server/remote-frame-bridge.d.ts +102 -0
- package/dist/src/server/remote-frame-bridge.js +791 -0
- package/dist/src/server/remote-gateway-client.d.ts +14 -0
- package/dist/src/server/remote-gateway-client.js +36 -0
- package/dist/src/server/remote-loopback-auth.d.ts +6 -0
- package/dist/src/server/remote-loopback-auth.js +112 -0
- package/dist/src/server/remote-pairing-tunnel.d.ts +59 -0
- package/dist/src/server/remote-pairing-tunnel.js +146 -0
- package/dist/src/server/remote-pairing.d.ts +58 -0
- package/dist/src/server/remote-pairing.js +237 -0
- package/dist/src/server/remote-tunnel.d.ts +113 -0
- package/dist/src/server/remote-tunnel.js +514 -0
- package/dist/src/server/restart-policy-support.d.ts +4 -1
- package/dist/src/server/restart-policy-support.js +3 -1
- package/dist/src/server/restart-policy.d.ts +1 -1
- package/dist/src/server/restart-policy.js +19 -3
- package/dist/src/server/route-types.d.ts +1 -1
- package/dist/src/server/routes-dispatches.js +1 -1
- package/dist/src/server/routes-fs.js +3 -3
- package/dist/src/server/routes-marketplace.js +2 -2
- package/dist/src/server/routes-open-workspace.js +1 -1
- package/dist/src/server/routes-remote.d.ts +2 -0
- package/dist/src/server/routes-remote.js +166 -0
- package/dist/src/server/routes-runtime.js +6 -6
- package/dist/src/server/routes-settings.js +16 -16
- package/dist/src/server/routes-tasks.js +2 -2
- package/dist/src/server/routes-team-memory.d.ts +2 -0
- package/dist/src/server/routes-team-memory.js +154 -0
- package/dist/src/server/routes-team-recall.d.ts +2 -0
- package/dist/src/server/routes-team-recall.js +119 -0
- package/dist/src/server/routes-team.js +31 -9
- package/dist/src/server/routes-ui.js +11 -1
- package/dist/src/server/routes-workflow-schedules.js +3 -3
- package/dist/src/server/routes-workflows.js +5 -5
- package/dist/src/server/routes-workspace-memory-dreams.d.ts +2 -0
- package/dist/src/server/routes-workspace-memory-dreams.js +105 -0
- package/dist/src/server/routes-workspace-memory.d.ts +2 -0
- package/dist/src/server/routes-workspace-memory.js +215 -0
- package/dist/src/server/routes-workspaces.js +9 -9
- package/dist/src/server/routes.js +10 -0
- package/dist/src/server/runtime-database.d.ts +1 -0
- package/dist/src/server/runtime-database.js +27 -2
- package/dist/src/server/runtime-restart-policy.d.ts +3 -1
- package/dist/src/server/runtime-restart-policy.js +2 -1
- package/dist/src/server/runtime-store-contract.d.ts +37 -0
- package/dist/src/server/runtime-store-dream.d.ts +23 -0
- package/dist/src/server/runtime-store-dream.js +16 -0
- package/dist/src/server/runtime-store-helpers.d.ts +20 -0
- package/dist/src/server/runtime-store-helpers.js +81 -7
- package/dist/src/server/runtime-store-memory.d.ts +33 -0
- package/dist/src/server/runtime-store-memory.js +37 -0
- package/dist/src/server/runtime-store-remote.d.ts +5 -0
- package/dist/src/server/runtime-store-remote.js +45 -0
- package/dist/src/server/runtime-store-workflows.js +2 -0
- package/dist/src/server/runtime-store.js +14 -3
- package/dist/src/server/session-capture-claude.d.ts +1 -1
- package/dist/src/server/session-capture-claude.js +7 -4
- package/dist/src/server/session-capture-codex.js +4 -5
- package/dist/src/server/session-capture-gemini.js +4 -5
- package/dist/src/server/session-capture-opencode.d.ts +4 -4
- package/dist/src/server/session-capture-opencode.js +20 -12
- package/dist/src/server/session-capture-qwen.d.ts +5 -0
- package/dist/src/server/session-capture-qwen.js +104 -0
- package/dist/src/server/session-capture.d.ts +17 -0
- package/dist/src/server/session-capture.js +16 -0
- package/dist/src/server/sqlite-schema-v23.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v23.js +43 -0
- package/dist/src/server/sqlite-schema-v24.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v24.js +34 -0
- package/dist/src/server/sqlite-schema-v25.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v25.js +127 -0
- package/dist/src/server/sqlite-schema-v26.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v26.js +56 -0
- package/dist/src/server/sqlite-schema-v27.d.ts +6 -0
- package/dist/src/server/sqlite-schema-v27.js +92 -0
- package/dist/src/server/sqlite-schema-v28.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v28.js +19 -0
- package/dist/src/server/sqlite-schema-v29.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v29.js +27 -0
- package/dist/src/server/sqlite-schema-v30.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v30.js +27 -0
- package/dist/src/server/sqlite-schema-v31.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v31.js +30 -0
- package/dist/src/server/sqlite-schema.d.ts +1 -1
- package/dist/src/server/sqlite-schema.js +49 -1
- package/dist/src/server/startup-command-parser.js +5 -1
- package/dist/src/server/tasks-file-watcher.d.ts +2 -0
- package/dist/src/server/tasks-file-watcher.js +15 -6
- package/dist/src/server/tasks-file.js +30 -5
- package/dist/src/server/tasks-websocket-server.js +4 -0
- package/dist/src/server/team-authz.d.ts +1 -1
- package/dist/src/server/team-authz.js +13 -1
- package/dist/src/server/team-list-enrichment.js +3 -1
- package/dist/src/server/team-memory-digest.d.ts +52 -0
- package/dist/src/server/team-memory-digest.js +200 -0
- package/dist/src/server/team-memory-dream-applier.d.ts +5 -0
- package/dist/src/server/team-memory-dream-applier.js +234 -0
- package/dist/src/server/team-memory-dream-http-serializers.d.ts +13 -0
- package/dist/src/server/team-memory-dream-http-serializers.js +12 -0
- package/dist/src/server/team-memory-dream-ops.d.ts +40 -0
- package/dist/src/server/team-memory-dream-ops.js +153 -0
- package/dist/src/server/team-memory-dream-reverter.d.ts +22 -0
- package/dist/src/server/team-memory-dream-reverter.js +221 -0
- package/dist/src/server/team-memory-dream-run-store.d.ts +23 -0
- package/dist/src/server/team-memory-dream-run-store.js +211 -0
- package/dist/src/server/team-memory-dream-runner.d.ts +37 -0
- package/dist/src/server/team-memory-dream-runner.js +178 -0
- package/dist/src/server/team-memory-dream-scheduler.d.ts +32 -0
- package/dist/src/server/team-memory-dream-scheduler.js +115 -0
- package/dist/src/server/team-memory-dream-store.d.ts +19 -0
- package/dist/src/server/team-memory-dream-store.js +16 -0
- package/dist/src/server/team-memory-dream-types.d.ts +104 -0
- package/dist/src/server/team-memory-dream-types.js +23 -0
- package/dist/src/server/team-memory-export.d.ts +22 -0
- package/dist/src/server/team-memory-export.js +220 -0
- package/dist/src/server/team-memory-feature.d.ts +12 -0
- package/dist/src/server/team-memory-feature.js +12 -0
- package/dist/src/server/team-memory-http-serializers.d.ts +102 -0
- package/dist/src/server/team-memory-http-serializers.js +46 -0
- package/dist/src/server/team-memory-injection.d.ts +31 -0
- package/dist/src/server/team-memory-injection.js +49 -0
- package/dist/src/server/team-memory-store.d.ts +116 -0
- package/dist/src/server/team-memory-store.js +513 -0
- package/dist/src/server/team-operations.d.ts +5 -1
- package/dist/src/server/team-operations.js +46 -16
- package/dist/src/server/team-recall-store.d.ts +38 -0
- package/dist/src/server/team-recall-store.js +205 -0
- package/dist/src/server/terminal-input-profile.d.ts +1 -1
- package/dist/src/server/terminal-input-profile.js +18 -0
- package/dist/src/server/terminal-ws-server.js +6 -0
- package/dist/src/server/ui-auth-helpers.d.ts +1 -1
- package/dist/src/server/ui-auth-helpers.js +7 -1
- package/dist/src/server/ui-auth.d.ts +3 -0
- package/dist/src/server/ui-auth.js +21 -1
- package/dist/src/server/workflow-cli-policy.d.ts +2 -3
- package/dist/src/server/workflow-cli-policy.js +3 -3
- package/dist/src/server/workflow-runner.d.ts +1 -0
- package/dist/src/server/workflow-runner.js +9 -4
- package/dist/src/server/workspace-path-validation.js +6 -2
- package/dist/src/server/workspace-store.d.ts +1 -1
- package/dist/src/server/workspace-store.js +35 -9
- package/dist/src/shared/fs-browse.d.ts +1 -0
- package/dist/src/shared/fs-browse.js +1 -0
- package/dist/src/shared/path-input.d.ts +12 -0
- package/dist/src/shared/path-input.js +22 -0
- package/dist/src/shared/remote-bridge-routing.d.ts +19 -0
- package/dist/src/shared/remote-bridge-routing.js +141 -0
- package/dist/src/shared/remote-crypto.d.ts +138 -0
- package/dist/src/shared/remote-crypto.js +427 -0
- package/dist/src/shared/remote-pairing-code.d.ts +7 -0
- package/dist/src/shared/remote-pairing-code.js +47 -0
- package/dist/src/shared/remote-protocol.d.ts +160 -0
- package/dist/src/shared/remote-protocol.js +526 -0
- package/dist/src/shared/team-memory.d.ts +11 -0
- package/dist/src/shared/team-memory.js +10 -0
- package/dist/src/shared/team-recall.d.ts +1 -0
- package/dist/src/shared/team-recall.js +1 -0
- package/dist/src/shared/types.d.ts +4 -5
- package/package.json +12 -5
- package/scripts/postinstall-native-artifacts.mjs +113 -0
- package/web/dist/assets/AddWorkerDialog-CbV75qUX.js +2 -0
- package/web/dist/assets/AddWorkspaceFlow-CwV-7wPx.js +1 -0
- package/web/dist/assets/FirstRunWizard-a6PWIK3x.js +1 -0
- package/web/dist/assets/MarketplaceDrawer-Dd8WIA8T.js +67 -0
- package/web/dist/assets/TaskGraphDrawer-Bk5WFIk_.js +1 -0
- package/web/dist/assets/{WhatsNewDialog-CHkZeINH.js → WhatsNewDialog-C2VZaip0.js} +1 -1
- package/web/dist/assets/WorkerModal-DucW-9YT.js +1 -0
- package/web/dist/assets/WorkflowsDrawer-Bjf4olbR.js +1 -0
- package/web/dist/assets/WorkspaceMemoryDrawer-DglCy_5f.js +1 -0
- package/web/dist/assets/WorkspaceTaskDrawer-BIWwISvA.js +1 -0
- package/web/dist/assets/index-BAiLYajK.css +1 -0
- package/web/dist/assets/index-BV2k9Dts.js +73 -0
- package/web/dist/assets/search-Bk2HQvO7.js +1 -0
- package/web/dist/assets/square-terminal-D93m9hfY.js +1 -0
- package/web/dist/cli-icons/agy.png +0 -0
- package/web/dist/cli-icons/cursor.ico +0 -0
- package/web/dist/cli-icons/grok.ico +0 -0
- package/web/dist/cli-icons/qwen.png +0 -0
- package/web/dist/index.html +8 -3
- package/web/dist/sw.js +1 -1
- package/scripts/fix-runtime-artifacts.mjs +0 -33
- package/web/dist/assets/AddWorkerDialog-BRUxpa3f.js +0 -2
- package/web/dist/assets/AddWorkspaceDialog-D56x5JCb.js +0 -1
- package/web/dist/assets/FirstRunWizard-BFVaMIsE.js +0 -1
- package/web/dist/assets/MarketplaceDrawer-DeEZ35dN.js +0 -76
- package/web/dist/assets/WorkerModal-BBCuMLIa.js +0 -1
- package/web/dist/assets/WorkspaceTaskDrawer-CpZHAcj1.js +0 -1
- package/web/dist/assets/WorkspaceTerminalPanels-7If2mDyp.js +0 -1
- package/web/dist/assets/WorkspaceTerminalPanels-DDGTF8rc.css +0 -1
- package/web/dist/assets/index-5zh61jMg.css +0 -1
- package/web/dist/assets/index-CxNL0O-C.js +0 -73
- package/web/dist/assets/path-join-7MR1s7b1.js +0 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const tableExists = (db, table) => Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?").get(table));
|
|
2
|
+
const quoteFtsToken = (value) => `"${value.replaceAll('"', '""')}"`;
|
|
3
|
+
const firstUnicodeTerm = (value) => {
|
|
4
|
+
if (!value)
|
|
5
|
+
return null;
|
|
6
|
+
const token = value.trim().split(/\s+/).find(Boolean);
|
|
7
|
+
if (!token)
|
|
8
|
+
return null;
|
|
9
|
+
return token;
|
|
10
|
+
};
|
|
11
|
+
const firstTrigramTerm = (value) => {
|
|
12
|
+
const token = firstUnicodeTerm(value);
|
|
13
|
+
if (!token)
|
|
14
|
+
return null;
|
|
15
|
+
return [...token].slice(0, Math.max(1, Math.min(3, [...token].length))).join('');
|
|
16
|
+
};
|
|
17
|
+
const ftsHasSampleHit = (db, table, term) => db
|
|
18
|
+
.prepare(`SELECT COUNT(*) AS count FROM ${table} WHERE ${table} MATCH ?`)
|
|
19
|
+
.get(quoteFtsToken(term)).count > 0;
|
|
20
|
+
const shouldRebuildMessageIndexes = (db) => {
|
|
21
|
+
const sample = db
|
|
22
|
+
.prepare(`SELECT text
|
|
23
|
+
FROM messages
|
|
24
|
+
ORDER BY sequence ASC
|
|
25
|
+
LIMIT 1`)
|
|
26
|
+
.get();
|
|
27
|
+
if (!sample)
|
|
28
|
+
return false;
|
|
29
|
+
const unicodeTerm = firstUnicodeTerm(sample.text);
|
|
30
|
+
const trigramTerm = firstTrigramTerm(sample.text);
|
|
31
|
+
if (!unicodeTerm && !trigramTerm)
|
|
32
|
+
return false;
|
|
33
|
+
const unicodeHealthy = unicodeTerm ? ftsHasSampleHit(db, 'messages_fts', unicodeTerm) : true;
|
|
34
|
+
const trigramHealthy = trigramTerm
|
|
35
|
+
? ftsHasSampleHit(db, 'messages_fts_trigram', trigramTerm)
|
|
36
|
+
: true;
|
|
37
|
+
return !(unicodeHealthy && trigramHealthy);
|
|
38
|
+
};
|
|
39
|
+
const shouldRebuildDispatchIndexes = (db) => {
|
|
40
|
+
const sample = db
|
|
41
|
+
.prepare(`SELECT text, report_text
|
|
42
|
+
FROM dispatches
|
|
43
|
+
ORDER BY sequence ASC
|
|
44
|
+
LIMIT 1`)
|
|
45
|
+
.get();
|
|
46
|
+
if (!sample)
|
|
47
|
+
return false;
|
|
48
|
+
const unicodeTerm = firstUnicodeTerm(sample.text) ?? firstUnicodeTerm(sample.report_text);
|
|
49
|
+
const trigramTerm = firstTrigramTerm(sample.text) ?? firstTrigramTerm(sample.report_text);
|
|
50
|
+
if (!unicodeTerm && !trigramTerm)
|
|
51
|
+
return false;
|
|
52
|
+
const unicodeHealthy = unicodeTerm ? ftsHasSampleHit(db, 'dispatches_fts', unicodeTerm) : true;
|
|
53
|
+
const trigramHealthy = trigramTerm
|
|
54
|
+
? ftsHasSampleHit(db, 'dispatches_fts_trigram', trigramTerm)
|
|
55
|
+
: true;
|
|
56
|
+
return !(unicodeHealthy && trigramHealthy);
|
|
57
|
+
};
|
|
58
|
+
export const applySchemaVersion25 = (db) => {
|
|
59
|
+
const messagesFtsExists = tableExists(db, 'messages_fts');
|
|
60
|
+
const messagesFtsTrigramExists = tableExists(db, 'messages_fts_trigram');
|
|
61
|
+
const dispatchesFtsExists = tableExists(db, 'dispatches_fts');
|
|
62
|
+
const dispatchesFtsTrigramExists = tableExists(db, 'dispatches_fts_trigram');
|
|
63
|
+
db.exec(`
|
|
64
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts
|
|
65
|
+
USING fts5(text, content='messages', content_rowid='sequence', tokenize='unicode61');
|
|
66
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts_trigram
|
|
67
|
+
USING fts5(text, content='messages', content_rowid='sequence', tokenize='trigram');
|
|
68
|
+
|
|
69
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS dispatches_fts
|
|
70
|
+
USING fts5(text, report_text, content='dispatches', content_rowid='sequence', tokenize='unicode61');
|
|
71
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS dispatches_fts_trigram
|
|
72
|
+
USING fts5(text, report_text, content='dispatches', content_rowid='sequence', tokenize='trigram');
|
|
73
|
+
|
|
74
|
+
CREATE TRIGGER IF NOT EXISTS messages_fts_ai AFTER INSERT ON messages BEGIN
|
|
75
|
+
INSERT INTO messages_fts(rowid, text) VALUES (new.sequence, new.text);
|
|
76
|
+
INSERT INTO messages_fts_trigram(rowid, text) VALUES (new.sequence, new.text);
|
|
77
|
+
END;
|
|
78
|
+
CREATE TRIGGER IF NOT EXISTS messages_fts_ad AFTER DELETE ON messages BEGIN
|
|
79
|
+
INSERT INTO messages_fts(messages_fts, rowid, text) VALUES('delete', old.sequence, old.text);
|
|
80
|
+
INSERT INTO messages_fts_trigram(messages_fts_trigram, rowid, text)
|
|
81
|
+
VALUES('delete', old.sequence, old.text);
|
|
82
|
+
END;
|
|
83
|
+
CREATE TRIGGER IF NOT EXISTS messages_fts_au AFTER UPDATE ON messages BEGIN
|
|
84
|
+
INSERT INTO messages_fts(messages_fts, rowid, text) VALUES('delete', old.sequence, old.text);
|
|
85
|
+
INSERT INTO messages_fts(rowid, text) VALUES (new.sequence, new.text);
|
|
86
|
+
INSERT INTO messages_fts_trigram(messages_fts_trigram, rowid, text)
|
|
87
|
+
VALUES('delete', old.sequence, old.text);
|
|
88
|
+
INSERT INTO messages_fts_trigram(rowid, text) VALUES (new.sequence, new.text);
|
|
89
|
+
END;
|
|
90
|
+
|
|
91
|
+
CREATE TRIGGER IF NOT EXISTS dispatches_fts_ai AFTER INSERT ON dispatches BEGIN
|
|
92
|
+
INSERT INTO dispatches_fts(rowid, text, report_text)
|
|
93
|
+
VALUES (new.sequence, new.text, new.report_text);
|
|
94
|
+
INSERT INTO dispatches_fts_trigram(rowid, text, report_text)
|
|
95
|
+
VALUES (new.sequence, new.text, new.report_text);
|
|
96
|
+
END;
|
|
97
|
+
CREATE TRIGGER IF NOT EXISTS dispatches_fts_ad AFTER DELETE ON dispatches BEGIN
|
|
98
|
+
INSERT INTO dispatches_fts(dispatches_fts, rowid, text, report_text)
|
|
99
|
+
VALUES('delete', old.sequence, old.text, old.report_text);
|
|
100
|
+
INSERT INTO dispatches_fts_trigram(dispatches_fts_trigram, rowid, text, report_text)
|
|
101
|
+
VALUES('delete', old.sequence, old.text, old.report_text);
|
|
102
|
+
END;
|
|
103
|
+
CREATE TRIGGER IF NOT EXISTS dispatches_fts_au AFTER UPDATE ON dispatches BEGIN
|
|
104
|
+
INSERT INTO dispatches_fts(dispatches_fts, rowid, text, report_text)
|
|
105
|
+
VALUES('delete', old.sequence, old.text, old.report_text);
|
|
106
|
+
INSERT INTO dispatches_fts(rowid, text, report_text)
|
|
107
|
+
VALUES (new.sequence, new.text, new.report_text);
|
|
108
|
+
INSERT INTO dispatches_fts_trigram(dispatches_fts_trigram, rowid, text, report_text)
|
|
109
|
+
VALUES('delete', old.sequence, old.text, old.report_text);
|
|
110
|
+
INSERT INTO dispatches_fts_trigram(rowid, text, report_text)
|
|
111
|
+
VALUES (new.sequence, new.text, new.report_text);
|
|
112
|
+
END;
|
|
113
|
+
`);
|
|
114
|
+
if (!messagesFtsExists ||
|
|
115
|
+
!messagesFtsTrigramExists ||
|
|
116
|
+
!dispatchesFtsExists ||
|
|
117
|
+
!dispatchesFtsTrigramExists ||
|
|
118
|
+
shouldRebuildMessageIndexes(db) ||
|
|
119
|
+
shouldRebuildDispatchIndexes(db)) {
|
|
120
|
+
db.exec(`
|
|
121
|
+
INSERT INTO messages_fts(messages_fts) VALUES('rebuild');
|
|
122
|
+
INSERT INTO messages_fts_trigram(messages_fts_trigram) VALUES('rebuild');
|
|
123
|
+
INSERT INTO dispatches_fts(dispatches_fts) VALUES('rebuild');
|
|
124
|
+
INSERT INTO dispatches_fts_trigram(dispatches_fts_trigram) VALUES('rebuild');
|
|
125
|
+
`);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export const applySchemaVersion26 = (db) => {
|
|
2
|
+
db.exec(`
|
|
3
|
+
CREATE TABLE IF NOT EXISTS memory_entries (
|
|
4
|
+
id TEXT PRIMARY KEY,
|
|
5
|
+
workspace_id TEXT,
|
|
6
|
+
scope TEXT NOT NULL DEFAULT 'workspace',
|
|
7
|
+
fts_rowid INTEGER UNIQUE,
|
|
8
|
+
kind TEXT NOT NULL,
|
|
9
|
+
body TEXT NOT NULL,
|
|
10
|
+
tags TEXT,
|
|
11
|
+
status TEXT NOT NULL,
|
|
12
|
+
source TEXT NOT NULL DEFAULT 'manual',
|
|
13
|
+
confidence REAL,
|
|
14
|
+
pinned INTEGER NOT NULL DEFAULT 0,
|
|
15
|
+
disabled INTEGER NOT NULL DEFAULT 0,
|
|
16
|
+
created_at INTEGER NOT NULL,
|
|
17
|
+
updated_at INTEGER NOT NULL,
|
|
18
|
+
archived_at INTEGER,
|
|
19
|
+
last_injected_at INTEGER
|
|
20
|
+
);
|
|
21
|
+
CREATE INDEX IF NOT EXISTS idx_memory_entries_ws_status
|
|
22
|
+
ON memory_entries(workspace_id, status);
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_memory_entries_ws_updated
|
|
24
|
+
ON memory_entries(workspace_id, updated_at);
|
|
25
|
+
|
|
26
|
+
CREATE TABLE IF NOT EXISTS memory_sources (
|
|
27
|
+
id TEXT PRIMARY KEY,
|
|
28
|
+
memory_id TEXT NOT NULL REFERENCES memory_entries(id) ON DELETE CASCADE,
|
|
29
|
+
source_type TEXT NOT NULL,
|
|
30
|
+
source_id TEXT,
|
|
31
|
+
source_sequence INTEGER,
|
|
32
|
+
excerpt TEXT,
|
|
33
|
+
text_hash TEXT,
|
|
34
|
+
actor_agent_id_snapshot TEXT,
|
|
35
|
+
actor_name_snapshot TEXT,
|
|
36
|
+
actor_role_snapshot TEXT,
|
|
37
|
+
created_at INTEGER NOT NULL
|
|
38
|
+
);
|
|
39
|
+
CREATE INDEX IF NOT EXISTS idx_memory_sources_memory
|
|
40
|
+
ON memory_sources(memory_id);
|
|
41
|
+
|
|
42
|
+
CREATE TABLE IF NOT EXISTS memory_injections (
|
|
43
|
+
id TEXT PRIMARY KEY,
|
|
44
|
+
memory_id TEXT NOT NULL REFERENCES memory_entries(id) ON DELETE CASCADE,
|
|
45
|
+
workspace_id TEXT,
|
|
46
|
+
target_agent_id_snapshot TEXT,
|
|
47
|
+
context_type TEXT NOT NULL,
|
|
48
|
+
dispatch_id TEXT,
|
|
49
|
+
injected_at INTEGER NOT NULL
|
|
50
|
+
);
|
|
51
|
+
CREATE INDEX IF NOT EXISTS idx_memory_injections_ws
|
|
52
|
+
ON memory_injections(workspace_id, injected_at);
|
|
53
|
+
CREATE INDEX IF NOT EXISTS idx_memory_injections_memory
|
|
54
|
+
ON memory_injections(memory_id, injected_at);
|
|
55
|
+
`);
|
|
56
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const tableExists = (db, table) => Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?").get(table));
|
|
2
|
+
const ensureFtsRowidColumn = (db) => {
|
|
3
|
+
const columns = new Set(db.prepare('PRAGMA table_info(memory_entries)').all().map((column) => column.name));
|
|
4
|
+
if (!columns.has('fts_rowid')) {
|
|
5
|
+
db.exec('ALTER TABLE memory_entries ADD COLUMN fts_rowid INTEGER');
|
|
6
|
+
}
|
|
7
|
+
db.exec(`
|
|
8
|
+
UPDATE memory_entries
|
|
9
|
+
SET fts_rowid = rowid
|
|
10
|
+
WHERE fts_rowid IS NULL;
|
|
11
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_memory_entries_fts_rowid
|
|
12
|
+
ON memory_entries(fts_rowid)
|
|
13
|
+
WHERE fts_rowid IS NOT NULL;
|
|
14
|
+
`);
|
|
15
|
+
};
|
|
16
|
+
const quoteFtsToken = (value) => `"${value.replaceAll('"', '""')}"`;
|
|
17
|
+
const firstUnicodeTerm = (value) => {
|
|
18
|
+
if (!value)
|
|
19
|
+
return null;
|
|
20
|
+
const token = value.trim().split(/\s+/).find(Boolean);
|
|
21
|
+
if (!token)
|
|
22
|
+
return null;
|
|
23
|
+
return token;
|
|
24
|
+
};
|
|
25
|
+
const firstTrigramTerm = (value) => {
|
|
26
|
+
const token = firstUnicodeTerm(value);
|
|
27
|
+
if (!token)
|
|
28
|
+
return null;
|
|
29
|
+
return [...token].slice(0, Math.max(1, Math.min(3, [...token].length))).join('');
|
|
30
|
+
};
|
|
31
|
+
const ftsHasSampleHit = (db, table, term) => db
|
|
32
|
+
.prepare(`SELECT COUNT(*) AS count FROM ${table} WHERE ${table} MATCH ?`)
|
|
33
|
+
.get(quoteFtsToken(term)).count > 0;
|
|
34
|
+
const shouldRebuildExistingIndex = (db) => {
|
|
35
|
+
const sample = db
|
|
36
|
+
.prepare(`SELECT body, tags
|
|
37
|
+
FROM memory_entries
|
|
38
|
+
WHERE scope = 'workspace'
|
|
39
|
+
ORDER BY created_at ASC, id ASC
|
|
40
|
+
LIMIT 1`)
|
|
41
|
+
.get();
|
|
42
|
+
if (!sample)
|
|
43
|
+
return false;
|
|
44
|
+
const unicodeTerm = firstUnicodeTerm(sample.body) ?? firstUnicodeTerm(sample.tags);
|
|
45
|
+
const trigramTerm = firstTrigramTerm(sample.body) ?? firstTrigramTerm(sample.tags);
|
|
46
|
+
if (!unicodeTerm && !trigramTerm)
|
|
47
|
+
return false;
|
|
48
|
+
const unicodeHealthy = unicodeTerm ? ftsHasSampleHit(db, 'memory_fts', unicodeTerm) : true;
|
|
49
|
+
const trigramHealthy = trigramTerm ? ftsHasSampleHit(db, 'memory_fts_trigram', trigramTerm) : true;
|
|
50
|
+
return !(unicodeHealthy && trigramHealthy);
|
|
51
|
+
};
|
|
52
|
+
export const applySchemaVersion27 = (db, options = {}) => {
|
|
53
|
+
ensureFtsRowidColumn(db);
|
|
54
|
+
const memoryFtsExists = tableExists(db, 'memory_fts');
|
|
55
|
+
const memoryFtsTrigramExists = tableExists(db, 'memory_fts_trigram');
|
|
56
|
+
db.exec(`
|
|
57
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts
|
|
58
|
+
USING fts5(body, tags, content='memory_entries', content_rowid='fts_rowid', tokenize='unicode61');
|
|
59
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts_trigram
|
|
60
|
+
USING fts5(body, tags, content='memory_entries', content_rowid='fts_rowid', tokenize='trigram');
|
|
61
|
+
|
|
62
|
+
CREATE TRIGGER IF NOT EXISTS memory_fts_ai AFTER INSERT ON memory_entries BEGIN
|
|
63
|
+
INSERT INTO memory_fts(rowid, body, tags) VALUES (new.fts_rowid, new.body, new.tags);
|
|
64
|
+
INSERT INTO memory_fts_trigram(rowid, body, tags)
|
|
65
|
+
VALUES (new.fts_rowid, new.body, new.tags);
|
|
66
|
+
END;
|
|
67
|
+
CREATE TRIGGER IF NOT EXISTS memory_fts_ad AFTER DELETE ON memory_entries BEGIN
|
|
68
|
+
INSERT INTO memory_fts(memory_fts, rowid, body, tags)
|
|
69
|
+
VALUES('delete', old.fts_rowid, old.body, old.tags);
|
|
70
|
+
INSERT INTO memory_fts_trigram(memory_fts_trigram, rowid, body, tags)
|
|
71
|
+
VALUES('delete', old.fts_rowid, old.body, old.tags);
|
|
72
|
+
END;
|
|
73
|
+
CREATE TRIGGER IF NOT EXISTS memory_fts_au AFTER UPDATE ON memory_entries BEGIN
|
|
74
|
+
INSERT INTO memory_fts(memory_fts, rowid, body, tags)
|
|
75
|
+
VALUES('delete', old.fts_rowid, old.body, old.tags);
|
|
76
|
+
INSERT INTO memory_fts(rowid, body, tags) VALUES (new.fts_rowid, new.body, new.tags);
|
|
77
|
+
INSERT INTO memory_fts_trigram(memory_fts_trigram, rowid, body, tags)
|
|
78
|
+
VALUES('delete', old.fts_rowid, old.body, old.tags);
|
|
79
|
+
INSERT INTO memory_fts_trigram(rowid, body, tags)
|
|
80
|
+
VALUES (new.fts_rowid, new.body, new.tags);
|
|
81
|
+
END;
|
|
82
|
+
`);
|
|
83
|
+
if (options.rebuild === true ||
|
|
84
|
+
!memoryFtsExists ||
|
|
85
|
+
!memoryFtsTrigramExists ||
|
|
86
|
+
shouldRebuildExistingIndex(db)) {
|
|
87
|
+
db.exec(`
|
|
88
|
+
INSERT INTO memory_fts(memory_fts) VALUES('rebuild');
|
|
89
|
+
INSERT INTO memory_fts_trigram(memory_fts_trigram) VALUES('rebuild');
|
|
90
|
+
`);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const applySchemaVersion28 = (db) => {
|
|
2
|
+
db.exec(`
|
|
3
|
+
CREATE TABLE IF NOT EXISTS dream_runs (
|
|
4
|
+
id TEXT PRIMARY KEY,
|
|
5
|
+
workspace_id TEXT NOT NULL,
|
|
6
|
+
trigger TEXT NOT NULL,
|
|
7
|
+
status TEXT NOT NULL,
|
|
8
|
+
started_at INTEGER NOT NULL,
|
|
9
|
+
finished_at INTEGER,
|
|
10
|
+
input_seq_from INTEGER,
|
|
11
|
+
input_seq_to INTEGER,
|
|
12
|
+
report TEXT,
|
|
13
|
+
revert_blob TEXT,
|
|
14
|
+
error TEXT
|
|
15
|
+
);
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_dream_runs_ws
|
|
17
|
+
ON dream_runs(workspace_id, started_at);
|
|
18
|
+
`);
|
|
19
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const QWEN_SESSION_ID_CAPTURE = {
|
|
2
|
+
pattern: '~/.qwen/sessions/**/*.json',
|
|
3
|
+
source: 'qwen_session_json_dir',
|
|
4
|
+
};
|
|
5
|
+
const QWEN_YOLO_ARGS = ['--approval-mode', 'yolo'];
|
|
6
|
+
export const applySchemaVersion29 = (db) => {
|
|
7
|
+
const hasCommandPresets = db
|
|
8
|
+
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'command_presets'")
|
|
9
|
+
.get();
|
|
10
|
+
if (!hasCommandPresets)
|
|
11
|
+
return;
|
|
12
|
+
const now = Date.now();
|
|
13
|
+
db.prepare(`INSERT INTO command_presets (
|
|
14
|
+
id, display_name, command, args, env, resume_args_template, session_id_capture,
|
|
15
|
+
yolo_args_template, is_builtin, created_at, updated_at
|
|
16
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
|
17
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
18
|
+
display_name = excluded.display_name,
|
|
19
|
+
command = excluded.command,
|
|
20
|
+
args = excluded.args,
|
|
21
|
+
env = excluded.env,
|
|
22
|
+
resume_args_template = excluded.resume_args_template,
|
|
23
|
+
session_id_capture = excluded.session_id_capture,
|
|
24
|
+
yolo_args_template = excluded.yolo_args_template,
|
|
25
|
+
updated_at = excluded.updated_at
|
|
26
|
+
WHERE command_presets.is_builtin = 1`).run('qwen', 'Qwen Code', 'qwen', '[]', '{}', '--resume {session_id}', JSON.stringify(QWEN_SESSION_ID_CAPTURE), JSON.stringify(QWEN_YOLO_ARGS), now, now);
|
|
27
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const AGY_SESSION_ID_CAPTURE = {
|
|
2
|
+
pattern: String.raw `(?:^|\s)(?:\S*[\\/])?agy(?:\.(?:cmd|exe))?\s+--conversation\s+([0-9a-fA-F-]{36})\b`,
|
|
3
|
+
source: 'stdout_regex',
|
|
4
|
+
};
|
|
5
|
+
const AGY_YOLO_ARGS = ['--dangerously-skip-permissions'];
|
|
6
|
+
export const applySchemaVersion30 = (db) => {
|
|
7
|
+
const hasCommandPresets = db
|
|
8
|
+
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'command_presets'")
|
|
9
|
+
.get();
|
|
10
|
+
if (!hasCommandPresets)
|
|
11
|
+
return;
|
|
12
|
+
const now = Date.now();
|
|
13
|
+
db.prepare(`INSERT INTO command_presets (
|
|
14
|
+
id, display_name, command, args, env, resume_args_template, session_id_capture,
|
|
15
|
+
yolo_args_template, is_builtin, created_at, updated_at
|
|
16
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
|
17
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
18
|
+
display_name = excluded.display_name,
|
|
19
|
+
command = excluded.command,
|
|
20
|
+
args = excluded.args,
|
|
21
|
+
env = excluded.env,
|
|
22
|
+
resume_args_template = excluded.resume_args_template,
|
|
23
|
+
session_id_capture = excluded.session_id_capture,
|
|
24
|
+
yolo_args_template = excluded.yolo_args_template,
|
|
25
|
+
updated_at = excluded.updated_at
|
|
26
|
+
WHERE command_presets.is_builtin = 1`).run('agy', 'Antigravity CLI', 'agy', '[]', '{}', '--conversation {session_id}', JSON.stringify(AGY_SESSION_ID_CAPTURE), JSON.stringify(AGY_YOLO_ARGS), now, now);
|
|
27
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getBuiltinCommandPreset } from './command-preset-defaults.js';
|
|
2
|
+
const upsertBuiltinCommandPreset = (db, id, now) => {
|
|
3
|
+
const preset = getBuiltinCommandPreset(id);
|
|
4
|
+
if (!preset)
|
|
5
|
+
return;
|
|
6
|
+
db.prepare(`INSERT INTO command_presets (
|
|
7
|
+
id, display_name, command, args, env, resume_args_template, session_id_capture,
|
|
8
|
+
yolo_args_template, is_builtin, created_at, updated_at
|
|
9
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
|
10
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
11
|
+
display_name = excluded.display_name,
|
|
12
|
+
command = excluded.command,
|
|
13
|
+
args = excluded.args,
|
|
14
|
+
env = excluded.env,
|
|
15
|
+
resume_args_template = excluded.resume_args_template,
|
|
16
|
+
session_id_capture = excluded.session_id_capture,
|
|
17
|
+
yolo_args_template = excluded.yolo_args_template,
|
|
18
|
+
updated_at = excluded.updated_at
|
|
19
|
+
WHERE command_presets.is_builtin = 1`).run(preset.id, preset.displayName, preset.command, '[]', '{}', preset.resumeArgsTemplate, preset.sessionIdCapture ? JSON.stringify(preset.sessionIdCapture) : null, preset.yoloArgsTemplate ? JSON.stringify(preset.yoloArgsTemplate) : null, now, now);
|
|
20
|
+
};
|
|
21
|
+
export const applySchemaVersion31 = (db) => {
|
|
22
|
+
const hasCommandPresets = db
|
|
23
|
+
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'command_presets'")
|
|
24
|
+
.get();
|
|
25
|
+
if (!hasCommandPresets)
|
|
26
|
+
return;
|
|
27
|
+
const now = Date.now();
|
|
28
|
+
upsertBuiltinCommandPreset(db, 'cursor', now);
|
|
29
|
+
upsertBuiltinCommandPreset(db, 'grok', now);
|
|
30
|
+
};
|
|
@@ -15,7 +15,16 @@ import { applySchemaVersion19 } from './sqlite-schema-v19.js';
|
|
|
15
15
|
import { applySchemaVersion20 } from './sqlite-schema-v20.js';
|
|
16
16
|
import { applySchemaVersion21 } from './sqlite-schema-v21.js';
|
|
17
17
|
import { applySchemaVersion22 } from './sqlite-schema-v22.js';
|
|
18
|
-
|
|
18
|
+
import { applySchemaVersion23 } from './sqlite-schema-v23.js';
|
|
19
|
+
import { applySchemaVersion24 } from './sqlite-schema-v24.js';
|
|
20
|
+
import { applySchemaVersion25 } from './sqlite-schema-v25.js';
|
|
21
|
+
import { applySchemaVersion26 } from './sqlite-schema-v26.js';
|
|
22
|
+
import { applySchemaVersion27 } from './sqlite-schema-v27.js';
|
|
23
|
+
import { applySchemaVersion28 } from './sqlite-schema-v28.js';
|
|
24
|
+
import { applySchemaVersion29 } from './sqlite-schema-v29.js';
|
|
25
|
+
import { applySchemaVersion30 } from './sqlite-schema-v30.js';
|
|
26
|
+
import { applySchemaVersion31 } from './sqlite-schema-v31.js';
|
|
27
|
+
export const CURRENT_SCHEMA_VERSION = 31;
|
|
19
28
|
// Idempotent column-add helper. SQLite doesn't have `ALTER TABLE … ADD COLUMN
|
|
20
29
|
// IF NOT EXISTS`, so PRAGMA-check first. Safe to call on every init; required
|
|
21
30
|
// for foreign-built DBs where the version-gated migration is skipped.
|
|
@@ -317,4 +326,43 @@ export const initializeRuntimeDatabase = (db) => {
|
|
|
317
326
|
applySchemaVersion22(db);
|
|
318
327
|
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(22, Date.now());
|
|
319
328
|
}
|
|
329
|
+
if (!appliedVersions.has(23)) {
|
|
330
|
+
applySchemaVersion23(db);
|
|
331
|
+
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(23, Date.now());
|
|
332
|
+
}
|
|
333
|
+
if (!appliedVersions.has(24)) {
|
|
334
|
+
applySchemaVersion24(db);
|
|
335
|
+
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(24, Date.now());
|
|
336
|
+
}
|
|
337
|
+
applySchemaVersion25(db);
|
|
338
|
+
if (!appliedVersions.has(25)) {
|
|
339
|
+
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(25, Date.now());
|
|
340
|
+
}
|
|
341
|
+
applySchemaVersion26(db);
|
|
342
|
+
if (!appliedVersions.has(26)) {
|
|
343
|
+
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(26, Date.now());
|
|
344
|
+
}
|
|
345
|
+
if (!appliedVersions.has(27)) {
|
|
346
|
+
applySchemaVersion27(db, { rebuild: true });
|
|
347
|
+
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(27, Date.now());
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
applySchemaVersion27(db, { rebuild: false });
|
|
351
|
+
}
|
|
352
|
+
applySchemaVersion28(db);
|
|
353
|
+
if (!appliedVersions.has(28)) {
|
|
354
|
+
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(28, Date.now());
|
|
355
|
+
}
|
|
356
|
+
applySchemaVersion29(db);
|
|
357
|
+
if (!appliedVersions.has(29)) {
|
|
358
|
+
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(29, Date.now());
|
|
359
|
+
}
|
|
360
|
+
applySchemaVersion30(db);
|
|
361
|
+
if (!appliedVersions.has(30)) {
|
|
362
|
+
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(30, Date.now());
|
|
363
|
+
}
|
|
364
|
+
applySchemaVersion31(db);
|
|
365
|
+
if (!appliedVersions.has(31)) {
|
|
366
|
+
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(31, Date.now());
|
|
367
|
+
}
|
|
320
368
|
};
|
|
@@ -2,7 +2,11 @@ import { basename } from 'node:path';
|
|
|
2
2
|
const getEnvValue = (env, key, platform = process.platform) => {
|
|
3
3
|
if (platform !== 'win32')
|
|
4
4
|
return env[key];
|
|
5
|
-
|
|
5
|
+
if (Object.hasOwn(env, key))
|
|
6
|
+
return env[key];
|
|
7
|
+
const matchedKey = Object.keys(env)
|
|
8
|
+
.filter((item) => item.toLowerCase() === key.toLowerCase())
|
|
9
|
+
.at(-1);
|
|
6
10
|
return matchedKey ? env[matchedKey] : undefined;
|
|
7
11
|
};
|
|
8
12
|
const createPosixShellArgs = (shell, command) => {
|
|
@@ -27,6 +27,8 @@ import type { WorkflowCliPolicy } from './workflow-cli-policy.js';
|
|
|
27
27
|
*/
|
|
28
28
|
export declare const TASKS_WATCHER_OPTIONS: ChokidarOptions;
|
|
29
29
|
export declare const buildTasksWatcherOptions: (workspacePath: string, platform?: NodeJS.Platform) => ChokidarOptions;
|
|
30
|
+
export declare const getTasksWatcherReadyTimeoutMs: (workspacePath: string, platform?: NodeJS.Platform) => number;
|
|
31
|
+
export declare const isTasksFileEvent: (tasksPath: string, changedPath: string | Buffer | undefined, platform?: NodeJS.Platform) => boolean;
|
|
30
32
|
export interface TasksFileWatcher {
|
|
31
33
|
close: () => Promise<void>;
|
|
32
34
|
start: (workspaceId: string, workspacePath: string) => Promise<void>;
|
|
@@ -7,7 +7,8 @@ import { ensureProtocolFile, ensureTasksFile, getTasksFilePath, TASKS_FILE_NAME,
|
|
|
7
7
|
const DEBOUNCE_MS = 100;
|
|
8
8
|
const WATCHER_RETRY_MS = 5000;
|
|
9
9
|
const WATCHER_CLOSE_TIMEOUT_MS = 2000;
|
|
10
|
-
const
|
|
10
|
+
const DEFAULT_WATCHER_READY_TIMEOUT_MS = 15000;
|
|
11
|
+
const WINDOWS_WATCHER_READY_TIMEOUT_MS = 60000;
|
|
11
12
|
/**
|
|
12
13
|
* Watcher configuration. The atomic-save option matters on Windows: VS
|
|
13
14
|
* Code, Cursor, Notepad++, and the editor inside Hive itself all save
|
|
@@ -43,6 +44,9 @@ export const buildTasksWatcherOptions = (workspacePath, platform = process.platf
|
|
|
43
44
|
? { interval: 500, usePolling: true }
|
|
44
45
|
: {}),
|
|
45
46
|
});
|
|
47
|
+
export const getTasksWatcherReadyTimeoutMs = (workspacePath, platform = process.platform) => platform === 'win32' || isWindowsUncPath(workspacePath, platform)
|
|
48
|
+
? WINDOWS_WATCHER_READY_TIMEOUT_MS
|
|
49
|
+
: DEFAULT_WATCHER_READY_TIMEOUT_MS;
|
|
46
50
|
const closeWatcherWithTimeout = async (watcher) => {
|
|
47
51
|
if (!watcher)
|
|
48
52
|
return;
|
|
@@ -61,10 +65,14 @@ const closeWatcherWithTimeout = async (watcher) => {
|
|
|
61
65
|
clearTimeout(timer);
|
|
62
66
|
}
|
|
63
67
|
};
|
|
64
|
-
const isTasksFileEvent = (tasksPath, changedPath) => {
|
|
68
|
+
export const isTasksFileEvent = (tasksPath, changedPath, platform = process.platform) => {
|
|
65
69
|
if (!changedPath)
|
|
66
70
|
return true;
|
|
67
71
|
const text = Buffer.isBuffer(changedPath) ? changedPath.toString() : changedPath;
|
|
72
|
+
if (platform === 'win32') {
|
|
73
|
+
return (normalize(text).toLowerCase() === normalize(tasksPath).toLowerCase() ||
|
|
74
|
+
basename(text).toLowerCase() === TASKS_FILE_NAME);
|
|
75
|
+
}
|
|
68
76
|
return normalize(text) === normalize(tasksPath) || basename(text) === TASKS_FILE_NAME;
|
|
69
77
|
};
|
|
70
78
|
export const createTasksFileWatcher = ({ onTasksUpdated, getWorkflowCliPolicy, getFlags, }) => {
|
|
@@ -120,7 +128,7 @@ export const createTasksFileWatcher = ({ onTasksUpdated, getWorkflowCliPolicy, g
|
|
|
120
128
|
timer.unref?.();
|
|
121
129
|
retryTimers.set(workspaceId, timer);
|
|
122
130
|
};
|
|
123
|
-
const waitForReady = async (watcher) => await new Promise((resolve, reject) => {
|
|
131
|
+
const waitForReady = async (watcher, timeoutMs) => await new Promise((resolve, reject) => {
|
|
124
132
|
const cleanup = () => {
|
|
125
133
|
watcher.off('ready', handleReady);
|
|
126
134
|
watcher.off('error', handleError);
|
|
@@ -136,8 +144,8 @@ export const createTasksFileWatcher = ({ onTasksUpdated, getWorkflowCliPolicy, g
|
|
|
136
144
|
};
|
|
137
145
|
const timeout = setTimeout(() => {
|
|
138
146
|
cleanup();
|
|
139
|
-
reject(new Error(`Timed out waiting for tasks watcher ready after ${
|
|
140
|
-
},
|
|
147
|
+
reject(new Error(`Timed out waiting for tasks watcher ready after ${timeoutMs}ms`));
|
|
148
|
+
}, timeoutMs);
|
|
141
149
|
timeout.unref?.();
|
|
142
150
|
watcher.once('ready', handleReady);
|
|
143
151
|
watcher.once('error', handleError);
|
|
@@ -149,6 +157,7 @@ export const createTasksFileWatcher = ({ onTasksUpdated, getWorkflowCliPolicy, g
|
|
|
149
157
|
ensureProtocolFile(workspacePath, getWorkflowCliPolicy?.(), getFlags?.() ?? FEATURE_FLAGS_ALL_OFF);
|
|
150
158
|
const tasksPath = getTasksFilePath(workspacePath);
|
|
151
159
|
const watcher = chokidar.watch(dirname(tasksPath), buildTasksWatcherOptions(workspacePath));
|
|
160
|
+
const readyTimeoutMs = getTasksWatcherReadyTimeoutMs(workspacePath);
|
|
152
161
|
const scheduleEmit = (changedPath) => {
|
|
153
162
|
if (!isTasksFileEvent(tasksPath, changedPath))
|
|
154
163
|
return;
|
|
@@ -169,7 +178,7 @@ export const createTasksFileWatcher = ({ onTasksUpdated, getWorkflowCliPolicy, g
|
|
|
169
178
|
});
|
|
170
179
|
watchers.set(workspaceId, watcher);
|
|
171
180
|
try {
|
|
172
|
-
await waitForReady(watcher);
|
|
181
|
+
await waitForReady(watcher, readyTimeoutMs);
|
|
173
182
|
}
|
|
174
183
|
catch (error) {
|
|
175
184
|
watchers.delete(workspaceId);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, writeFileSync, } from 'node:fs';
|
|
3
|
+
import { basename, dirname, join } from 'node:path';
|
|
3
4
|
import { FEATURE_FLAGS_ALL_OFF } from './feature-flags.js';
|
|
4
5
|
import { buildProtocolDoc } from './hive-team-guidance.js';
|
|
5
6
|
export const HIVE_DIR_NAME = '.hive';
|
|
@@ -32,6 +33,30 @@ const runRetryableTasksFileOperation = (operation) => {
|
|
|
32
33
|
const ensureTasksDir = (workspacePath) => {
|
|
33
34
|
runRetryableTasksFileOperation(() => mkdirSync(dirname(getTasksFilePath(workspacePath)), { recursive: true }));
|
|
34
35
|
};
|
|
36
|
+
const writeUtf8FileAtomically = (targetPath, content) => {
|
|
37
|
+
const tempPath = join(dirname(targetPath), `.${basename(targetPath)}.${randomUUID()}.tmp`);
|
|
38
|
+
let committed = false;
|
|
39
|
+
let fd = null;
|
|
40
|
+
try {
|
|
41
|
+
try {
|
|
42
|
+
fd = openSync(tempPath, 'w');
|
|
43
|
+
writeFileSync(fd, content, 'utf8');
|
|
44
|
+
fsyncSync(fd);
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
if (fd !== null) {
|
|
48
|
+
closeSync(fd);
|
|
49
|
+
fd = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
renameSync(tempPath, targetPath);
|
|
53
|
+
committed = true;
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
if (!committed && existsSync(tempPath))
|
|
57
|
+
rmSync(tempPath, { force: true });
|
|
58
|
+
}
|
|
59
|
+
};
|
|
35
60
|
export const ensureTasksFile = (workspacePath) => {
|
|
36
61
|
ensureTasksDir(workspacePath);
|
|
37
62
|
const tasksFilePath = getTasksFilePath(workspacePath);
|
|
@@ -42,7 +67,7 @@ export const ensureTasksFile = (workspacePath) => {
|
|
|
42
67
|
const content = existsSync(legacyTasksFilePath)
|
|
43
68
|
? runRetryableTasksFileOperation(() => readFileSync(legacyTasksFilePath, 'utf8'))
|
|
44
69
|
: '';
|
|
45
|
-
runRetryableTasksFileOperation(() =>
|
|
70
|
+
runRetryableTasksFileOperation(() => writeUtf8FileAtomically(tasksFilePath, content));
|
|
46
71
|
return content;
|
|
47
72
|
};
|
|
48
73
|
/**
|
|
@@ -60,7 +85,7 @@ export const ensureProtocolFile = (workspacePath, cliPolicy, flags = FEATURE_FLA
|
|
|
60
85
|
: null;
|
|
61
86
|
if (current === desired)
|
|
62
87
|
return desired;
|
|
63
|
-
runRetryableTasksFileOperation(() =>
|
|
88
|
+
runRetryableTasksFileOperation(() => writeUtf8FileAtomically(protocolFilePath, desired));
|
|
64
89
|
return desired;
|
|
65
90
|
};
|
|
66
91
|
export const createTasksFileService = () => {
|
|
@@ -70,7 +95,7 @@ export const createTasksFileService = () => {
|
|
|
70
95
|
},
|
|
71
96
|
writeTasks(workspacePath, content) {
|
|
72
97
|
ensureTasksDir(workspacePath);
|
|
73
|
-
runRetryableTasksFileOperation(() =>
|
|
98
|
+
runRetryableTasksFileOperation(() => writeUtf8FileAtomically(getTasksFilePath(workspacePath), content));
|
|
74
99
|
},
|
|
75
100
|
};
|
|
76
101
|
};
|
|
@@ -12,6 +12,10 @@ export const createTasksWebSocketServer = (server, store, tasksFileService) => {
|
|
|
12
12
|
attachWebSocketServerErrorHandler(wss, 'tasks');
|
|
13
13
|
const socketsByWorkspaceId = new Map();
|
|
14
14
|
const validateUpgradeSession = (request) => {
|
|
15
|
+
// Tunnel-originated upgrades carry the per-boot secret (invariant 2); a
|
|
16
|
+
// request with no secret header falls through to the unchanged cookie path.
|
|
17
|
+
if (store.authorizeRemoteTunnelRequest(request))
|
|
18
|
+
return true;
|
|
15
19
|
const cookieHeader = Array.isArray(request.headers.cookie)
|
|
16
20
|
? request.headers.cookie.join('; ')
|
|
17
21
|
: request.headers.cookie;
|