@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,119 @@
|
|
|
1
|
+
import { RECALL_QUERY_MAX_CHARS } from '../shared/team-recall.js';
|
|
2
|
+
import { BadRequestError } from './http-errors.js';
|
|
3
|
+
import { readJsonBody, route, sendJson } from './route-helpers.js';
|
|
4
|
+
import { authenticateCliAgent, requireCommandForRole } from './team-authz.js';
|
|
5
|
+
const DEFAULT_RECALL_LIMIT = 10;
|
|
6
|
+
const requireNonEmptyString = (value, field) => {
|
|
7
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
8
|
+
throw new BadRequestError(`Missing ${field}`);
|
|
9
|
+
}
|
|
10
|
+
const trimmed = value.trim();
|
|
11
|
+
if (field === 'query' && [...trimmed].length > RECALL_QUERY_MAX_CHARS) {
|
|
12
|
+
throw new BadRequestError(`query must be ${RECALL_QUERY_MAX_CHARS} characters or fewer`);
|
|
13
|
+
}
|
|
14
|
+
return trimmed;
|
|
15
|
+
};
|
|
16
|
+
const optionalNonNegativeInteger = (value, field) => {
|
|
17
|
+
if (value === undefined)
|
|
18
|
+
return undefined;
|
|
19
|
+
if (!Number.isInteger(value) || Number(value) < 0) {
|
|
20
|
+
throw new BadRequestError(`${field} must be a non-negative integer`);
|
|
21
|
+
}
|
|
22
|
+
return Number(value);
|
|
23
|
+
};
|
|
24
|
+
const serializeContext = (item) => ({
|
|
25
|
+
created_at: item.createdAt,
|
|
26
|
+
from_agent_id: item.fromAgentId,
|
|
27
|
+
source_sequence: item.sourceSequence,
|
|
28
|
+
text: item.text,
|
|
29
|
+
to_agent_id: item.toAgentId,
|
|
30
|
+
type: item.type,
|
|
31
|
+
worker_id: item.workerId,
|
|
32
|
+
});
|
|
33
|
+
const serializeRecallResult = (result) => ({
|
|
34
|
+
context: result.context.map(serializeContext),
|
|
35
|
+
created_at: result.createdAt,
|
|
36
|
+
dispatch_id: result.dispatchId,
|
|
37
|
+
dispatch_status: result.dispatchStatus,
|
|
38
|
+
from_agent_id: result.fromAgentId,
|
|
39
|
+
index_name: result.indexName,
|
|
40
|
+
memory_confidence: result.memoryConfidence ?? null,
|
|
41
|
+
memory_id: result.memoryId ?? null,
|
|
42
|
+
memory_kind: result.memoryKind ?? null,
|
|
43
|
+
memory_status: result.memoryStatus ?? null,
|
|
44
|
+
memory_tags: result.memoryTags ?? [],
|
|
45
|
+
message_type: result.messageType,
|
|
46
|
+
report_text: result.reportText,
|
|
47
|
+
score: result.score,
|
|
48
|
+
source_sequence: result.sourceSequence,
|
|
49
|
+
source_type: result.sourceType,
|
|
50
|
+
text: result.text,
|
|
51
|
+
to_agent_id: result.toAgentId,
|
|
52
|
+
worker_id: result.workerId,
|
|
53
|
+
});
|
|
54
|
+
const memoryToRecallResult = (memory) => ({
|
|
55
|
+
context: memory.sources.map((source) => ({
|
|
56
|
+
createdAt: source.createdAt,
|
|
57
|
+
fromAgentId: source.actorAgentIdSnapshot,
|
|
58
|
+
sourceSequence: source.sourceSequence ?? 0,
|
|
59
|
+
text: source.excerpt ?? '',
|
|
60
|
+
toAgentId: null,
|
|
61
|
+
type: source.sourceType,
|
|
62
|
+
workerId: source.actorAgentIdSnapshot ?? '',
|
|
63
|
+
})),
|
|
64
|
+
createdAt: memory.updatedAt,
|
|
65
|
+
dispatchId: null,
|
|
66
|
+
dispatchStatus: null,
|
|
67
|
+
fromAgentId: null,
|
|
68
|
+
indexName: memory.indexName,
|
|
69
|
+
memoryConfidence: memory.confidence,
|
|
70
|
+
memoryId: memory.id,
|
|
71
|
+
memoryKind: memory.kind,
|
|
72
|
+
memoryStatus: memory.status,
|
|
73
|
+
memoryTags: memory.tags,
|
|
74
|
+
messageType: null,
|
|
75
|
+
reportText: null,
|
|
76
|
+
score: memory.score,
|
|
77
|
+
sourceSequence: 0,
|
|
78
|
+
sourceType: 'memory',
|
|
79
|
+
text: memory.body,
|
|
80
|
+
toAgentId: null,
|
|
81
|
+
workerId: null,
|
|
82
|
+
});
|
|
83
|
+
export const teamRecallRoutes = [
|
|
84
|
+
route('POST', '/api/team/recall', async ({ request, response, store }) => {
|
|
85
|
+
const body = await readJsonBody(request);
|
|
86
|
+
const projectId = requireNonEmptyString(body.project_id, 'project_id');
|
|
87
|
+
const fromAgentId = requireNonEmptyString(body.from_agent_id, 'from_agent_id');
|
|
88
|
+
const query = requireNonEmptyString(body.query, 'query');
|
|
89
|
+
const token = typeof body.token === 'string' ? body.token : undefined;
|
|
90
|
+
const agent = authenticateCliAgent({
|
|
91
|
+
fromAgentId,
|
|
92
|
+
getAgent: store.getAgent,
|
|
93
|
+
token,
|
|
94
|
+
validateToken: store.validateAgentToken,
|
|
95
|
+
workspaceId: projectId,
|
|
96
|
+
});
|
|
97
|
+
requireCommandForRole(agent, 'recall');
|
|
98
|
+
const limit = optionalNonNegativeInteger(body.limit, 'limit');
|
|
99
|
+
const window = optionalNonNegativeInteger(body.window, 'window');
|
|
100
|
+
const recallResults = store.recallMessages(projectId, query, {
|
|
101
|
+
...(limit !== undefined ? { limit } : {}),
|
|
102
|
+
...(window !== undefined ? { window } : {}),
|
|
103
|
+
});
|
|
104
|
+
const memoryResults = store
|
|
105
|
+
.searchMemoryEntries(projectId, query, {
|
|
106
|
+
...(limit !== undefined ? { limit } : {}),
|
|
107
|
+
statuses: ['active'],
|
|
108
|
+
})
|
|
109
|
+
.map(memoryToRecallResult);
|
|
110
|
+
const combined = [...recallResults, ...memoryResults]
|
|
111
|
+
.sort((a, b) => a.score - b.score || b.createdAt - a.createdAt)
|
|
112
|
+
.slice(0, limit ?? DEFAULT_RECALL_LIMIT);
|
|
113
|
+
sendJson(response, 200, {
|
|
114
|
+
ok: true,
|
|
115
|
+
query,
|
|
116
|
+
results: combined.map(serializeRecallResult),
|
|
117
|
+
});
|
|
118
|
+
}),
|
|
119
|
+
];
|
|
@@ -26,6 +26,26 @@ const requireNonEmptyString = (value, field) => {
|
|
|
26
26
|
return value;
|
|
27
27
|
};
|
|
28
28
|
const getArtifacts = (value) => Array.isArray(value) ? value.filter((item) => typeof item === 'string') : [];
|
|
29
|
+
const REPORT_STATUSES = new Set(['success', 'failed']);
|
|
30
|
+
const getReportStatus = (value) => {
|
|
31
|
+
if (value === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
if (typeof value !== 'string' || !REPORT_STATUSES.has(value)) {
|
|
34
|
+
throw new BadRequestError('Invalid status; expected success or failed');
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
};
|
|
38
|
+
const resolveSpawnLaunchConfig = (store, cli) => {
|
|
39
|
+
if (cli === undefined || cli === null || cli === '') {
|
|
40
|
+
return (resolveCommandPresetLaunchConfig(store.settings, 'claude') ?? { command: 'claude', args: [] });
|
|
41
|
+
}
|
|
42
|
+
const cliId = requireNonEmptyString(cli, 'cli');
|
|
43
|
+
const launchConfig = resolveCommandPresetLaunchConfig(store.settings, cliId);
|
|
44
|
+
if (!launchConfig) {
|
|
45
|
+
throw new BadRequestError(`Unsupported cli '${cliId}'`);
|
|
46
|
+
}
|
|
47
|
+
return launchConfig;
|
|
48
|
+
};
|
|
29
49
|
export const teamRoutes = [
|
|
30
50
|
route('POST', '/api/team/send', async ({ request, response, store }) => {
|
|
31
51
|
const body = await readJsonBody(request);
|
|
@@ -42,14 +62,13 @@ export const teamRoutes = [
|
|
|
42
62
|
});
|
|
43
63
|
requireCommandForRole(agent, 'send');
|
|
44
64
|
const dispatch = await store.dispatchTaskByWorkerName(projectId, to, text, {
|
|
65
|
+
autoStartWorker: false,
|
|
45
66
|
fromAgentId,
|
|
46
67
|
hivePort: String(request.socket.localPort ?? ''),
|
|
47
68
|
});
|
|
48
|
-
/*
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
stderr notice on this flag so the agent can explain the wake-up
|
|
52
|
-
to the user instead of being out of sync with worker state. */
|
|
69
|
+
/* The user-facing team send route queues work for stopped workers without
|
|
70
|
+
auto-starting them; internal workflow dispatches may still surface
|
|
71
|
+
restarted_worker when they intentionally wake a worker. */
|
|
53
72
|
sendJson(response, 202, {
|
|
54
73
|
dispatch_id: dispatch.id,
|
|
55
74
|
ok: true,
|
|
@@ -72,8 +91,7 @@ export const teamRoutes = [
|
|
|
72
91
|
const name = typeof body.name === 'string' && body.name.trim().length > 0
|
|
73
92
|
? body.name.trim()
|
|
74
93
|
: `${role}-${randomUUID()}`;
|
|
75
|
-
const launchConfig = (
|
|
76
|
-
{ command: body.cli ?? 'claude', args: [] };
|
|
94
|
+
const launchConfig = resolveSpawnLaunchConfig(store, body.cli);
|
|
77
95
|
// M11: default is persistent (acts like a normal member); --ephemeral
|
|
78
96
|
// opts into auto-dismiss-after-first-report (mirrors workflow workers,
|
|
79
97
|
// but orchestrator-spawned). Existing M1-D cascade-on-orchestrator-exit
|
|
@@ -289,16 +307,18 @@ export const teamRoutes = [
|
|
|
289
307
|
requireActiveRun: true,
|
|
290
308
|
text: resultText,
|
|
291
309
|
};
|
|
292
|
-
|
|
310
|
+
const status = getReportStatus(body.status);
|
|
311
|
+
if (status !== undefined) {
|
|
293
312
|
const result = store.reportTask(projectId, fromAgentId, {
|
|
294
313
|
...reportInput,
|
|
295
|
-
status
|
|
314
|
+
status,
|
|
296
315
|
});
|
|
297
316
|
sendJson(response, 202, {
|
|
298
317
|
dispatch_id: result.dispatch?.id ?? null,
|
|
299
318
|
forward_error: result.forwardError,
|
|
300
319
|
forwarded: result.forwarded,
|
|
301
320
|
ok: true,
|
|
321
|
+
...(result.pendingWarning ? { pending_warning: result.pendingWarning } : {}),
|
|
302
322
|
});
|
|
303
323
|
return;
|
|
304
324
|
}
|
|
@@ -309,6 +329,7 @@ export const teamRoutes = [
|
|
|
309
329
|
forward_error: result.forwardError,
|
|
310
330
|
forwarded: result.forwarded,
|
|
311
331
|
ok: true,
|
|
332
|
+
...(result.pendingWarning ? { pending_warning: result.pendingWarning } : {}),
|
|
312
333
|
});
|
|
313
334
|
return;
|
|
314
335
|
}
|
|
@@ -336,6 +357,7 @@ export const teamRoutes = [
|
|
|
336
357
|
forward_error: result.forwardError,
|
|
337
358
|
forwarded: result.forwarded,
|
|
338
359
|
ok: true,
|
|
360
|
+
...(result.pendingWarning ? { pending_warning: result.pendingWarning } : {}),
|
|
339
361
|
});
|
|
340
362
|
return;
|
|
341
363
|
}),
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
import { ForbiddenError } from './http-errors.js';
|
|
1
2
|
import { route, sendJson } from './route-helpers.js';
|
|
2
3
|
export const uiRoutes = [
|
|
3
|
-
route('GET', '/api/ui/session', ({ response, store }) => {
|
|
4
|
+
route('GET', '/api/ui/session', ({ request, response, store }) => {
|
|
5
|
+
// HARDEN (defense in depth, layer 3): this route mints the master
|
|
6
|
+
// hive_ui_token cookie, the single credential for every /api/* route + WS
|
|
7
|
+
// upgrade. The bridge whitelist already hard-denies /api/ui/session, but if
|
|
8
|
+
// that ever regresses, a tunnel-tagged request must STILL never mint a
|
|
9
|
+
// cookie for a remote device. The tunnel is authorized by the per-boot
|
|
10
|
+
// secret, so it has zero need for the UI cookie — refuse it outright.
|
|
11
|
+
if (store.authorizeRemoteTunnelRequest(request)) {
|
|
12
|
+
throw new ForbiddenError('UI session cookie is not available over the remote tunnel');
|
|
13
|
+
}
|
|
4
14
|
response.setHeader('set-cookie', `hive_ui_token=${store.getUiToken()}; Path=/; HttpOnly; SameSite=Strict`);
|
|
5
15
|
sendJson(response, 200, { ok: true });
|
|
6
16
|
}),
|
|
@@ -8,7 +8,7 @@ import { serializeWorkflowSchedule } from './workflow-http-serializers.js';
|
|
|
8
8
|
// no human create route here.
|
|
9
9
|
export const workflowScheduleRoutes = [
|
|
10
10
|
route('GET', '/api/workspaces/:workspaceId/workflow-schedules', ({ params, request, response, store }) => {
|
|
11
|
-
requireUiTokenFromRequest(request, store.validateUiToken);
|
|
11
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
12
12
|
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
13
13
|
if (!workspaceId)
|
|
14
14
|
return;
|
|
@@ -17,7 +17,7 @@ export const workflowScheduleRoutes = [
|
|
|
17
17
|
});
|
|
18
18
|
}),
|
|
19
19
|
route('PATCH', '/api/workflow-schedules/:scheduleId', async ({ params, request, response, store }) => {
|
|
20
|
-
requireUiTokenFromRequest(request, store.validateUiToken);
|
|
20
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
21
21
|
const scheduleId = getRequiredParam(response, params, 'scheduleId', 'Missing scheduleId');
|
|
22
22
|
if (!scheduleId)
|
|
23
23
|
return;
|
|
@@ -43,7 +43,7 @@ export const workflowScheduleRoutes = [
|
|
|
43
43
|
});
|
|
44
44
|
}),
|
|
45
45
|
route('DELETE', '/api/workflow-schedules/:scheduleId', ({ params, request, response, store }) => {
|
|
46
|
-
requireUiTokenFromRequest(request, store.validateUiToken);
|
|
46
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
47
47
|
const scheduleId = getRequiredParam(response, params, 'scheduleId', 'Missing scheduleId');
|
|
48
48
|
if (!scheduleId)
|
|
49
49
|
return;
|
|
@@ -8,7 +8,7 @@ import { serializeWorkflowDispatch, serializeWorkflowRun } from './workflow-http
|
|
|
8
8
|
// start-by-path, template-install, or source-editor route.
|
|
9
9
|
export const workflowRoutes = [
|
|
10
10
|
route('GET', '/api/workspaces/:workspaceId/workflows/runs', ({ params, request, response, store }) => {
|
|
11
|
-
requireUiTokenFromRequest(request, store.validateUiToken);
|
|
11
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
12
12
|
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
13
13
|
if (!workspaceId)
|
|
14
14
|
return;
|
|
@@ -17,7 +17,7 @@ export const workflowRoutes = [
|
|
|
17
17
|
});
|
|
18
18
|
}),
|
|
19
19
|
route('GET', '/api/workflows/runs/:runId', ({ params, request, response, store }) => {
|
|
20
|
-
requireUiTokenFromRequest(request, store.validateUiToken);
|
|
20
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
21
21
|
const runId = getRequiredParam(response, params, 'runId', 'Missing runId');
|
|
22
22
|
if (!runId)
|
|
23
23
|
return;
|
|
@@ -29,7 +29,7 @@ export const workflowRoutes = [
|
|
|
29
29
|
sendJson(response, 200, { run: serializeWorkflowRun(run) });
|
|
30
30
|
}),
|
|
31
31
|
route('POST', '/api/workflows/runs/:runId/stop', ({ params, request, response, store }) => {
|
|
32
|
-
requireUiTokenFromRequest(request, store.validateUiToken);
|
|
32
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
33
33
|
const runId = getRequiredParam(response, params, 'runId', 'Missing runId');
|
|
34
34
|
if (!runId)
|
|
35
35
|
return;
|
|
@@ -45,7 +45,7 @@ export const workflowRoutes = [
|
|
|
45
45
|
});
|
|
46
46
|
}),
|
|
47
47
|
route('GET', '/api/workflows/runs/:runId/dispatches', ({ params, request, response, store }) => {
|
|
48
|
-
requireUiTokenFromRequest(request, store.validateUiToken);
|
|
48
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
49
49
|
const runId = getRequiredParam(response, params, 'runId', 'Missing runId');
|
|
50
50
|
if (!runId)
|
|
51
51
|
return;
|
|
@@ -70,7 +70,7 @@ export const workflowRoutes = [
|
|
|
70
70
|
/* TIER 2 #3 — narrator lane. Drawer polls this alongside dispatches.
|
|
71
71
|
Same auth path; same 404 semantics. */
|
|
72
72
|
route('GET', '/api/workflows/runs/:runId/logs', ({ params, request, response, store }) => {
|
|
73
|
-
requireUiTokenFromRequest(request, store.validateUiToken);
|
|
73
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
74
74
|
const runId = getRequiredParam(response, params, 'runId', 'Missing runId');
|
|
75
75
|
if (!runId)
|
|
76
76
|
return;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { BadRequestError, ConflictError } from './http-errors.js';
|
|
2
|
+
import { getRequiredParam, readJsonBody, route, sendJson } from './route-helpers.js';
|
|
3
|
+
import { serializeDreamRun } from './team-memory-dream-http-serializers.js';
|
|
4
|
+
import { DreamRunAlreadyRunningError, DreamRunNotFoundError, DreamRunRevertDataError, DreamRunRevertStatusError, DreamWorkspaceMissingError, } from './team-memory-dream-store.js';
|
|
5
|
+
import { readWorkspaceMemoryDreamEnabled, readWorkspaceMemoryEnabled, workspaceMemoryDreamEnabledKey, workspaceMemoryEnabledKey, } from './team-memory-feature.js';
|
|
6
|
+
import { requireUiTokenFromRequest } from './ui-auth-helpers.js';
|
|
7
|
+
const DREAM_RUN_LIST_MAX_LIMIT = 50;
|
|
8
|
+
const requireWorkspace = (response, store, workspaceId) => {
|
|
9
|
+
if (store.listWorkspaces().some((workspace) => workspace.id === workspaceId))
|
|
10
|
+
return true;
|
|
11
|
+
sendJson(response, 404, { error: `Workspace not found: ${workspaceId}` });
|
|
12
|
+
return false;
|
|
13
|
+
};
|
|
14
|
+
const requireDreamEnabled = (store, workspaceId) => {
|
|
15
|
+
const memoryEnabled = readWorkspaceMemoryEnabled(store.settings.getAppState(workspaceMemoryEnabledKey(workspaceId))?.value);
|
|
16
|
+
const dreamEnabled = readWorkspaceMemoryDreamEnabled(store.settings.getAppState(workspaceMemoryDreamEnabledKey(workspaceId))?.value);
|
|
17
|
+
if (!memoryEnabled)
|
|
18
|
+
throw new ConflictError('Workspace memory is disabled');
|
|
19
|
+
if (!dreamEnabled)
|
|
20
|
+
throw new ConflictError('Workspace memory dream is disabled');
|
|
21
|
+
};
|
|
22
|
+
const hasRequestBody = (request) => {
|
|
23
|
+
const rawContentLength = request.headers['content-length'];
|
|
24
|
+
const contentLength = Array.isArray(rawContentLength) ? rawContentLength[0] : rawContentLength;
|
|
25
|
+
return contentLength !== undefined && Number(contentLength) > 0;
|
|
26
|
+
};
|
|
27
|
+
const parseLimit = (value) => {
|
|
28
|
+
if (value === null)
|
|
29
|
+
return 20;
|
|
30
|
+
if (!/^(0|[1-9][0-9]*)$/.test(value)) {
|
|
31
|
+
throw new BadRequestError('limit must be a non-negative integer');
|
|
32
|
+
}
|
|
33
|
+
return Math.min(Number(value), DREAM_RUN_LIST_MAX_LIMIT);
|
|
34
|
+
};
|
|
35
|
+
export const workspaceMemoryDreamRoutes = [
|
|
36
|
+
route('GET', '/api/ui/workspaces/:workspaceId/memory/dream-runs', ({ params, request, response, store }) => {
|
|
37
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
38
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
39
|
+
if (!workspaceId)
|
|
40
|
+
return;
|
|
41
|
+
if (!requireWorkspace(response, store, workspaceId))
|
|
42
|
+
return;
|
|
43
|
+
const url = new URL(request.url ?? '/', 'http://127.0.0.1');
|
|
44
|
+
const runs = store.listMemoryDreamRuns(workspaceId, parseLimit(url.searchParams.get('limit')));
|
|
45
|
+
sendJson(response, 200, { ok: true, runs: runs.map(serializeDreamRun) });
|
|
46
|
+
}),
|
|
47
|
+
route('POST', '/api/ui/workspaces/:workspaceId/memory/dream-runs', async ({ params, request, response, store }) => {
|
|
48
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
49
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
50
|
+
if (!workspaceId)
|
|
51
|
+
return;
|
|
52
|
+
if (!requireWorkspace(response, store, workspaceId))
|
|
53
|
+
return;
|
|
54
|
+
requireDreamEnabled(store, workspaceId);
|
|
55
|
+
if (hasRequestBody(request))
|
|
56
|
+
await readJsonBody(request);
|
|
57
|
+
try {
|
|
58
|
+
const run = await store.runMemoryDream(workspaceId);
|
|
59
|
+
sendJson(response, 200, { ok: true, run: serializeDreamRun(run) });
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error instanceof DreamRunAlreadyRunningError) {
|
|
63
|
+
sendJson(response, 409, { error: 'Workspace already has a running dream run' });
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (error instanceof DreamWorkspaceMissingError) {
|
|
67
|
+
sendJson(response, 404, { error: `Workspace not found: ${error.workspaceId}` });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}),
|
|
73
|
+
route('POST', '/api/ui/workspaces/:workspaceId/memory/dream-runs/:runId/revert', async ({ params, request, response, store }) => {
|
|
74
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
75
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
76
|
+
const runId = getRequiredParam(response, params, 'runId', 'Missing runId');
|
|
77
|
+
if (!workspaceId || !runId)
|
|
78
|
+
return;
|
|
79
|
+
if (!requireWorkspace(response, store, workspaceId))
|
|
80
|
+
return;
|
|
81
|
+
if (hasRequestBody(request))
|
|
82
|
+
await readJsonBody(request);
|
|
83
|
+
try {
|
|
84
|
+
const run = store.revertMemoryDream(workspaceId, runId);
|
|
85
|
+
sendJson(response, 200, { ok: true, run: serializeDreamRun(run) });
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error instanceof DreamRunNotFoundError) {
|
|
89
|
+
sendJson(response, 404, { error: `Dream run not found: ${error.runId}` });
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (error instanceof DreamRunRevertDataError) {
|
|
93
|
+
sendJson(response, 409, { error: 'Dream run cannot be reverted from stored data' });
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (error instanceof DreamRunRevertStatusError) {
|
|
97
|
+
sendJson(response, 409, {
|
|
98
|
+
error: `Dream run has status ${error.actualStatus}; expected ${error.expectedStatus}`,
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}),
|
|
105
|
+
];
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { MEMORY_QUERY_MAX_CHARS, MEMORY_SEARCH_MAX_LIMIT } from '../shared/team-memory.js';
|
|
2
|
+
import { BadRequestError } from './http-errors.js';
|
|
3
|
+
import { getRequiredParam, readJsonBody, route, sendJson } from './route-helpers.js';
|
|
4
|
+
import { readWorkspaceMemoryDreamEnabled, readWorkspaceMemoryEnabled, serializeWorkspaceMemoryDreamEnabled, serializeWorkspaceMemoryEnabled, workspaceMemoryDreamEnabledKey, workspaceMemoryEnabledKey, } from './team-memory-feature.js';
|
|
5
|
+
import { serializeMemoryEntry, serializeMemoryInjection } from './team-memory-http-serializers.js';
|
|
6
|
+
import { MemoryEntryNotFoundError, MemoryEntryStatusError, } from './team-memory-store.js';
|
|
7
|
+
import { requireUiTokenFromRequest } from './ui-auth-helpers.js';
|
|
8
|
+
const MEMORY_STATUSES = ['active', 'candidate', 'archived', 'rejected'];
|
|
9
|
+
const parseLimit = (value) => {
|
|
10
|
+
if (value === null)
|
|
11
|
+
return MEMORY_SEARCH_MAX_LIMIT;
|
|
12
|
+
if (!/^(0|[1-9][0-9]*)$/.test(value)) {
|
|
13
|
+
throw new BadRequestError('limit must be a non-negative integer');
|
|
14
|
+
}
|
|
15
|
+
return Math.min(Number(value), MEMORY_SEARCH_MAX_LIMIT);
|
|
16
|
+
};
|
|
17
|
+
const parseStatuses = (value) => {
|
|
18
|
+
if (value === null)
|
|
19
|
+
return ['active'];
|
|
20
|
+
if (value === 'all')
|
|
21
|
+
return MEMORY_STATUSES;
|
|
22
|
+
if (MEMORY_STATUSES.includes(value))
|
|
23
|
+
return [value];
|
|
24
|
+
throw new BadRequestError('status must be active, candidate, archived, rejected, or all');
|
|
25
|
+
};
|
|
26
|
+
const parseQuery = (value) => {
|
|
27
|
+
const query = value?.trim() ?? '';
|
|
28
|
+
if ([...query].length > MEMORY_QUERY_MAX_CHARS) {
|
|
29
|
+
throw new BadRequestError(`query must be ${MEMORY_QUERY_MAX_CHARS} characters or fewer`);
|
|
30
|
+
}
|
|
31
|
+
return query;
|
|
32
|
+
};
|
|
33
|
+
const requireBoolean = (value, field) => {
|
|
34
|
+
if (typeof value !== 'boolean')
|
|
35
|
+
throw new BadRequestError(`${field} must be a boolean`);
|
|
36
|
+
return value;
|
|
37
|
+
};
|
|
38
|
+
const sendMemoryMutationError = (response, error) => {
|
|
39
|
+
if (error instanceof MemoryEntryNotFoundError) {
|
|
40
|
+
sendJson(response, 404, { error: `Memory entry not found: ${error.memoryId}` });
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (error instanceof MemoryEntryStatusError) {
|
|
44
|
+
sendJson(response, 409, {
|
|
45
|
+
error: `Memory entry has status ${error.actualStatus}; expected ${Array.isArray(error.expectedStatus)
|
|
46
|
+
? error.expectedStatus.join(' or ')
|
|
47
|
+
: error.expectedStatus}`,
|
|
48
|
+
});
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
};
|
|
53
|
+
const getMemoryId = (response, params) => getRequiredParam(response, params, 'memoryId', 'Missing memoryId');
|
|
54
|
+
const requireWorkspace = (response, store, workspaceId) => {
|
|
55
|
+
if (store.listWorkspaces().some((workspace) => workspace.id === workspaceId))
|
|
56
|
+
return true;
|
|
57
|
+
sendJson(response, 404, { error: `Workspace not found: ${workspaceId}` });
|
|
58
|
+
return false;
|
|
59
|
+
};
|
|
60
|
+
export const workspaceMemoryRoutes = [
|
|
61
|
+
route('GET', '/api/ui/workspaces/:workspaceId/memory', ({ params, request, response, store }) => {
|
|
62
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
63
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
64
|
+
if (!workspaceId)
|
|
65
|
+
return;
|
|
66
|
+
if (!requireWorkspace(response, store, workspaceId))
|
|
67
|
+
return;
|
|
68
|
+
const url = new URL(request.url ?? '/', 'http://127.0.0.1');
|
|
69
|
+
const statuses = parseStatuses(url.searchParams.get('status'));
|
|
70
|
+
const limit = parseLimit(url.searchParams.get('limit'));
|
|
71
|
+
const query = parseQuery(url.searchParams.get('query'));
|
|
72
|
+
const memories = query
|
|
73
|
+
? store.searchMemoryEntries(workspaceId, query, {
|
|
74
|
+
includeDisabled: true,
|
|
75
|
+
limit,
|
|
76
|
+
statuses,
|
|
77
|
+
})
|
|
78
|
+
: store.listMemoryEntries(workspaceId, { limit, statuses });
|
|
79
|
+
sendJson(response, 200, { memories: memories.map(serializeMemoryEntry), ok: true });
|
|
80
|
+
}),
|
|
81
|
+
route('GET', '/api/ui/workspaces/:workspaceId/memory/injections', ({ params, request, response, store }) => {
|
|
82
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
83
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
84
|
+
if (!workspaceId)
|
|
85
|
+
return;
|
|
86
|
+
if (!requireWorkspace(response, store, workspaceId))
|
|
87
|
+
return;
|
|
88
|
+
const url = new URL(request.url ?? '/', 'http://127.0.0.1');
|
|
89
|
+
const dispatchId = url.searchParams.get('dispatch_id')?.trim();
|
|
90
|
+
if (!dispatchId)
|
|
91
|
+
throw new BadRequestError('Missing dispatch_id');
|
|
92
|
+
sendJson(response, 200, {
|
|
93
|
+
injections: store
|
|
94
|
+
.listMemoryInjectionsForDispatch(workspaceId, dispatchId)
|
|
95
|
+
.map(serializeMemoryInjection),
|
|
96
|
+
ok: true,
|
|
97
|
+
});
|
|
98
|
+
}),
|
|
99
|
+
route('GET', '/api/ui/workspaces/:workspaceId/memory/settings', ({ params, request, response, store }) => {
|
|
100
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
101
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
102
|
+
if (!workspaceId)
|
|
103
|
+
return;
|
|
104
|
+
if (!requireWorkspace(response, store, workspaceId))
|
|
105
|
+
return;
|
|
106
|
+
sendJson(response, 200, {
|
|
107
|
+
dream_enabled: readWorkspaceMemoryDreamEnabled(store.settings.getAppState(workspaceMemoryDreamEnabledKey(workspaceId))?.value),
|
|
108
|
+
enabled: readWorkspaceMemoryEnabled(store.settings.getAppState(workspaceMemoryEnabledKey(workspaceId))?.value),
|
|
109
|
+
ok: true,
|
|
110
|
+
});
|
|
111
|
+
}),
|
|
112
|
+
route('PUT', '/api/ui/workspaces/:workspaceId/memory/settings', async ({ params, request, response, store }) => {
|
|
113
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
114
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
115
|
+
if (!workspaceId)
|
|
116
|
+
return;
|
|
117
|
+
if (!requireWorkspace(response, store, workspaceId))
|
|
118
|
+
return;
|
|
119
|
+
const body = await readJsonBody(request);
|
|
120
|
+
if (body.enabled !== undefined) {
|
|
121
|
+
store.settings.setAppState(workspaceMemoryEnabledKey(workspaceId), serializeWorkspaceMemoryEnabled(requireBoolean(body.enabled, 'enabled')));
|
|
122
|
+
}
|
|
123
|
+
if (body.dream_enabled !== undefined) {
|
|
124
|
+
store.settings.setAppState(workspaceMemoryDreamEnabledKey(workspaceId), serializeWorkspaceMemoryDreamEnabled(requireBoolean(body.dream_enabled, 'dream_enabled')));
|
|
125
|
+
}
|
|
126
|
+
sendJson(response, 200, {
|
|
127
|
+
dream_enabled: readWorkspaceMemoryDreamEnabled(store.settings.getAppState(workspaceMemoryDreamEnabledKey(workspaceId))?.value),
|
|
128
|
+
enabled: readWorkspaceMemoryEnabled(store.settings.getAppState(workspaceMemoryEnabledKey(workspaceId))?.value),
|
|
129
|
+
ok: true,
|
|
130
|
+
});
|
|
131
|
+
}),
|
|
132
|
+
route('PATCH', '/api/ui/workspaces/:workspaceId/memory/:memoryId', async ({ params, request, response, store }) => {
|
|
133
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
134
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
135
|
+
const memoryId = getMemoryId(response, params);
|
|
136
|
+
if (!workspaceId || !memoryId)
|
|
137
|
+
return;
|
|
138
|
+
if (!requireWorkspace(response, store, workspaceId))
|
|
139
|
+
return;
|
|
140
|
+
const body = await readJsonBody(request);
|
|
141
|
+
try {
|
|
142
|
+
let memory = store.getMemoryEntry(workspaceId, memoryId);
|
|
143
|
+
if (!memory)
|
|
144
|
+
throw new MemoryEntryNotFoundError(memoryId, workspaceId);
|
|
145
|
+
if (body.pinned !== undefined) {
|
|
146
|
+
memory = store.setMemoryPinned(workspaceId, memoryId, requireBoolean(body.pinned, 'pinned'));
|
|
147
|
+
}
|
|
148
|
+
if (body.disabled !== undefined) {
|
|
149
|
+
memory = store.setMemoryDisabled(workspaceId, memoryId, requireBoolean(body.disabled, 'disabled'));
|
|
150
|
+
}
|
|
151
|
+
sendJson(response, 200, { memory: serializeMemoryEntry(memory), ok: true });
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
if (!sendMemoryMutationError(response, error))
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}),
|
|
158
|
+
route('POST', '/api/ui/workspaces/:workspaceId/memory/:memoryId/approve', ({ params, request, response, store }) => {
|
|
159
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
160
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
161
|
+
const memoryId = getMemoryId(response, params);
|
|
162
|
+
if (!workspaceId || !memoryId)
|
|
163
|
+
return;
|
|
164
|
+
if (!requireWorkspace(response, store, workspaceId))
|
|
165
|
+
return;
|
|
166
|
+
try {
|
|
167
|
+
sendJson(response, 200, {
|
|
168
|
+
memory: serializeMemoryEntry(store.approveMemoryCandidate(workspaceId, memoryId)),
|
|
169
|
+
ok: true,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
if (!sendMemoryMutationError(response, error))
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
}),
|
|
177
|
+
route('POST', '/api/ui/workspaces/:workspaceId/memory/:memoryId/reject', ({ params, request, response, store }) => {
|
|
178
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
179
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
180
|
+
const memoryId = getMemoryId(response, params);
|
|
181
|
+
if (!workspaceId || !memoryId)
|
|
182
|
+
return;
|
|
183
|
+
if (!requireWorkspace(response, store, workspaceId))
|
|
184
|
+
return;
|
|
185
|
+
try {
|
|
186
|
+
sendJson(response, 200, {
|
|
187
|
+
memory: serializeMemoryEntry(store.rejectMemoryCandidate(workspaceId, memoryId)),
|
|
188
|
+
ok: true,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (!sendMemoryMutationError(response, error))
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
}),
|
|
196
|
+
route('POST', '/api/ui/workspaces/:workspaceId/memory/:memoryId/archive', ({ params, request, response, store }) => {
|
|
197
|
+
requireUiTokenFromRequest(request, store.validateUiToken, store.authorizeRemoteTunnelRequest);
|
|
198
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Missing workspaceId');
|
|
199
|
+
const memoryId = getMemoryId(response, params);
|
|
200
|
+
if (!workspaceId || !memoryId)
|
|
201
|
+
return;
|
|
202
|
+
if (!requireWorkspace(response, store, workspaceId))
|
|
203
|
+
return;
|
|
204
|
+
try {
|
|
205
|
+
sendJson(response, 200, {
|
|
206
|
+
memory: serializeMemoryEntry(store.archiveMemoryEntry(workspaceId, memoryId)),
|
|
207
|
+
ok: true,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
if (!sendMemoryMutationError(response, error))
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
}),
|
|
215
|
+
];
|