@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,153 @@
|
|
|
1
|
+
import { DREAM_MEMORY_BODY_MAX_CHARS, DREAM_MEMORY_MAX_ADDS_PER_RUN, isMemoryKind, MEMORY_TAG_MAX_CHARS, MEMORY_TAG_MAX_COUNT, } from '../shared/team-memory.js';
|
|
2
|
+
export class DreamRunValidationError extends Error {
|
|
3
|
+
code = 'dream_validation_failed';
|
|
4
|
+
}
|
|
5
|
+
const asRecord = (value) => {
|
|
6
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
7
|
+
throw new DreamRunValidationError('Dream op must be an object');
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
};
|
|
11
|
+
const requiredString = (record, field) => {
|
|
12
|
+
const value = record[field];
|
|
13
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
14
|
+
throw new DreamRunValidationError(`Dream op field ${field} must be a non-empty string`);
|
|
15
|
+
}
|
|
16
|
+
return value.trim();
|
|
17
|
+
};
|
|
18
|
+
const optionalString = (record, field) => {
|
|
19
|
+
const value = record[field];
|
|
20
|
+
if (value === undefined || value === null)
|
|
21
|
+
return null;
|
|
22
|
+
if (typeof value !== 'string') {
|
|
23
|
+
throw new DreamRunValidationError(`Dream op field ${field} must be a string`);
|
|
24
|
+
}
|
|
25
|
+
return value.trim() || null;
|
|
26
|
+
};
|
|
27
|
+
const requiredBody = (record) => {
|
|
28
|
+
const body = requiredString(record, 'body');
|
|
29
|
+
if ([...body].length > DREAM_MEMORY_BODY_MAX_CHARS) {
|
|
30
|
+
throw new DreamRunValidationError(`Dream op body must be ${DREAM_MEMORY_BODY_MAX_CHARS} characters or fewer`);
|
|
31
|
+
}
|
|
32
|
+
return body;
|
|
33
|
+
};
|
|
34
|
+
const requiredKind = (record) => {
|
|
35
|
+
const kind = record.kind;
|
|
36
|
+
if (!isMemoryKind(kind))
|
|
37
|
+
throw new DreamRunValidationError('Dream op kind is invalid');
|
|
38
|
+
return kind;
|
|
39
|
+
};
|
|
40
|
+
const optionalKind = (record) => {
|
|
41
|
+
const kind = record.kind;
|
|
42
|
+
if (kind === undefined || kind === null)
|
|
43
|
+
return undefined;
|
|
44
|
+
if (!isMemoryKind(kind))
|
|
45
|
+
throw new DreamRunValidationError('Dream op kind is invalid');
|
|
46
|
+
return kind;
|
|
47
|
+
};
|
|
48
|
+
const optionalConfidence = (record) => {
|
|
49
|
+
const value = record.confidence;
|
|
50
|
+
if (value === undefined)
|
|
51
|
+
return undefined;
|
|
52
|
+
if (value === null)
|
|
53
|
+
return null;
|
|
54
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value < 0 || value > 1) {
|
|
55
|
+
throw new DreamRunValidationError('Dream op confidence must be between 0 and 1');
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
};
|
|
59
|
+
const optionalTags = (record) => {
|
|
60
|
+
const value = record.tags;
|
|
61
|
+
if (value === undefined || value === null)
|
|
62
|
+
return undefined;
|
|
63
|
+
if (!Array.isArray(value))
|
|
64
|
+
throw new DreamRunValidationError('Dream op tags must be an array');
|
|
65
|
+
if (value.length > MEMORY_TAG_MAX_COUNT) {
|
|
66
|
+
throw new DreamRunValidationError(`Dream op tags can include at most ${MEMORY_TAG_MAX_COUNT}`);
|
|
67
|
+
}
|
|
68
|
+
return value.map((tag) => {
|
|
69
|
+
if (typeof tag !== 'string' || !tag.trim()) {
|
|
70
|
+
throw new DreamRunValidationError('Dream op tags must be non-empty strings');
|
|
71
|
+
}
|
|
72
|
+
const trimmed = tag.trim();
|
|
73
|
+
if ([...trimmed].length > MEMORY_TAG_MAX_CHARS) {
|
|
74
|
+
throw new DreamRunValidationError(`Dream op tags must be ${MEMORY_TAG_MAX_CHARS} characters or fewer`);
|
|
75
|
+
}
|
|
76
|
+
return trimmed;
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
const optionalSourceSequences = (record) => {
|
|
80
|
+
const value = record.sources;
|
|
81
|
+
if (value === undefined || value === null)
|
|
82
|
+
return [];
|
|
83
|
+
if (!Array.isArray(value))
|
|
84
|
+
throw new DreamRunValidationError('Dream op sources must be an array');
|
|
85
|
+
return value.map((source) => {
|
|
86
|
+
const sourceRecord = asRecord(source);
|
|
87
|
+
const sequence = sourceRecord.sequence;
|
|
88
|
+
if (!Number.isInteger(sequence) || sequence <= 0) {
|
|
89
|
+
throw new DreamRunValidationError('Dream op source sequence must be a positive integer');
|
|
90
|
+
}
|
|
91
|
+
return sequence;
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
export const parseDreamOperations = (rawOps) => {
|
|
95
|
+
if (!Array.isArray(rawOps))
|
|
96
|
+
throw new DreamRunValidationError('Dream output ops must be an array');
|
|
97
|
+
const operations = rawOps.map((rawOp) => {
|
|
98
|
+
const record = asRecord(rawOp);
|
|
99
|
+
switch (record.op) {
|
|
100
|
+
case 'add':
|
|
101
|
+
return {
|
|
102
|
+
body: requiredBody(record),
|
|
103
|
+
confidence: optionalConfidence(record) ?? 0.5,
|
|
104
|
+
kind: requiredKind(record),
|
|
105
|
+
op: 'add',
|
|
106
|
+
sources: optionalSourceSequences(record),
|
|
107
|
+
tags: optionalTags(record) ?? [],
|
|
108
|
+
};
|
|
109
|
+
case 'archive':
|
|
110
|
+
return {
|
|
111
|
+
id: requiredString(record, 'id'),
|
|
112
|
+
op: 'archive',
|
|
113
|
+
reason: optionalString(record, 'reason'),
|
|
114
|
+
};
|
|
115
|
+
case 'merge': {
|
|
116
|
+
const from = record.from;
|
|
117
|
+
if (!Array.isArray(from) || from.length === 0) {
|
|
118
|
+
throw new DreamRunValidationError('Dream merge op must include from ids');
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
body: requiredBody(record),
|
|
122
|
+
confidence: optionalConfidence(record),
|
|
123
|
+
from: from.map((id) => {
|
|
124
|
+
if (typeof id !== 'string' || !id.trim()) {
|
|
125
|
+
throw new DreamRunValidationError('Dream merge from ids must be non-empty strings');
|
|
126
|
+
}
|
|
127
|
+
return id.trim();
|
|
128
|
+
}),
|
|
129
|
+
into: requiredString(record, 'into'),
|
|
130
|
+
kind: optionalKind(record),
|
|
131
|
+
op: 'merge',
|
|
132
|
+
tags: optionalTags(record),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
case 'rewrite':
|
|
136
|
+
return {
|
|
137
|
+
body: requiredBody(record),
|
|
138
|
+
confidence: optionalConfidence(record),
|
|
139
|
+
id: requiredString(record, 'id'),
|
|
140
|
+
kind: optionalKind(record),
|
|
141
|
+
op: 'rewrite',
|
|
142
|
+
tags: optionalTags(record),
|
|
143
|
+
};
|
|
144
|
+
default:
|
|
145
|
+
throw new DreamRunValidationError('Unsupported dream op');
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
const addCount = operations.filter((op) => op.op === 'add').length;
|
|
149
|
+
if (addCount > DREAM_MEMORY_MAX_ADDS_PER_RUN) {
|
|
150
|
+
throw new DreamRunValidationError(`Dream run can add at most ${DREAM_MEMORY_MAX_ADDS_PER_RUN} memories`);
|
|
151
|
+
}
|
|
152
|
+
return operations;
|
|
153
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
import { type DreamRunRecord, type DreamRunRow } from './team-memory-dream-types.js';
|
|
3
|
+
export declare class DreamRunNotFoundError extends Error {
|
|
4
|
+
readonly runId: string;
|
|
5
|
+
readonly workspaceId: string;
|
|
6
|
+
constructor(workspaceId: string, runId: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class DreamRunRevertDataError extends Error {
|
|
9
|
+
readonly runId: string;
|
|
10
|
+
readonly workspaceId: string;
|
|
11
|
+
constructor(workspaceId: string, runId: string, message: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class DreamRunRevertStatusError extends Error {
|
|
14
|
+
readonly actualStatus: DreamRunRow['status'];
|
|
15
|
+
readonly expectedStatus = "completed";
|
|
16
|
+
readonly runId: string;
|
|
17
|
+
readonly workspaceId: string;
|
|
18
|
+
constructor(workspaceId: string, runId: string, actualStatus: DreamRunRow['status']);
|
|
19
|
+
}
|
|
20
|
+
export declare const createDreamRunReverter: (db: Database) => {
|
|
21
|
+
revertRun: (workspaceId: string, runId: string) => DreamRunRecord;
|
|
22
|
+
};
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { isMemoryKind } from '../shared/team-memory.js';
|
|
2
|
+
import { toDreamRunRecord, } from './team-memory-dream-types.js';
|
|
3
|
+
const MEMORY_STATUSES = new Set(['active', 'candidate', 'archived', 'rejected']);
|
|
4
|
+
const MEMORY_SOURCES = new Set(['manual', 'dream']);
|
|
5
|
+
const MEMORY_SOURCE_TYPES = new Set(['manual', 'message', 'dispatch', 'report', 'dream']);
|
|
6
|
+
const isObject = (value) => typeof value === 'object' && value !== null;
|
|
7
|
+
const hasValidMemoryEntryShape = (value) => {
|
|
8
|
+
if (!isObject(value))
|
|
9
|
+
return false;
|
|
10
|
+
return ((typeof value.archived_at === 'number' || value.archived_at === null) &&
|
|
11
|
+
typeof value.id === 'string' &&
|
|
12
|
+
typeof value.body === 'string' &&
|
|
13
|
+
(typeof value.confidence === 'number' || value.confidence === null) &&
|
|
14
|
+
typeof value.created_at === 'number' &&
|
|
15
|
+
(value.disabled === 0 || value.disabled === 1) &&
|
|
16
|
+
typeof value.fts_rowid === 'number' &&
|
|
17
|
+
isMemoryKind(value.kind) &&
|
|
18
|
+
(typeof value.last_injected_at === 'number' || value.last_injected_at === null) &&
|
|
19
|
+
(value.pinned === 0 || value.pinned === 1) &&
|
|
20
|
+
value.scope === 'workspace' &&
|
|
21
|
+
typeof value.source === 'string' &&
|
|
22
|
+
MEMORY_SOURCES.has(value.source) &&
|
|
23
|
+
typeof value.status === 'string' &&
|
|
24
|
+
MEMORY_STATUSES.has(value.status) &&
|
|
25
|
+
(typeof value.tags === 'string' || value.tags === null) &&
|
|
26
|
+
typeof value.updated_at === 'number' &&
|
|
27
|
+
(typeof value.workspace_id === 'string' || value.workspace_id === null));
|
|
28
|
+
};
|
|
29
|
+
const hasValidMemorySourceShape = (value) => {
|
|
30
|
+
if (!isObject(value))
|
|
31
|
+
return false;
|
|
32
|
+
return ((typeof value.actor_agent_id_snapshot === 'string' || value.actor_agent_id_snapshot === null) &&
|
|
33
|
+
(typeof value.actor_name_snapshot === 'string' || value.actor_name_snapshot === null) &&
|
|
34
|
+
(typeof value.actor_role_snapshot === 'string' || value.actor_role_snapshot === null) &&
|
|
35
|
+
typeof value.id === 'string' &&
|
|
36
|
+
typeof value.memory_id === 'string' &&
|
|
37
|
+
(typeof value.excerpt === 'string' || value.excerpt === null) &&
|
|
38
|
+
(typeof value.source_id === 'string' || value.source_id === null) &&
|
|
39
|
+
(typeof value.source_sequence === 'number' || value.source_sequence === null) &&
|
|
40
|
+
typeof value.source_type === 'string' &&
|
|
41
|
+
MEMORY_SOURCE_TYPES.has(value.source_type) &&
|
|
42
|
+
(typeof value.text_hash === 'string' || value.text_hash === null) &&
|
|
43
|
+
typeof value.created_at === 'number');
|
|
44
|
+
};
|
|
45
|
+
const hasValidRevertBlobShape = (value) => {
|
|
46
|
+
if (!isObject(value))
|
|
47
|
+
return false;
|
|
48
|
+
if (!Array.isArray(value.added_entry_ids) ||
|
|
49
|
+
!value.added_entry_ids.every((id) => typeof id === 'string')) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (!Array.isArray(value.prior_entries))
|
|
53
|
+
return false;
|
|
54
|
+
return value.prior_entries.every((prior) => {
|
|
55
|
+
if (!isObject(prior))
|
|
56
|
+
return false;
|
|
57
|
+
if (!hasValidMemoryEntryShape(prior.entry))
|
|
58
|
+
return false;
|
|
59
|
+
return Array.isArray(prior.sources) && prior.sources.every(hasValidMemorySourceShape);
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
export class DreamRunNotFoundError extends Error {
|
|
63
|
+
runId;
|
|
64
|
+
workspaceId;
|
|
65
|
+
constructor(workspaceId, runId) {
|
|
66
|
+
super(`Dream run not found: ${runId}`);
|
|
67
|
+
this.name = 'DreamRunNotFoundError';
|
|
68
|
+
this.workspaceId = workspaceId;
|
|
69
|
+
this.runId = runId;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export class DreamRunRevertDataError extends Error {
|
|
73
|
+
runId;
|
|
74
|
+
workspaceId;
|
|
75
|
+
constructor(workspaceId, runId, message) {
|
|
76
|
+
super(message);
|
|
77
|
+
this.name = 'DreamRunRevertDataError';
|
|
78
|
+
this.workspaceId = workspaceId;
|
|
79
|
+
this.runId = runId;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export class DreamRunRevertStatusError extends Error {
|
|
83
|
+
actualStatus;
|
|
84
|
+
expectedStatus = 'completed';
|
|
85
|
+
runId;
|
|
86
|
+
workspaceId;
|
|
87
|
+
constructor(workspaceId, runId, actualStatus) {
|
|
88
|
+
super(`Dream run has status ${actualStatus}; expected completed`);
|
|
89
|
+
this.name = 'DreamRunRevertStatusError';
|
|
90
|
+
this.workspaceId = workspaceId;
|
|
91
|
+
this.runId = runId;
|
|
92
|
+
this.actualStatus = actualStatus;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export const createDreamRunReverter = (db) => {
|
|
96
|
+
const getRunRow = (workspaceId, runId) => db
|
|
97
|
+
.prepare(`SELECT *
|
|
98
|
+
FROM dream_runs
|
|
99
|
+
WHERE id = ?
|
|
100
|
+
AND workspace_id = ?
|
|
101
|
+
LIMIT 1`)
|
|
102
|
+
.get(runId, workspaceId);
|
|
103
|
+
const requireCompletedRun = (workspaceId, runId) => {
|
|
104
|
+
const row = getRunRow(workspaceId, runId);
|
|
105
|
+
if (!row)
|
|
106
|
+
throw new DreamRunNotFoundError(workspaceId, runId);
|
|
107
|
+
if (row.status !== 'completed') {
|
|
108
|
+
throw new DreamRunRevertStatusError(workspaceId, runId, row.status);
|
|
109
|
+
}
|
|
110
|
+
return row;
|
|
111
|
+
};
|
|
112
|
+
const assertPriorEntry = (workspaceId, runId, entry) => {
|
|
113
|
+
if (entry.scope !== 'workspace' || entry.workspace_id !== workspaceId) {
|
|
114
|
+
throw new DreamRunRevertDataError(workspaceId, runId, 'Dream revert entry is out of scope');
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const restoreSource = (workspaceId, runId, memoryId, source) => {
|
|
118
|
+
if (source.memory_id !== memoryId) {
|
|
119
|
+
throw new DreamRunRevertDataError(workspaceId, runId, 'Dream revert source is out of scope');
|
|
120
|
+
}
|
|
121
|
+
db.prepare(`INSERT INTO memory_sources (
|
|
122
|
+
id,
|
|
123
|
+
memory_id,
|
|
124
|
+
source_type,
|
|
125
|
+
source_id,
|
|
126
|
+
source_sequence,
|
|
127
|
+
excerpt,
|
|
128
|
+
text_hash,
|
|
129
|
+
actor_agent_id_snapshot,
|
|
130
|
+
actor_name_snapshot,
|
|
131
|
+
actor_role_snapshot,
|
|
132
|
+
created_at
|
|
133
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(source.id, source.memory_id, source.source_type, source.source_id, source.source_sequence, source.excerpt, source.text_hash, source.actor_agent_id_snapshot, source.actor_name_snapshot, source.actor_role_snapshot, source.created_at);
|
|
134
|
+
};
|
|
135
|
+
const restorePriorEntry = (workspaceId, runId, prior) => {
|
|
136
|
+
assertPriorEntry(workspaceId, runId, prior.entry);
|
|
137
|
+
const result = db
|
|
138
|
+
.prepare(`UPDATE memory_entries
|
|
139
|
+
SET workspace_id = ?,
|
|
140
|
+
scope = ?,
|
|
141
|
+
fts_rowid = ?,
|
|
142
|
+
kind = ?,
|
|
143
|
+
body = ?,
|
|
144
|
+
tags = ?,
|
|
145
|
+
status = ?,
|
|
146
|
+
source = ?,
|
|
147
|
+
confidence = ?,
|
|
148
|
+
pinned = ?,
|
|
149
|
+
disabled = ?,
|
|
150
|
+
created_at = ?,
|
|
151
|
+
updated_at = ?,
|
|
152
|
+
archived_at = ?,
|
|
153
|
+
last_injected_at = ?
|
|
154
|
+
WHERE id = ?
|
|
155
|
+
AND workspace_id = ?
|
|
156
|
+
AND scope = 'workspace'`)
|
|
157
|
+
.run(prior.entry.workspace_id, prior.entry.scope, prior.entry.fts_rowid, prior.entry.kind, prior.entry.body, prior.entry.tags, prior.entry.status, prior.entry.source, prior.entry.confidence, prior.entry.pinned, prior.entry.disabled, prior.entry.created_at, prior.entry.updated_at, prior.entry.archived_at, prior.entry.last_injected_at, prior.entry.id, workspaceId);
|
|
158
|
+
if (result.changes === 0) {
|
|
159
|
+
throw new DreamRunRevertDataError(workspaceId, runId, 'Dream revert prior entry is missing');
|
|
160
|
+
}
|
|
161
|
+
db.prepare('DELETE FROM memory_sources WHERE memory_id = ?').run(prior.entry.id);
|
|
162
|
+
for (const source of prior.sources)
|
|
163
|
+
restoreSource(workspaceId, runId, prior.entry.id, source);
|
|
164
|
+
};
|
|
165
|
+
const archiveAddedEntry = (workspaceId, runId, memoryId, now) => {
|
|
166
|
+
const result = db
|
|
167
|
+
.prepare(`UPDATE memory_entries
|
|
168
|
+
SET status = 'archived',
|
|
169
|
+
archived_at = COALESCE(archived_at, ?),
|
|
170
|
+
updated_at = ?
|
|
171
|
+
WHERE id = ?
|
|
172
|
+
AND workspace_id = ?
|
|
173
|
+
AND scope = 'workspace'
|
|
174
|
+
AND source = 'dream'`)
|
|
175
|
+
.run(now, now, memoryId, workspaceId);
|
|
176
|
+
if (result.changes === 0) {
|
|
177
|
+
throw new DreamRunRevertDataError(workspaceId, runId, 'Dream added entry is missing');
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
const parseCompletedRun = (workspaceId, runId, row) => {
|
|
181
|
+
try {
|
|
182
|
+
const run = toDreamRunRecord(row);
|
|
183
|
+
if (!run.revertBlob || !hasValidRevertBlobShape(run.revertBlob)) {
|
|
184
|
+
throw new DreamRunRevertDataError(workspaceId, runId, 'Dream run has no revert data');
|
|
185
|
+
}
|
|
186
|
+
return run;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
if (error instanceof DreamRunRevertDataError)
|
|
190
|
+
throw error;
|
|
191
|
+
throw new DreamRunRevertDataError(workspaceId, runId, 'Dream run revert data is invalid');
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
const revertRunTransaction = db.transaction((workspaceId, runId) => {
|
|
195
|
+
const run = parseCompletedRun(workspaceId, runId, requireCompletedRun(workspaceId, runId));
|
|
196
|
+
const now = Date.now();
|
|
197
|
+
for (const prior of run.revertBlob.prior_entries) {
|
|
198
|
+
restorePriorEntry(workspaceId, runId, prior);
|
|
199
|
+
}
|
|
200
|
+
for (const memoryId of run.revertBlob.added_entry_ids) {
|
|
201
|
+
archiveAddedEntry(workspaceId, runId, memoryId, now);
|
|
202
|
+
}
|
|
203
|
+
const result = db
|
|
204
|
+
.prepare(`UPDATE dream_runs
|
|
205
|
+
SET status = 'reverted',
|
|
206
|
+
finished_at = ?
|
|
207
|
+
WHERE id = ?
|
|
208
|
+
AND workspace_id = ?
|
|
209
|
+
AND status = 'completed'`)
|
|
210
|
+
.run(now, runId, workspaceId);
|
|
211
|
+
if (result.changes === 0) {
|
|
212
|
+
throw new DreamRunRevertStatusError(workspaceId, runId, run.status);
|
|
213
|
+
}
|
|
214
|
+
const reverted = getRunRow(workspaceId, runId);
|
|
215
|
+
if (!reverted)
|
|
216
|
+
throw new DreamRunNotFoundError(workspaceId, runId);
|
|
217
|
+
return toDreamRunRecord(reverted);
|
|
218
|
+
});
|
|
219
|
+
const revertRun = (workspaceId, runId) => revertRunTransaction(workspaceId, runId);
|
|
220
|
+
return { revertRun };
|
|
221
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
import { type DreamMessageInput, type DreamRunRecord, type DreamRunTrigger, type DreamScheduleState } from './team-memory-dream-types.js';
|
|
3
|
+
export declare const DREAM_RUNNING_STALE_MS: number;
|
|
4
|
+
export declare class DreamRunAlreadyRunningError extends Error {
|
|
5
|
+
readonly workspaceId: string;
|
|
6
|
+
constructor(workspaceId: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class DreamWorkspaceMissingError extends Error {
|
|
9
|
+
readonly workspaceId: string;
|
|
10
|
+
constructor(workspaceId: string);
|
|
11
|
+
}
|
|
12
|
+
export declare const createDreamRunStore: (db: Database) => {
|
|
13
|
+
createRun: (input: {
|
|
14
|
+
trigger: DreamRunTrigger;
|
|
15
|
+
workspaceId: string;
|
|
16
|
+
}) => DreamRunRecord;
|
|
17
|
+
deleteWorkspaceDreamRuns: (workspaceId: string) => void;
|
|
18
|
+
getScheduleState: (workspaceId: string) => DreamScheduleState;
|
|
19
|
+
getRun: (runId: string) => DreamRunRecord | undefined;
|
|
20
|
+
listInputMessages: (workspaceId: string, from: number | null, to: number | null) => DreamMessageInput[];
|
|
21
|
+
listRuns: (workspaceId: string, limit?: number) => DreamRunRecord[];
|
|
22
|
+
markFailed: (runId: string, error: string, fallback?: DreamRunRecord) => DreamRunRecord;
|
|
23
|
+
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { toDreamRunRecord, } from './team-memory-dream-types.js';
|
|
3
|
+
const DREAM_INPUT_MESSAGE_TYPES = "'user_input', 'send', 'report'";
|
|
4
|
+
export const DREAM_RUNNING_STALE_MS = 10 * 60 * 1000;
|
|
5
|
+
const DREAM_STALE_ERROR = 'Dream run exceeded the stale running window';
|
|
6
|
+
export class DreamRunAlreadyRunningError extends Error {
|
|
7
|
+
workspaceId;
|
|
8
|
+
constructor(workspaceId) {
|
|
9
|
+
super(`Dream run already running for workspace: ${workspaceId}`);
|
|
10
|
+
this.name = 'DreamRunAlreadyRunningError';
|
|
11
|
+
this.workspaceId = workspaceId;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class DreamWorkspaceMissingError extends Error {
|
|
15
|
+
workspaceId;
|
|
16
|
+
constructor(workspaceId) {
|
|
17
|
+
super(`Dream workspace not found: ${workspaceId}`);
|
|
18
|
+
this.name = 'DreamWorkspaceMissingError';
|
|
19
|
+
this.workspaceId = workspaceId;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export const createDreamRunStore = (db) => {
|
|
23
|
+
const requireWorkspace = (workspaceId) => {
|
|
24
|
+
const row = db.prepare('SELECT id FROM workspaces WHERE id = ? LIMIT 1').get(workspaceId);
|
|
25
|
+
if (!row)
|
|
26
|
+
throw new DreamWorkspaceMissingError(workspaceId);
|
|
27
|
+
};
|
|
28
|
+
const markStaleRunningRuns = (workspaceId) => {
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
db.prepare(`UPDATE dream_runs
|
|
31
|
+
SET status = 'failed',
|
|
32
|
+
finished_at = COALESCE(finished_at, ?),
|
|
33
|
+
error = COALESCE(error, ?)
|
|
34
|
+
WHERE workspace_id = ?
|
|
35
|
+
AND status = 'running'
|
|
36
|
+
AND started_at < ?`).run(now, DREAM_STALE_ERROR, workspaceId, now - DREAM_RUNNING_STALE_MS);
|
|
37
|
+
};
|
|
38
|
+
const hasRunningRun = (workspaceId) => db
|
|
39
|
+
.prepare(`SELECT COUNT(*) AS count
|
|
40
|
+
FROM dream_runs
|
|
41
|
+
WHERE workspace_id = ?
|
|
42
|
+
AND status = 'running'`)
|
|
43
|
+
.get(workspaceId).count > 0;
|
|
44
|
+
const getRun = (runId) => {
|
|
45
|
+
const row = db.prepare('SELECT * FROM dream_runs WHERE id = ? LIMIT 1').get(runId);
|
|
46
|
+
if (row?.status === 'running') {
|
|
47
|
+
markStaleRunningRuns(row.workspace_id);
|
|
48
|
+
const refreshed = db.prepare('SELECT * FROM dream_runs WHERE id = ? LIMIT 1').get(runId);
|
|
49
|
+
return refreshed ? toDreamRunRecord(refreshed) : undefined;
|
|
50
|
+
}
|
|
51
|
+
return row ? toDreamRunRecord(row) : undefined;
|
|
52
|
+
};
|
|
53
|
+
const listRuns = (workspaceId, limit = 20) => {
|
|
54
|
+
markStaleRunningRuns(workspaceId);
|
|
55
|
+
return db
|
|
56
|
+
.prepare(`SELECT
|
|
57
|
+
id,
|
|
58
|
+
workspace_id,
|
|
59
|
+
trigger,
|
|
60
|
+
status,
|
|
61
|
+
started_at,
|
|
62
|
+
finished_at,
|
|
63
|
+
input_seq_from,
|
|
64
|
+
input_seq_to,
|
|
65
|
+
report,
|
|
66
|
+
NULL AS revert_blob,
|
|
67
|
+
error
|
|
68
|
+
FROM dream_runs
|
|
69
|
+
WHERE workspace_id = ?
|
|
70
|
+
ORDER BY started_at DESC, id DESC
|
|
71
|
+
LIMIT ?`)
|
|
72
|
+
.all(workspaceId, limit).map(toDreamRunRecord);
|
|
73
|
+
};
|
|
74
|
+
const requireRun = (runId) => {
|
|
75
|
+
const run = getRun(runId);
|
|
76
|
+
if (!run)
|
|
77
|
+
throw new Error(`Dream run not found: ${runId}`);
|
|
78
|
+
return run;
|
|
79
|
+
};
|
|
80
|
+
// Manual and scheduled runs resume from the last *successfully consumed* window
|
|
81
|
+
// (completed or reverted). A failed run does not advance this watermark, so its window
|
|
82
|
+
// is retried on the next run rather than silently skipped.
|
|
83
|
+
const latestConsumedSeq = (workspaceId) => db
|
|
84
|
+
.prepare(`SELECT MAX(input_seq_to) AS last
|
|
85
|
+
FROM dream_runs
|
|
86
|
+
WHERE workspace_id = ?
|
|
87
|
+
AND status IN ('completed', 'reverted')`)
|
|
88
|
+
.get(workspaceId).last;
|
|
89
|
+
const inputWindow = (workspaceId) => {
|
|
90
|
+
const lastSeq = latestConsumedSeq(workspaceId) ?? 0;
|
|
91
|
+
return db
|
|
92
|
+
.prepare(`SELECT MIN(sequence) AS seq_from, MAX(sequence) AS seq_to
|
|
93
|
+
FROM messages
|
|
94
|
+
WHERE workspace_id = ?
|
|
95
|
+
AND sequence > ?
|
|
96
|
+
AND type IN (${DREAM_INPUT_MESSAGE_TYPES})`)
|
|
97
|
+
.get(workspaceId, lastSeq);
|
|
98
|
+
};
|
|
99
|
+
const getScheduleState = (workspaceId) => {
|
|
100
|
+
markStaleRunningRuns(workspaceId);
|
|
101
|
+
const lastSeq = latestConsumedSeq(workspaceId) ?? 0;
|
|
102
|
+
// Scheduled failures after the most recent success mark how many times the current
|
|
103
|
+
// (un-advanced) window has been retried — used to back the scheduler off.
|
|
104
|
+
const lastSuccessAt = db
|
|
105
|
+
.prepare(`SELECT MAX(started_at) AS at
|
|
106
|
+
FROM dream_runs
|
|
107
|
+
WHERE workspace_id = ?
|
|
108
|
+
AND status IN ('completed', 'reverted')`)
|
|
109
|
+
.get(workspaceId).at ?? 0;
|
|
110
|
+
const row = db
|
|
111
|
+
.prepare(`SELECT
|
|
112
|
+
COALESCE(SUM(CASE WHEN status = 'running' THEN 1 ELSE 0 END), 0) AS running_count,
|
|
113
|
+
COALESCE(
|
|
114
|
+
SUM(
|
|
115
|
+
CASE
|
|
116
|
+
WHEN trigger = 'scheduled' AND status = 'failed' AND started_at > ?
|
|
117
|
+
THEN 1 ELSE 0
|
|
118
|
+
END
|
|
119
|
+
),
|
|
120
|
+
0
|
|
121
|
+
) AS consecutive_scheduled_failures,
|
|
122
|
+
MAX(CASE WHEN trigger = 'scheduled' THEN started_at ELSE NULL END) AS last_scheduled_at,
|
|
123
|
+
(
|
|
124
|
+
SELECT COUNT(*)
|
|
125
|
+
FROM messages
|
|
126
|
+
WHERE workspace_id = ?
|
|
127
|
+
AND sequence > ?
|
|
128
|
+
AND type IN (${DREAM_INPUT_MESSAGE_TYPES})
|
|
129
|
+
) AS pending_message_count
|
|
130
|
+
FROM dream_runs
|
|
131
|
+
WHERE workspace_id = ?`)
|
|
132
|
+
.get(lastSuccessAt, workspaceId, lastSeq, workspaceId);
|
|
133
|
+
return {
|
|
134
|
+
consecutiveScheduledFailures: row.consecutive_scheduled_failures,
|
|
135
|
+
hasRunningRun: row.running_count > 0,
|
|
136
|
+
lastScheduledAt: row.last_scheduled_at,
|
|
137
|
+
pendingMessageCount: row.pending_message_count,
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
const createRun = (input) => {
|
|
141
|
+
requireWorkspace(input.workspaceId);
|
|
142
|
+
markStaleRunningRuns(input.workspaceId);
|
|
143
|
+
if (hasRunningRun(input.workspaceId))
|
|
144
|
+
throw new DreamRunAlreadyRunningError(input.workspaceId);
|
|
145
|
+
const id = randomUUID();
|
|
146
|
+
const now = Date.now();
|
|
147
|
+
const window = inputWindow(input.workspaceId);
|
|
148
|
+
db.prepare(`INSERT INTO dream_runs (
|
|
149
|
+
id,
|
|
150
|
+
workspace_id,
|
|
151
|
+
trigger,
|
|
152
|
+
status,
|
|
153
|
+
started_at,
|
|
154
|
+
finished_at,
|
|
155
|
+
input_seq_from,
|
|
156
|
+
input_seq_to,
|
|
157
|
+
report,
|
|
158
|
+
revert_blob,
|
|
159
|
+
error
|
|
160
|
+
) VALUES (?, ?, ?, 'running', ?, NULL, ?, ?, NULL, NULL, NULL)`).run(id, input.workspaceId, input.trigger, now, window.seq_from, window.seq_to);
|
|
161
|
+
return requireRun(id);
|
|
162
|
+
};
|
|
163
|
+
const markFailed = (runId, error, fallback) => {
|
|
164
|
+
const finishedAt = Date.now();
|
|
165
|
+
db.prepare(`UPDATE dream_runs
|
|
166
|
+
SET status = 'failed',
|
|
167
|
+
finished_at = ?,
|
|
168
|
+
error = ?
|
|
169
|
+
WHERE id = ?
|
|
170
|
+
AND status = 'running'`).run(finishedAt, error, runId);
|
|
171
|
+
const run = getRun(runId);
|
|
172
|
+
if (run)
|
|
173
|
+
return run;
|
|
174
|
+
if (fallback)
|
|
175
|
+
return { ...fallback, error, finishedAt, status: 'failed' };
|
|
176
|
+
throw new Error(`Dream run not found: ${runId}`);
|
|
177
|
+
};
|
|
178
|
+
const listInputMessages = (workspaceId, from, to) => {
|
|
179
|
+
if (from === null || to === null)
|
|
180
|
+
return [];
|
|
181
|
+
return db
|
|
182
|
+
.prepare(`SELECT
|
|
183
|
+
sequence,
|
|
184
|
+
worker_id AS workerId,
|
|
185
|
+
type,
|
|
186
|
+
from_agent_id AS fromAgentId,
|
|
187
|
+
to_agent_id AS toAgentId,
|
|
188
|
+
text,
|
|
189
|
+
status,
|
|
190
|
+
artifacts,
|
|
191
|
+
created_at AS createdAt
|
|
192
|
+
FROM messages
|
|
193
|
+
WHERE workspace_id = ?
|
|
194
|
+
AND sequence BETWEEN ? AND ?
|
|
195
|
+
AND type IN (${DREAM_INPUT_MESSAGE_TYPES})
|
|
196
|
+
ORDER BY sequence ASC`)
|
|
197
|
+
.all(workspaceId, from, to);
|
|
198
|
+
};
|
|
199
|
+
const deleteWorkspaceDreamRuns = (workspaceId) => {
|
|
200
|
+
db.prepare('DELETE FROM dream_runs WHERE workspace_id = ?').run(workspaceId);
|
|
201
|
+
};
|
|
202
|
+
return {
|
|
203
|
+
createRun,
|
|
204
|
+
deleteWorkspaceDreamRuns,
|
|
205
|
+
getScheduleState,
|
|
206
|
+
getRun,
|
|
207
|
+
listInputMessages,
|
|
208
|
+
listRuns,
|
|
209
|
+
markFailed,
|
|
210
|
+
};
|
|
211
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { DreamMessageInput, DreamRunRecord, DreamRunTrigger } from './team-memory-dream-store.js';
|
|
2
|
+
import type { MemoryEntryWithSources } from './team-memory-store.js';
|
|
3
|
+
interface DreamStorePort {
|
|
4
|
+
applyAndCompleteRun: (workspaceId: string, runId: string, rawOps: unknown) => DreamRunRecord;
|
|
5
|
+
createRun: (input: {
|
|
6
|
+
trigger: DreamRunTrigger;
|
|
7
|
+
workspaceId: string;
|
|
8
|
+
}) => DreamRunRecord;
|
|
9
|
+
listInputMessages: (workspaceId: string, from: number | null, to: number | null) => DreamMessageInput[];
|
|
10
|
+
markFailed: (runId: string, error: string, fallback?: DreamRunRecord | undefined) => DreamRunRecord;
|
|
11
|
+
}
|
|
12
|
+
interface MemoryStorePort {
|
|
13
|
+
listAllEntries: (workspaceId: string) => MemoryEntryWithSources[];
|
|
14
|
+
}
|
|
15
|
+
interface DreamCliCommand {
|
|
16
|
+
args: string[];
|
|
17
|
+
command: string;
|
|
18
|
+
}
|
|
19
|
+
export interface TeamMemoryDreamRunner {
|
|
20
|
+
runManual: (workspaceId: string) => Promise<DreamRunRecord>;
|
|
21
|
+
runScheduled: (workspaceId: string) => Promise<DreamRunRecord>;
|
|
22
|
+
}
|
|
23
|
+
export declare const defaultDreamCliCommand: () => DreamCliCommand;
|
|
24
|
+
export declare const dreamCliCommandForLaunchCommand: (command: string) => DreamCliCommand;
|
|
25
|
+
export declare const buildDreamPrompt: (input: {
|
|
26
|
+
memories: MemoryEntryWithSources[];
|
|
27
|
+
messages: DreamMessageInput[];
|
|
28
|
+
workspaceId: string;
|
|
29
|
+
}) => string;
|
|
30
|
+
export declare const createTeamMemoryDreamRunner: (deps: {
|
|
31
|
+
dreamStore: DreamStorePort;
|
|
32
|
+
getDreamCliCommand?: (workspaceId: string) => DreamCliCommand;
|
|
33
|
+
getWorkspacePath: (workspaceId: string) => string;
|
|
34
|
+
memoryStore: MemoryStorePort;
|
|
35
|
+
scheduleExport: (workspaceId: string) => void;
|
|
36
|
+
}) => TeamMemoryDreamRunner;
|
|
37
|
+
export {};
|