@myagentroam/node 0.9.9 → 0.9.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities.js +2 -92
- package/dist/claude-agent-sdk.js +2 -330
- package/dist/claude-channel.js +2 -44
- package/dist/codex-app-server.js +2 -503
- package/dist/config.js +2 -56
- package/dist/connector/node-connector-options.js +2 -1
- package/dist/connector/node-operation-router.js +2 -22
- package/dist/connector.js +2 -845
- package/dist/control-outbound-scheduler.js +2 -154
- package/dist/database.js +2 -1418
- package/dist/event-buffer.js +2 -19
- package/dist/fake-runner.js +2 -129
- package/dist/health.js +2 -3
- package/dist/main.js +2 -54
- package/dist/migrations/v001.js +3 -144
- package/dist/migrations/v002.js +2 -143
- package/dist/migrations/v003.js +2 -44
- package/dist/migrations/v004.js +34 -30
- package/dist/native-jsonl-reader.js +2 -186
- package/dist/native-session-history.js +2 -1119
- package/dist/opencode-runtime.js +2 -80
- package/dist/opencode-server.js +2 -263
- package/dist/operational.js +2 -122
- package/dist/process-tree.js +2 -18
- package/dist/rotating-log.js +2 -67
- package/dist/runner/abstract-runner.js +2 -232
- package/dist/runner/claude/managed-run-controller.js +2 -345
- package/dist/runner/claude-code-runner.js +2 -303
- package/dist/runner/codex/composer-image-markers.js +2 -0
- package/dist/runner/codex/conversation-parser.js +2 -861
- package/dist/runner/codex/managed-run-controller.js +2 -460
- package/dist/runner/codex-runner.js +2 -628
- package/dist/runner/fake-test-runner.js +2 -47
- package/dist/runner/opencode/conversation-parser.js +2 -221
- package/dist/runner/opencode/managed-run-controller.js +2 -537
- package/dist/runner/opencode-runner.js +2 -448
- package/dist/runner/runner-registry.js +2 -90
- package/dist/runner-command-engine.js +2 -70
- package/dist/runner-profiles.js +2 -215
- package/dist/runner-usage.js +2 -190
- package/dist/runtime-command-detector.js +2 -73
- package/dist/runtime-state.js +2 -982
- package/dist/service/attachment-domain-state.js +2 -7
- package/dist/service/conversation-history-service.js +2 -457
- package/dist/service/conversation-segment-service.js +2 -162
- package/dist/service/external-session-resume-service.js +2 -118
- package/dist/service/fake-managed-run-service.js +2 -60
- package/dist/service/managed-runner-session-service.js +2 -35
- package/dist/service/mcp-installation-verifier.js +2 -87
- package/dist/service/mcp-node-operation-service.js +2 -90
- package/dist/service/mcp-package-installer.js +2 -136
- package/dist/service/native-session-projection-service.js +2 -280
- package/dist/service/native-session-watch-service.js +2 -383
- package/dist/service/node-connection-lifecycle-service.js +2 -84
- package/dist/service/node-control-channel.js +2 -85
- package/dist/service/node-control-message-service.js +2 -107
- package/dist/service/node-request-service.js +2 -52
- package/dist/service/node-run-event-bridge.js +2 -83
- package/dist/service/node-terminal-channel.js +2 -182
- package/dist/service/node-upgrade-coordinator.js +2 -137
- package/dist/service/node-workspace-coordinator.js +2 -70
- package/dist/service/recent-run-projection-service.js +2 -78
- package/dist/service/run-attachment-service.js +2 -194
- package/dist/service/run-domain-state.js +2 -4
- package/dist/service/run-event-service.js +2 -193
- package/dist/service/run-workbench-service.js +2 -104
- package/dist/service/runner-channel-message-service.js +2 -20
- package/dist/service/runner-interaction-service.js +2 -243
- package/dist/service/runner-service.js +2 -71
- package/dist/service/session-catalog-service.js +2 -224
- package/dist/service/session-command-service.js +2 -76
- package/dist/service/session-context-service.js +2 -101
- package/dist/service/session-domain-state.js +2 -9
- package/dist/service/session-identity-service.js +2 -86
- package/dist/service/session-lifecycle-service.js +2 -240
- package/dist/service/session-message-service.js +2 -173
- package/dist/service/session-presentation-service.js +2 -43
- package/dist/service/session-query-service.js +2 -82
- package/dist/service/skill-directory-service.js +2 -238
- package/dist/service/skill-install-service.js +2 -434
- package/dist/service/skill-node-operation-service.js +2 -206
- package/dist/service/terminal-relay-state.js +2 -3
- package/dist/service/terminal-service.js +2 -52
- package/dist/service/workbench-event-service.js +2 -19
- package/dist/service/workbench-manifest-service.js +2 -69
- package/dist/service/workspace-change-service.js +2 -86
- package/dist/service/workspace-content-search-service.js +2 -477
- package/dist/service/workspace-domain-state.js +2 -41
- package/dist/service/workspace-file-service.js +2 -122
- package/dist/service/workspace-git-exclude-service.js +2 -119
- package/dist/service/workspace-queue-workbench-service.js +2 -304
- package/dist/service/workspace-service.js +2 -69
- package/dist/service/workspace-session-service.js +2 -139
- package/dist/service/workspace-upload-service.js +2 -262
- package/dist/service/workspace-watch-service.js +2 -146
- package/dist/service/workspace-workbench-service.js +2 -405
- package/dist/service.js +2 -38
- package/dist/storage.js +2 -32
- package/dist/supervisor.js +2 -136
- package/dist/terminal.js +2 -416
- package/dist/util/node-operation-parsers.js +2 -382
- package/dist/util/personal-instructions.js +2 -31
- package/dist/util/runner-error.js +2 -52
- package/dist/util/runner-native-session-parsers.js +2 -490
- package/dist/util/safe-error.js +2 -5
- package/dist/util/secret-environment.js +2 -25
- package/dist/workspace.js +2 -1519
- package/package.json +3 -3
- package/dist/capabilities.d.ts +0 -12
- package/dist/claude-agent-sdk.d.ts +0 -92
- package/dist/claude-channel.d.ts +0 -28
- package/dist/codex-app-server.d.ts +0 -133
- package/dist/config.d.ts +0 -18
- package/dist/connector/node-connector-options.d.ts +0 -27
- package/dist/connector/node-operation-router.d.ts +0 -9
- package/dist/connector.d.ts +0 -94
- package/dist/control-outbound-scheduler.d.ts +0 -29
- package/dist/database.d.ts +0 -305
- package/dist/event-buffer.d.ts +0 -9
- package/dist/fake-runner.d.ts +0 -42
- package/dist/health.d.ts +0 -4
- package/dist/main.d.ts +0 -2
- package/dist/migrations/v001.d.ts +0 -3
- package/dist/migrations/v002.d.ts +0 -4
- package/dist/migrations/v003.d.ts +0 -4
- package/dist/migrations/v004.d.ts +0 -4
- package/dist/native-jsonl-reader.d.ts +0 -35
- package/dist/native-session-history.d.ts +0 -126
- package/dist/opencode-runtime.d.ts +0 -33
- package/dist/opencode-server.d.ts +0 -49
- package/dist/operational.d.ts +0 -39
- package/dist/process-tree.d.ts +0 -9
- package/dist/rotating-log.d.ts +0 -17
- package/dist/runner/abstract-runner.d.ts +0 -172
- package/dist/runner/claude/managed-run-controller.d.ts +0 -51
- package/dist/runner/claude-code-runner.d.ts +0 -72
- package/dist/runner/codex/conversation-parser.d.ts +0 -59
- package/dist/runner/codex/managed-run-controller.d.ts +0 -90
- package/dist/runner/codex-runner.d.ts +0 -103
- package/dist/runner/fake-test-runner.d.ts +0 -26
- package/dist/runner/opencode/conversation-parser.d.ts +0 -31
- package/dist/runner/opencode/managed-run-controller.d.ts +0 -82
- package/dist/runner/opencode-runner.d.ts +0 -71
- package/dist/runner/runner-registry.d.ts +0 -19
- package/dist/runner-command-engine.d.ts +0 -28
- package/dist/runner-profiles.d.ts +0 -15
- package/dist/runner-usage.d.ts +0 -33
- package/dist/runtime-command-detector.d.ts +0 -3
- package/dist/runtime-state.d.ts +0 -171
- package/dist/service/attachment-domain-state.d.ts +0 -7
- package/dist/service/conversation-history-service.d.ts +0 -43
- package/dist/service/conversation-segment-service.d.ts +0 -20
- package/dist/service/external-session-resume-service.d.ts +0 -34
- package/dist/service/fake-managed-run-service.d.ts +0 -28
- package/dist/service/managed-runner-session-service.d.ts +0 -12
- package/dist/service/mcp-installation-verifier.d.ts +0 -9
- package/dist/service/mcp-node-operation-service.d.ts +0 -11
- package/dist/service/mcp-package-installer.d.ts +0 -8
- package/dist/service/native-session-projection-service.d.ts +0 -52
- package/dist/service/native-session-watch-service.d.ts +0 -62
- package/dist/service/node-connection-lifecycle-service.d.ts +0 -36
- package/dist/service/node-control-channel.d.ts +0 -32
- package/dist/service/node-control-message-service.d.ts +0 -27
- package/dist/service/node-request-service.d.ts +0 -14
- package/dist/service/node-run-event-bridge.d.ts +0 -40
- package/dist/service/node-terminal-channel.d.ts +0 -29
- package/dist/service/node-upgrade-coordinator.d.ts +0 -29
- package/dist/service/node-workspace-coordinator.d.ts +0 -29
- package/dist/service/recent-run-projection-service.d.ts +0 -14
- package/dist/service/run-attachment-service.d.ts +0 -38
- package/dist/service/run-domain-state.d.ts +0 -4
- package/dist/service/run-event-service.d.ts +0 -33
- package/dist/service/run-workbench-service.d.ts +0 -25
- package/dist/service/runner-channel-message-service.d.ts +0 -13
- package/dist/service/runner-interaction-service.d.ts +0 -39
- package/dist/service/runner-service.d.ts +0 -46
- package/dist/service/session-catalog-service.d.ts +0 -45
- package/dist/service/session-command-service.d.ts +0 -24
- package/dist/service/session-context-service.d.ts +0 -35
- package/dist/service/session-domain-state.d.ts +0 -9
- package/dist/service/session-identity-service.d.ts +0 -24
- package/dist/service/session-lifecycle-service.d.ts +0 -31
- package/dist/service/session-message-service.d.ts +0 -33
- package/dist/service/session-presentation-service.d.ts +0 -34
- package/dist/service/session-query-service.d.ts +0 -35
- package/dist/service/skill-directory-service.d.ts +0 -20
- package/dist/service/skill-install-service.d.ts +0 -21
- package/dist/service/skill-node-operation-service.d.ts +0 -44
- package/dist/service/terminal-relay-state.d.ts +0 -6
- package/dist/service/terminal-service.d.ts +0 -12
- package/dist/service/workbench-event-service.d.ts +0 -9
- package/dist/service/workbench-manifest-service.d.ts +0 -90
- package/dist/service/workspace-change-service.d.ts +0 -9
- package/dist/service/workspace-content-search-service.d.ts +0 -14
- package/dist/service/workspace-domain-state.d.ts +0 -79
- package/dist/service/workspace-file-service.d.ts +0 -18
- package/dist/service/workspace-git-exclude-service.d.ts +0 -4
- package/dist/service/workspace-queue-workbench-service.d.ts +0 -86
- package/dist/service/workspace-service.d.ts +0 -15
- package/dist/service/workspace-session-service.d.ts +0 -23
- package/dist/service/workspace-upload-service.d.ts +0 -39
- package/dist/service/workspace-watch-service.d.ts +0 -23
- package/dist/service/workspace-workbench-service.d.ts +0 -58
- package/dist/service.d.ts +0 -4
- package/dist/storage.d.ts +0 -2
- package/dist/supervisor.d.ts +0 -1
- package/dist/terminal.d.ts +0 -133
- package/dist/util/node-operation-parsers.d.ts +0 -92
- package/dist/util/personal-instructions.d.ts +0 -2
- package/dist/util/runner-error.d.ts +0 -6
- package/dist/util/runner-native-session-parsers.d.ts +0 -74
- package/dist/util/safe-error.d.ts +0 -2
- package/dist/util/secret-environment.d.ts +0 -1
- package/dist/workspace.d.ts +0 -217
package/dist/database.js
CHANGED
|
@@ -1,1418 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import { closeSync, existsSync, mkdirSync, openSync, rmSync } from 'node:fs';
|
|
3
|
-
import { dirname } from 'node:path';
|
|
4
|
-
import { DatabaseSync } from 'node:sqlite';
|
|
5
|
-
import { runnerDefaultConfigurationSchema } from '@myagentroam/protocol';
|
|
6
|
-
import { mcpCatalogEntrySchema, mcpInstallationConfigurationSchema, mcpRuntimeDescriptorSchema } from '@myagentroam/protocol';
|
|
7
|
-
import { assertNodeSchema, NODE_SCHEMA_V1 } from './migrations/v001.js';
|
|
8
|
-
import { assertNodeSchemaV2, migrateNodeSchemaV2 } from './migrations/v002.js';
|
|
9
|
-
import { assertNodeSchemaV3, migrateNodeSchemaV3 } from './migrations/v003.js';
|
|
10
|
-
import { assertNodeSchemaV4, migrateNodeSchemaV4, NODE_SCHEMA_VERSION_V4 } from './migrations/v004.js';
|
|
11
|
-
const NODE_SCHEMA_VERSION = NODE_SCHEMA_VERSION_V4;
|
|
12
|
-
export class NodeDatabase {
|
|
13
|
-
now;
|
|
14
|
-
activeWorkspaceLeaseCount() {
|
|
15
|
-
const row = this.raw
|
|
16
|
-
.prepare("SELECT COUNT(*) AS count FROM workspace_leases WHERE state IN ('ACTIVE', 'SUSPECT')")
|
|
17
|
-
.get();
|
|
18
|
-
return row.count;
|
|
19
|
-
}
|
|
20
|
-
raw;
|
|
21
|
-
constructor(path, nodeId, now = Date.now) {
|
|
22
|
-
this.now = now;
|
|
23
|
-
this.nodeIdProvider = typeof nodeId === 'string' ? () => nodeId : nodeId;
|
|
24
|
-
if (path !== ':memory:')
|
|
25
|
-
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
26
|
-
const releaseMigrationLock = acquireNodeMigrationLock(path);
|
|
27
|
-
try {
|
|
28
|
-
this.raw = new DatabaseSync(path, {
|
|
29
|
-
enableForeignKeyConstraints: true,
|
|
30
|
-
timeout: 5_000,
|
|
31
|
-
defensive: true
|
|
32
|
-
});
|
|
33
|
-
this.raw.exec('PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON; PRAGMA busy_timeout = 5000;');
|
|
34
|
-
migrate(this.raw);
|
|
35
|
-
initializeEphemeralRuntimeTables(this.raw);
|
|
36
|
-
}
|
|
37
|
-
finally {
|
|
38
|
-
releaseMigrationLock();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
close() {
|
|
42
|
-
this.raw.close();
|
|
43
|
-
}
|
|
44
|
-
getRunnerDefaults() {
|
|
45
|
-
const rows = this.raw
|
|
46
|
-
.prepare('SELECT runner, model, effort, access FROM runner_defaults ORDER BY runner')
|
|
47
|
-
.all();
|
|
48
|
-
return rows.flatMap((row) => {
|
|
49
|
-
const parsed = runnerDefaultConfigurationSchema.safeParse({
|
|
50
|
-
runner: stringValue(row, 'runner'),
|
|
51
|
-
model: stringValue(row, 'model'),
|
|
52
|
-
effort: stringValue(row, 'effort'),
|
|
53
|
-
access: stringValue(row, 'access')
|
|
54
|
-
});
|
|
55
|
-
return parsed.success ? [parsed.data] : [];
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
saveRunnerDefaults(input) {
|
|
59
|
-
this.raw
|
|
60
|
-
.prepare(`INSERT INTO runner_defaults (runner, model, effort, access)
|
|
61
|
-
VALUES (?, ?, ?, ?)
|
|
62
|
-
ON CONFLICT(runner) DO UPDATE SET
|
|
63
|
-
model = excluded.model, effort = excluded.effort,
|
|
64
|
-
access = excluded.access`)
|
|
65
|
-
.run(input.runner, input.model, input.effort, input.access);
|
|
66
|
-
return input;
|
|
67
|
-
}
|
|
68
|
-
listMcpInstallations(targetKind, targetId = '') {
|
|
69
|
-
const rows = this.raw
|
|
70
|
-
.prepare(`SELECT target_kind,target_id,catalog_entry_id,server_name,display_name,version,
|
|
71
|
-
enabled,runtime,configuration,installed_at
|
|
72
|
-
FROM mcp_installations WHERE target_kind=? AND target_id=? ORDER BY display_name,server_name`)
|
|
73
|
-
.all(targetKind, targetKind === 'NODE' ? '' : targetId);
|
|
74
|
-
return rows.map(mcpInstallation);
|
|
75
|
-
}
|
|
76
|
-
saveMcpInstallation(input) {
|
|
77
|
-
const entry = mcpCatalogEntrySchema.parse(input.entry);
|
|
78
|
-
const configuration = mcpInstallationConfigurationSchema.parse(input.configuration);
|
|
79
|
-
const targetId = input.targetKind === 'NODE' ? '' : (input.targetId ?? '');
|
|
80
|
-
if (input.targetKind === 'WORKSPACE' && this.getWorkspace(targetId) === undefined)
|
|
81
|
-
throw new Error('WORKSPACE_NOT_FOUND');
|
|
82
|
-
const installedAt = this.now();
|
|
83
|
-
this.raw
|
|
84
|
-
.prepare(`INSERT INTO mcp_installations
|
|
85
|
-
(target_kind,target_id,catalog_entry_id,server_name,display_name,version,enabled,runtime,configuration,installed_at)
|
|
86
|
-
VALUES (?,?,?,?,?,?,?,?,?,?)
|
|
87
|
-
ON CONFLICT(target_kind,target_id,server_name) DO UPDATE SET
|
|
88
|
-
catalog_entry_id=excluded.catalog_entry_id,display_name=excluded.display_name,
|
|
89
|
-
version=excluded.version,enabled=excluded.enabled,runtime=excluded.runtime,
|
|
90
|
-
configuration=excluded.configuration,installed_at=excluded.installed_at`)
|
|
91
|
-
.run(input.targetKind, targetId, entry.id, entry.serverName, entry.displayName, entry.version, input.enabled ? 1 : 0, JSON.stringify(entry.runtime), JSON.stringify(configuration), installedAt);
|
|
92
|
-
return {
|
|
93
|
-
targetKind: input.targetKind,
|
|
94
|
-
targetId,
|
|
95
|
-
catalogEntryId: entry.id,
|
|
96
|
-
serverName: entry.serverName,
|
|
97
|
-
displayName: entry.displayName,
|
|
98
|
-
version: entry.version,
|
|
99
|
-
enabled: input.enabled,
|
|
100
|
-
runtime: entry.runtime,
|
|
101
|
-
configuration,
|
|
102
|
-
installedAt
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
removeMcpInstallation(targetKind, targetId, serverName) {
|
|
106
|
-
return (Number(this.raw
|
|
107
|
-
.prepare('DELETE FROM mcp_installations WHERE target_kind=? AND target_id=? AND server_name=?')
|
|
108
|
-
.run(targetKind, targetKind === 'NODE' ? '' : targetId, serverName).changes) > 0);
|
|
109
|
-
}
|
|
110
|
-
effectiveMcpInstallations(workspaceId) {
|
|
111
|
-
const effective = new Map(this.listMcpInstallations('NODE').map((installation) => [
|
|
112
|
-
installation.serverName,
|
|
113
|
-
installation
|
|
114
|
-
]));
|
|
115
|
-
for (const installation of this.listMcpInstallations('WORKSPACE', workspaceId))
|
|
116
|
-
effective.set(installation.serverName, installation);
|
|
117
|
-
return [...effective.values()].filter((installation) => installation.enabled);
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Stores only terminal lifecycle metadata. PTY input/output must remain in
|
|
121
|
-
* the Node-local bounded replay buffer and must never be passed here.
|
|
122
|
-
*/
|
|
123
|
-
saveTerminalSession(input) {
|
|
124
|
-
this.raw
|
|
125
|
-
.prepare(`INSERT INTO terminal_sessions
|
|
126
|
-
(id, workspace_id, profile_id, state, exit_code, rows, cols, latest_sequence, created_at, updated_at)
|
|
127
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
128
|
-
ON CONFLICT(id) DO UPDATE SET workspace_id = excluded.workspace_id, profile_id = excluded.profile_id, state = excluded.state,
|
|
129
|
-
exit_code = excluded.exit_code, rows = excluded.rows, cols = excluded.cols,
|
|
130
|
-
latest_sequence = excluded.latest_sequence, updated_at = excluded.updated_at`)
|
|
131
|
-
.run(input.id, input.workspaceId, input.profileId, input.state, input.exitCode, input.rows, input.cols, input.latestSequence, input.createdAt, input.updatedAt);
|
|
132
|
-
return this.getTerminalSession(input.id);
|
|
133
|
-
}
|
|
134
|
-
getTerminalSession(id) {
|
|
135
|
-
const row = this.raw
|
|
136
|
-
.prepare(`SELECT id, workspace_id, profile_id, state, exit_code, rows, cols, latest_sequence, created_at, updated_at
|
|
137
|
-
FROM terminal_sessions WHERE id = ?`)
|
|
138
|
-
.get(id);
|
|
139
|
-
return row === undefined ? undefined : terminalSession(row);
|
|
140
|
-
}
|
|
141
|
-
listTerminalSessions() {
|
|
142
|
-
return this.raw
|
|
143
|
-
.prepare(`SELECT id, workspace_id, profile_id, state, exit_code, rows, cols, latest_sequence, created_at, updated_at
|
|
144
|
-
FROM terminal_sessions WHERE state = 'RUNNING' ORDER BY created_at ASC, id ASC`)
|
|
145
|
-
.all()
|
|
146
|
-
.map((row) => terminalSession(row));
|
|
147
|
-
}
|
|
148
|
-
/** A restart cannot safely reattach an orphaned PTY, so record it as closed. */
|
|
149
|
-
closeRunningTerminalSessions() {
|
|
150
|
-
this.raw
|
|
151
|
-
.prepare("UPDATE terminal_sessions SET state = 'CLOSED', updated_at = ? WHERE state = 'RUNNING'")
|
|
152
|
-
.run(this.now());
|
|
153
|
-
}
|
|
154
|
-
saveWorkspace(input) {
|
|
155
|
-
const current = this.raw.prepare('SELECT id FROM workspaces WHERE path = ?').get(input.path);
|
|
156
|
-
const workspace = {
|
|
157
|
-
id: current === undefined ? (input.id ?? randomUUID()) : stringValue(current, 'id'),
|
|
158
|
-
path: input.path,
|
|
159
|
-
kind: input.kind,
|
|
160
|
-
gitSummary: input.gitSummary
|
|
161
|
-
};
|
|
162
|
-
const timestamp = this.now();
|
|
163
|
-
this.raw
|
|
164
|
-
.prepare(`INSERT INTO workspaces (id, path, kind, git_summary, created_at, updated_at)
|
|
165
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
166
|
-
ON CONFLICT(path) DO UPDATE SET kind = excluded.kind,
|
|
167
|
-
git_summary = excluded.git_summary, updated_at = excluded.updated_at`)
|
|
168
|
-
.run(workspace.id, workspace.path, workspace.kind, workspace.gitSummary === null ? null : JSON.stringify(workspace.gitSummary), timestamp, timestamp);
|
|
169
|
-
return workspace;
|
|
170
|
-
}
|
|
171
|
-
listWorkspaces() {
|
|
172
|
-
return this.raw
|
|
173
|
-
.prepare('SELECT id, path, kind, git_summary FROM workspaces ORDER BY created_at ASC')
|
|
174
|
-
.all()
|
|
175
|
-
.map((row) => workspace(row));
|
|
176
|
-
}
|
|
177
|
-
getWorkspace(id) {
|
|
178
|
-
const row = this.raw
|
|
179
|
-
.prepare('SELECT id, path, kind, git_summary FROM workspaces WHERE id = ?')
|
|
180
|
-
.get(id);
|
|
181
|
-
return row === undefined ? undefined : workspace(row);
|
|
182
|
-
}
|
|
183
|
-
/** Unregisters a Workspace registration without deleting its local directory. */
|
|
184
|
-
removeWorkspace(id) {
|
|
185
|
-
const current = this.getWorkspace(id);
|
|
186
|
-
if (current === undefined)
|
|
187
|
-
throw new Error('WORKSPACE_NOT_FOUND');
|
|
188
|
-
this.raw.exec('BEGIN');
|
|
189
|
-
try {
|
|
190
|
-
// Session deletion cascades their runs, conversation and attachments. The workspace
|
|
191
|
-
// record itself never represents a filesystem deletion.
|
|
192
|
-
this.raw.prepare('DELETE FROM agent_sessions WHERE workspace_id = ?').run(id);
|
|
193
|
-
this.raw.prepare('DELETE FROM legacy_agent_sessions WHERE workspace_id = ?').run(id);
|
|
194
|
-
this.raw
|
|
195
|
-
.prepare("DELETE FROM mcp_installations WHERE target_kind='WORKSPACE' AND target_id = ?")
|
|
196
|
-
.run(id);
|
|
197
|
-
this.raw.prepare('DELETE FROM workspaces WHERE id = ?').run(id);
|
|
198
|
-
this.raw.exec('COMMIT');
|
|
199
|
-
return current;
|
|
200
|
-
}
|
|
201
|
-
catch (error) {
|
|
202
|
-
this.raw.exec('ROLLBACK');
|
|
203
|
-
throw error;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
createAgentSession(input) {
|
|
207
|
-
if (this.getWorkspace(input.workspaceId) === undefined)
|
|
208
|
-
throw new Error('WORKSPACE_NOT_FOUND');
|
|
209
|
-
const session = {
|
|
210
|
-
id: randomUUID(),
|
|
211
|
-
nodeId: this.nodeIdProvider(),
|
|
212
|
-
workspaceId: input.workspaceId,
|
|
213
|
-
runner: input.runner,
|
|
214
|
-
externalSessionId: input.externalSessionId ?? null,
|
|
215
|
-
nativeControl: input.externalSessionId === undefined ? 'MAR_MANAGED' : (input.nativeControl ?? 'EXTERNAL'),
|
|
216
|
-
channelToken: null,
|
|
217
|
-
cwd: input.cwd,
|
|
218
|
-
model: optionValue(input.model),
|
|
219
|
-
effort: optionValue(input.effort),
|
|
220
|
-
access: optionValue(input.access),
|
|
221
|
-
customTitle: null,
|
|
222
|
-
runnerTitle: input.title?.trim().slice(0, 160) || null,
|
|
223
|
-
pinnedAt: null,
|
|
224
|
-
titleSource: input.title?.trim() ? 'RUNNER' : 'AUTO',
|
|
225
|
-
lastActivityAt: this.now(),
|
|
226
|
-
createdAt: this.now()
|
|
227
|
-
};
|
|
228
|
-
this.raw
|
|
229
|
-
.prepare(`INSERT INTO legacy_agent_sessions
|
|
230
|
-
(id, workspace_id, runner, external_session_id, native_control, channel_token, cwd, model, effort, access, custom_title, runner_title, pinned_at, title_source, last_activity_at, created_at, updated_at)
|
|
231
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
232
|
-
.run(session.id, session.workspaceId, session.runner, session.externalSessionId, session.nativeControl, session.channelToken, session.cwd, session.model, session.effort, session.access, session.customTitle, session.runnerTitle, session.pinnedAt, session.titleSource, session.lastActivityAt, session.createdAt, session.createdAt);
|
|
233
|
-
return session;
|
|
234
|
-
}
|
|
235
|
-
getAgentSession(id) {
|
|
236
|
-
const row = this.raw
|
|
237
|
-
.prepare('SELECT id, workspace_id, runner, external_session_id, native_control, channel_token, cwd, model, effort, access, custom_title, runner_title, pinned_at, title_source, last_activity_at, created_at FROM legacy_agent_sessions WHERE id = ?')
|
|
238
|
-
.get(id);
|
|
239
|
-
return row === undefined ? undefined : session(row, this.nodeIdProvider());
|
|
240
|
-
}
|
|
241
|
-
updateAgentSessionConfiguration(input) {
|
|
242
|
-
const result = this.raw
|
|
243
|
-
.prepare(`UPDATE legacy_agent_sessions
|
|
244
|
-
SET model = ?, effort = ?, access = ?, updated_at = ?
|
|
245
|
-
WHERE id = ?`)
|
|
246
|
-
.run(input.model, input.effort, input.access, this.now(), input.sessionId);
|
|
247
|
-
if (Number(result.changes) === 0)
|
|
248
|
-
throw new Error('SESSION_NOT_FOUND');
|
|
249
|
-
return this.getAgentSession(input.sessionId);
|
|
250
|
-
}
|
|
251
|
-
listAgentSessions() {
|
|
252
|
-
return this.raw
|
|
253
|
-
.prepare('SELECT id, workspace_id, runner, external_session_id, native_control, channel_token, cwd, model, effort, access, custom_title, runner_title, pinned_at, title_source, last_activity_at, created_at FROM legacy_agent_sessions ORDER BY pinned_at IS NULL, pinned_at DESC, last_activity_at DESC, id DESC')
|
|
254
|
-
.all()
|
|
255
|
-
.map((row) => session(row, this.nodeIdProvider()));
|
|
256
|
-
}
|
|
257
|
-
findAgentSessionByExternalSession(runner, externalSessionId) {
|
|
258
|
-
const row = this.raw
|
|
259
|
-
.prepare(`SELECT id, workspace_id, runner, external_session_id, native_control, channel_token, cwd, model, effort, access, custom_title, runner_title, pinned_at, title_source, last_activity_at, created_at
|
|
260
|
-
FROM legacy_agent_sessions WHERE runner = ? AND external_session_id = ?`)
|
|
261
|
-
.get(runner, externalSessionId);
|
|
262
|
-
return row === undefined ? undefined : session(row, this.nodeIdProvider());
|
|
263
|
-
}
|
|
264
|
-
setNativeControl(sessionId, nativeControl) {
|
|
265
|
-
const result = this.raw
|
|
266
|
-
.prepare('UPDATE legacy_agent_sessions SET native_control = ?, updated_at = ? WHERE id = ?')
|
|
267
|
-
.run(nativeControl, this.now(), sessionId);
|
|
268
|
-
if (Number(result.changes) === 0)
|
|
269
|
-
throw new Error('SESSION_NOT_FOUND');
|
|
270
|
-
}
|
|
271
|
-
setExternalSessionId(sessionId, externalSessionId) {
|
|
272
|
-
if (externalSessionId.length === 0)
|
|
273
|
-
throw new Error('SESSION_EXTERNAL_ID_INVALID');
|
|
274
|
-
const result = this.raw
|
|
275
|
-
.prepare("UPDATE legacy_agent_sessions SET external_session_id = ?, native_control = 'MAR_MANAGED', updated_at = ? WHERE id = ?")
|
|
276
|
-
.run(externalSessionId, this.now(), sessionId);
|
|
277
|
-
if (Number(result.changes) === 0)
|
|
278
|
-
throw new Error('SESSION_NOT_FOUND');
|
|
279
|
-
}
|
|
280
|
-
setChannelToken(sessionId, token) {
|
|
281
|
-
if (token.length < 16)
|
|
282
|
-
throw new Error('SESSION_CHANNEL_TOKEN_INVALID');
|
|
283
|
-
const result = this.raw
|
|
284
|
-
.prepare('UPDATE legacy_agent_sessions SET channel_token = ?, updated_at = ? WHERE id = ?')
|
|
285
|
-
.run(token, this.now(), sessionId);
|
|
286
|
-
if (Number(result.changes) === 0)
|
|
287
|
-
throw new Error('SESSION_NOT_FOUND');
|
|
288
|
-
}
|
|
289
|
-
updateSessionMetadata(input) {
|
|
290
|
-
const current = this.getAgentSession(input.sessionId);
|
|
291
|
-
if (current === undefined)
|
|
292
|
-
throw new Error('SESSION_NOT_FOUND');
|
|
293
|
-
const title = input.customTitle === undefined ? current.customTitle : input.customTitle?.trim() || null;
|
|
294
|
-
if (title !== null && title.length > 160)
|
|
295
|
-
throw new Error('SESSION_TITLE_INVALID');
|
|
296
|
-
const pinnedAt = input.pinned === undefined ? current.pinnedAt : input.pinned ? this.now() : null;
|
|
297
|
-
const titleSource = title === null ? 'AUTO' : 'CUSTOM';
|
|
298
|
-
this.raw
|
|
299
|
-
.prepare('UPDATE legacy_agent_sessions SET custom_title = ?, pinned_at = ?, title_source = ?, updated_at = ? WHERE id = ?')
|
|
300
|
-
.run(title, pinnedAt, titleSource, this.now(), input.sessionId);
|
|
301
|
-
return this.getAgentSession(input.sessionId);
|
|
302
|
-
}
|
|
303
|
-
getNativeSessionMetadata(runner, externalSessionId, workspaceId) {
|
|
304
|
-
const row = this.raw
|
|
305
|
-
.prepare('SELECT pin_order, metadata FROM agent_sessions WHERE id = ? AND runner = ? AND workspace_id = ?')
|
|
306
|
-
.get(externalSessionId, runner, workspaceId);
|
|
307
|
-
if (row === undefined)
|
|
308
|
-
return undefined;
|
|
309
|
-
return {
|
|
310
|
-
...sessionMetadata(row),
|
|
311
|
-
pinnedAt: row['pin_order'] === null ? null : 1,
|
|
312
|
-
pinOrder: nullableNumber(row, 'pin_order')
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
saveNativeSessionMetadata(input) {
|
|
316
|
-
const current = this.getNativeSessionMetadata(input.runner, input.externalSessionId, input.workspaceId);
|
|
317
|
-
const customTitle = input.customTitle === undefined
|
|
318
|
-
? (current?.customTitle ?? null)
|
|
319
|
-
: input.customTitle?.trim() || null;
|
|
320
|
-
const runnerTitle = input.runnerTitle === undefined
|
|
321
|
-
? (current?.runnerTitle ?? null)
|
|
322
|
-
: input.runnerTitle?.trim() || null;
|
|
323
|
-
const runnerTitlePending = input.runnerTitlePending === undefined
|
|
324
|
-
? (current?.runnerTitlePending ?? false)
|
|
325
|
-
: input.runnerTitlePending;
|
|
326
|
-
if (customTitle !== null && customTitle.length > 160)
|
|
327
|
-
throw new Error('SESSION_TITLE_INVALID');
|
|
328
|
-
if (runnerTitle !== null && runnerTitle.length > 160)
|
|
329
|
-
throw new Error('SESSION_TITLE_INVALID');
|
|
330
|
-
let pinOrder = current?.pinOrder ?? null;
|
|
331
|
-
const pinAtTop = input.pinned === true && pinOrder === null;
|
|
332
|
-
if (pinAtTop)
|
|
333
|
-
pinOrder = 0;
|
|
334
|
-
else if (input.pinned === false)
|
|
335
|
-
pinOrder = null;
|
|
336
|
-
const model = input.model === undefined ? (current?.model ?? null) : input.model;
|
|
337
|
-
const effort = input.effort === undefined ? (current?.effort ?? null) : input.effort;
|
|
338
|
-
const access = input.access === undefined ? (current?.access ?? null) : input.access;
|
|
339
|
-
const metadata = JSON.stringify({
|
|
340
|
-
version: 1,
|
|
341
|
-
customTitle,
|
|
342
|
-
runnerTitle,
|
|
343
|
-
runnerTitlePending,
|
|
344
|
-
model,
|
|
345
|
-
effort,
|
|
346
|
-
access
|
|
347
|
-
});
|
|
348
|
-
this.raw.exec('BEGIN IMMEDIATE');
|
|
349
|
-
try {
|
|
350
|
-
if (pinAtTop)
|
|
351
|
-
this.raw
|
|
352
|
-
.prepare('UPDATE agent_sessions SET pin_order = pin_order + 1 WHERE workspace_id = ? AND pin_order IS NOT NULL')
|
|
353
|
-
.run(input.workspaceId);
|
|
354
|
-
this.raw
|
|
355
|
-
.prepare(`INSERT INTO agent_sessions (id, workspace_id, runner, pin_order, metadata)
|
|
356
|
-
VALUES (?, ?, ?, ?, ?)
|
|
357
|
-
ON CONFLICT(id) DO UPDATE SET workspace_id = excluded.workspace_id,
|
|
358
|
-
runner = excluded.runner, pin_order = excluded.pin_order, metadata = excluded.metadata`)
|
|
359
|
-
.run(input.externalSessionId, input.workspaceId, input.runner, pinOrder, metadata);
|
|
360
|
-
this.raw.exec('COMMIT');
|
|
361
|
-
}
|
|
362
|
-
catch (error) {
|
|
363
|
-
this.raw.exec('ROLLBACK');
|
|
364
|
-
throw error;
|
|
365
|
-
}
|
|
366
|
-
return {
|
|
367
|
-
customTitle,
|
|
368
|
-
runnerTitle,
|
|
369
|
-
runnerTitlePending,
|
|
370
|
-
pinnedAt: pinOrder === null ? null : 1,
|
|
371
|
-
pinOrder,
|
|
372
|
-
model,
|
|
373
|
-
effort,
|
|
374
|
-
access
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
listSessionRecords(workspaceId) {
|
|
378
|
-
return this.raw
|
|
379
|
-
.prepare('SELECT id, workspace_id, runner, pin_order, metadata FROM agent_sessions WHERE workspace_id = ? ORDER BY pin_order IS NULL, pin_order, id')
|
|
380
|
-
.all(workspaceId).map((row) => ({
|
|
381
|
-
id: stringValue(row, 'id'),
|
|
382
|
-
workspaceId: stringValue(row, 'workspace_id'),
|
|
383
|
-
runner: stringValue(row, 'runner'),
|
|
384
|
-
pinOrder: nullableNumber(row, 'pin_order'),
|
|
385
|
-
metadata: {
|
|
386
|
-
...sessionMetadata(row),
|
|
387
|
-
pinnedAt: row['pin_order'] === null ? null : 1,
|
|
388
|
-
pinOrder: nullableNumber(row, 'pin_order')
|
|
389
|
-
}
|
|
390
|
-
}));
|
|
391
|
-
}
|
|
392
|
-
movePinnedSession(sessionId, direction) {
|
|
393
|
-
const current = this.raw
|
|
394
|
-
.prepare('SELECT workspace_id, pin_order FROM agent_sessions WHERE id = ?')
|
|
395
|
-
.get(sessionId);
|
|
396
|
-
if (current === undefined || current['pin_order'] === null)
|
|
397
|
-
throw new Error('SESSION_NOT_PINNED');
|
|
398
|
-
const order = numberValue(current, 'pin_order');
|
|
399
|
-
const adjacent = this.raw
|
|
400
|
-
.prepare(direction === 'up'
|
|
401
|
-
? 'SELECT id, pin_order FROM agent_sessions WHERE workspace_id = ? AND pin_order < ? ORDER BY pin_order DESC LIMIT 1'
|
|
402
|
-
: 'SELECT id, pin_order FROM agent_sessions WHERE workspace_id = ? AND pin_order > ? ORDER BY pin_order ASC LIMIT 1')
|
|
403
|
-
.get(stringValue(current, 'workspace_id'), order);
|
|
404
|
-
if (adjacent === undefined)
|
|
405
|
-
return;
|
|
406
|
-
this.raw.exec('BEGIN IMMEDIATE');
|
|
407
|
-
try {
|
|
408
|
-
this.raw
|
|
409
|
-
.prepare('UPDATE agent_sessions SET pin_order = ? WHERE id = ?')
|
|
410
|
-
.run(order, stringValue(adjacent, 'id'));
|
|
411
|
-
this.raw
|
|
412
|
-
.prepare('UPDATE agent_sessions SET pin_order = ? WHERE id = ?')
|
|
413
|
-
.run(numberValue(adjacent, 'pin_order'), sessionId);
|
|
414
|
-
this.raw.exec('COMMIT');
|
|
415
|
-
}
|
|
416
|
-
catch (error) {
|
|
417
|
-
this.raw.exec('ROLLBACK');
|
|
418
|
-
throw error;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
deleteSessionRecord(sessionId) {
|
|
422
|
-
return (Number(this.raw.prepare('DELETE FROM agent_sessions WHERE id = ?').run(sessionId).changes) > 0);
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* Replaces only transcript-derived, run-less history. Managed Run turns are
|
|
426
|
-
* never touched by a vendor file scan.
|
|
427
|
-
*/
|
|
428
|
-
syncNativeTranscript(sessionId, history) {
|
|
429
|
-
const current = this.getAgentSession(sessionId);
|
|
430
|
-
if (current === undefined)
|
|
431
|
-
throw new Error('SESSION_NOT_FOUND');
|
|
432
|
-
const checkpoint = this.raw
|
|
433
|
-
.prepare('SELECT digest FROM native_session_checkpoints WHERE session_id = ?')
|
|
434
|
-
.get(sessionId);
|
|
435
|
-
if (checkpoint !== undefined && stringValue(checkpoint, 'digest') === history.digest)
|
|
436
|
-
return false;
|
|
437
|
-
const now = this.now();
|
|
438
|
-
this.raw.exec('BEGIN IMMEDIATE');
|
|
439
|
-
try {
|
|
440
|
-
this.raw
|
|
441
|
-
.prepare('DELETE FROM conversation_turns WHERE session_id = ? AND run_id IS NULL')
|
|
442
|
-
.run(sessionId);
|
|
443
|
-
for (const [index, item] of history.items.entries()) {
|
|
444
|
-
if (item.kind !== 'message')
|
|
445
|
-
continue;
|
|
446
|
-
const turnId = randomUUID();
|
|
447
|
-
const itemId = randomUUID();
|
|
448
|
-
const createdAt = item.createdAt ?? now + index;
|
|
449
|
-
this.raw
|
|
450
|
-
.prepare(`INSERT INTO conversation_turns
|
|
451
|
-
(id, session_id, run_id, user_item_id, status, started_at, completed_at, created_at, updated_at)
|
|
452
|
-
VALUES (?, ?, NULL, ?, 'SUCCEEDED', ?, ?, ?, ?)`)
|
|
453
|
-
.run(turnId, sessionId, item.role === 'USER' ? itemId : null, createdAt, createdAt, createdAt, now);
|
|
454
|
-
this.raw
|
|
455
|
-
.prepare(`INSERT INTO conversation_items
|
|
456
|
-
(id, session_id, turn_id, run_id, parent_item_id, source_sequence, revision, kind, status, payload, started_at, completed_at, created_at, updated_at)
|
|
457
|
-
VALUES (?, ?, ?, NULL, NULL, ?, 0, ?, 'COMPLETED', ?, ?, ?, ?, ?)`)
|
|
458
|
-
.run(itemId, sessionId, turnId, index, item.role === 'USER' ? 'user_message' : 'assistant_message', JSON.stringify({ text: item.text, format: 'markdown', source: 'native-file' }), createdAt, createdAt, createdAt, now);
|
|
459
|
-
this.recordConversationItemChange(sessionId, itemId, 0);
|
|
460
|
-
}
|
|
461
|
-
const runnerTitle = history.title?.trim().slice(0, 160) || current.runnerTitle;
|
|
462
|
-
this.raw
|
|
463
|
-
.prepare(`UPDATE legacy_agent_sessions
|
|
464
|
-
SET runner_title = ?, title_source = CASE WHEN custom_title IS NULL THEN 'RUNNER' ELSE title_source END,
|
|
465
|
-
last_activity_at = CASE WHEN ? > last_activity_at THEN ? ELSE last_activity_at END, updated_at = ?
|
|
466
|
-
WHERE id = ?`)
|
|
467
|
-
.run(runnerTitle, now, now, now, sessionId);
|
|
468
|
-
this.raw
|
|
469
|
-
.prepare(`INSERT INTO native_session_checkpoints (session_id, digest, updated_at)
|
|
470
|
-
VALUES (?, ?, ?)
|
|
471
|
-
ON CONFLICT(session_id) DO UPDATE SET digest = excluded.digest, updated_at = excluded.updated_at`)
|
|
472
|
-
.run(sessionId, history.digest, now);
|
|
473
|
-
this.raw.exec('COMMIT');
|
|
474
|
-
return true;
|
|
475
|
-
}
|
|
476
|
-
catch (error) {
|
|
477
|
-
this.raw.exec('ROLLBACK');
|
|
478
|
-
throw error;
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
createMessageRun(input) {
|
|
482
|
-
const existing = this.raw
|
|
483
|
-
.prepare(`SELECT r.id, r.session_id, r.workspace_id, r.runner, r.status, r.recovery_state, r.version,
|
|
484
|
-
m.client_message_id, r.created_at, r.updated_at
|
|
485
|
-
FROM agent_runs r JOIN session_messages m ON m.id = r.message_id
|
|
486
|
-
WHERE m.session_id = ? AND m.client_message_id = ?`)
|
|
487
|
-
.get(input.sessionId, input.clientMessageId);
|
|
488
|
-
if (existing !== undefined)
|
|
489
|
-
return { run: run(existing, this.nodeIdProvider()), created: false };
|
|
490
|
-
const agentSession = this.getAgentSession(input.sessionId);
|
|
491
|
-
if (agentSession === undefined)
|
|
492
|
-
throw new Error('SESSION_NOT_FOUND');
|
|
493
|
-
const attachments = normalizeAttachments(input.attachments ?? []);
|
|
494
|
-
const value = {
|
|
495
|
-
id: randomUUID(),
|
|
496
|
-
sessionId: agentSession.id,
|
|
497
|
-
nodeId: this.nodeIdProvider(),
|
|
498
|
-
workspaceId: agentSession.workspaceId,
|
|
499
|
-
runner: agentSession.runner,
|
|
500
|
-
status: 'QUEUED',
|
|
501
|
-
recoveryState: 'ACTIVE',
|
|
502
|
-
version: 0,
|
|
503
|
-
clientMessageId: input.clientMessageId,
|
|
504
|
-
createdAt: this.now(),
|
|
505
|
-
updatedAt: this.now()
|
|
506
|
-
};
|
|
507
|
-
this.raw.exec('BEGIN IMMEDIATE');
|
|
508
|
-
try {
|
|
509
|
-
const messageId = randomUUID();
|
|
510
|
-
this.raw
|
|
511
|
-
.prepare(`INSERT INTO session_messages (id, session_id, client_message_id, role, content, created_at)
|
|
512
|
-
VALUES (?, ?, ?, 'USER', ?, ?)`)
|
|
513
|
-
.run(messageId, input.sessionId, input.clientMessageId, input.content, value.createdAt);
|
|
514
|
-
for (const attachment of attachments) {
|
|
515
|
-
this.raw
|
|
516
|
-
.prepare(`INSERT INTO message_attachments (id, message_id, name, mime, byte_size, data, created_at)
|
|
517
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`)
|
|
518
|
-
.run(randomUUID(), messageId, attachment.name, attachment.mime, attachment.data.length, attachment.data, value.createdAt);
|
|
519
|
-
}
|
|
520
|
-
this.raw
|
|
521
|
-
.prepare(`INSERT INTO agent_runs
|
|
522
|
-
(id, session_id, message_id, workspace_id, runner, status, recovery_state, version, created_at, updated_at)
|
|
523
|
-
VALUES (?, ?, ?, ?, ?, ?, 'ACTIVE', 0, ?, ?)`)
|
|
524
|
-
.run(value.id, value.sessionId, messageId, value.workspaceId, value.runner, value.status, value.createdAt, value.updatedAt);
|
|
525
|
-
this.raw
|
|
526
|
-
.prepare(`INSERT INTO workspace_leases (id, workspace_id, run_id, state, created_at, updated_at)
|
|
527
|
-
VALUES (?, ?, ?, 'ACTIVE', ?, ?)`)
|
|
528
|
-
.run(randomUUID(), value.workspaceId, value.id, value.createdAt, value.createdAt);
|
|
529
|
-
const turnId = randomUUID();
|
|
530
|
-
const userItemId = randomUUID();
|
|
531
|
-
this.raw
|
|
532
|
-
.prepare(`INSERT INTO conversation_turns
|
|
533
|
-
(id, session_id, run_id, user_item_id, status, model, effort, access, started_at, created_at, updated_at)
|
|
534
|
-
VALUES (?, ?, ?, ?, 'QUEUED', ?, ?, ?, NULL, ?, ?)`)
|
|
535
|
-
.run(turnId, value.sessionId, value.id, userItemId, agentSession.model, agentSession.effort, agentSession.access, value.createdAt, value.createdAt);
|
|
536
|
-
this.raw
|
|
537
|
-
.prepare(`INSERT INTO conversation_items
|
|
538
|
-
(id, session_id, turn_id, run_id, parent_item_id, source_sequence, revision, kind, status, payload, started_at, completed_at, created_at, updated_at)
|
|
539
|
-
VALUES (?, ?, ?, ?, NULL, NULL, 0, 'user_message', 'COMPLETED', ?, ?, ?, ?, ?)`)
|
|
540
|
-
.run(userItemId, value.sessionId, turnId, value.id, JSON.stringify({
|
|
541
|
-
clientMessageId: input.clientMessageId,
|
|
542
|
-
text: input.content,
|
|
543
|
-
contexts: [],
|
|
544
|
-
attachments: attachments.map(({ name, mime, data }) => ({
|
|
545
|
-
name,
|
|
546
|
-
mime,
|
|
547
|
-
byteSize: data.length
|
|
548
|
-
})),
|
|
549
|
-
delivery: 'ACCEPTED'
|
|
550
|
-
}), value.createdAt, value.createdAt, value.createdAt, value.createdAt);
|
|
551
|
-
this.recordConversationItemChange(value.sessionId, userItemId, 0);
|
|
552
|
-
this.raw
|
|
553
|
-
.prepare('UPDATE legacy_agent_sessions SET last_activity_at = ?, updated_at = ? WHERE id = ?')
|
|
554
|
-
.run(value.createdAt, value.createdAt, value.sessionId);
|
|
555
|
-
this.raw.exec('COMMIT');
|
|
556
|
-
return { run: value, created: true };
|
|
557
|
-
}
|
|
558
|
-
catch (error) {
|
|
559
|
-
this.raw.exec('ROLLBACK');
|
|
560
|
-
if (isConstraint(error))
|
|
561
|
-
throw new Error('WORKSPACE_BUSY');
|
|
562
|
-
throw error;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
getRun(id) {
|
|
566
|
-
const row = this.raw
|
|
567
|
-
.prepare(`SELECT r.id, r.session_id, r.workspace_id, r.runner, r.status, r.recovery_state, r.version,
|
|
568
|
-
m.client_message_id, r.created_at, r.updated_at
|
|
569
|
-
FROM agent_runs r JOIN session_messages m ON m.id = r.message_id WHERE r.id = ?`)
|
|
570
|
-
.get(id);
|
|
571
|
-
return row === undefined ? undefined : run(row, this.nodeIdProvider());
|
|
572
|
-
}
|
|
573
|
-
listRunsForSession(sessionId) {
|
|
574
|
-
if (this.getAgentSession(sessionId) === undefined)
|
|
575
|
-
throw new Error('SESSION_NOT_FOUND');
|
|
576
|
-
return this.raw
|
|
577
|
-
.prepare(`SELECT r.id, r.session_id, r.workspace_id, r.runner, r.status, r.recovery_state, r.version,
|
|
578
|
-
m.client_message_id, r.created_at, r.updated_at
|
|
579
|
-
FROM agent_runs r JOIN session_messages m ON m.id = r.message_id
|
|
580
|
-
WHERE r.session_id = ? ORDER BY r.created_at DESC, r.id DESC`)
|
|
581
|
-
.all(sessionId)
|
|
582
|
-
.map((row) => run(row, this.nodeIdProvider()));
|
|
583
|
-
}
|
|
584
|
-
getRunInput(id) {
|
|
585
|
-
const row = this.raw
|
|
586
|
-
.prepare('SELECT m.content FROM session_messages m JOIN agent_runs r ON r.message_id = m.id WHERE r.id = ?')
|
|
587
|
-
.get(id);
|
|
588
|
-
return row === undefined ? undefined : stringValue(row, 'content');
|
|
589
|
-
}
|
|
590
|
-
transitionRun(runId, next) {
|
|
591
|
-
const current = this.getRun(runId);
|
|
592
|
-
if (current === undefined)
|
|
593
|
-
throw new Error('RUN_NOT_FOUND');
|
|
594
|
-
if (current.recoveryState === 'LOST')
|
|
595
|
-
throw new Error('RUN_LOST');
|
|
596
|
-
if (!transitionAllowed(current.status, next))
|
|
597
|
-
throw new Error('RUN_STATE_INVALID');
|
|
598
|
-
const changed = this.raw
|
|
599
|
-
.prepare('UPDATE agent_runs SET status = ?, version = version + 1, updated_at = ? WHERE id = ? AND version = ?')
|
|
600
|
-
.run(next, this.now(), runId, current.version);
|
|
601
|
-
if (Number(changed.changes) === 0)
|
|
602
|
-
throw new Error('RUN_VERSION_CONFLICT');
|
|
603
|
-
if (terminal(next))
|
|
604
|
-
this.releaseLease(runId);
|
|
605
|
-
return this.getRun(runId);
|
|
606
|
-
}
|
|
607
|
-
appendRunEvent(input) {
|
|
608
|
-
if (this.getRun(input.runId) === undefined)
|
|
609
|
-
throw new Error('RUN_NOT_FOUND');
|
|
610
|
-
const row = this.raw
|
|
611
|
-
.prepare('SELECT MAX(sequence) AS sequence FROM run_events WHERE run_id = ?')
|
|
612
|
-
.get(input.runId);
|
|
613
|
-
const lastSequence = row['sequence'] === null ? 0 : numberValue(row, 'sequence');
|
|
614
|
-
if (input.sequence > lastSequence + 1)
|
|
615
|
-
throw new Error('EVENT_SEQUENCE_GAP');
|
|
616
|
-
const timestamp = this.now();
|
|
617
|
-
const result = this.raw
|
|
618
|
-
.prepare(`INSERT INTO run_events (run_id, sequence, event_type, payload, created_at)
|
|
619
|
-
VALUES (?, ?, ?, ?, ?) ON CONFLICT(run_id, sequence) DO NOTHING`)
|
|
620
|
-
.run(input.runId, input.sequence, input.eventType, JSON.stringify(input.payload ?? null), timestamp);
|
|
621
|
-
if (Number(result.changes) === 0)
|
|
622
|
-
return undefined;
|
|
623
|
-
if (input.status !== undefined)
|
|
624
|
-
this.transitionRun(input.runId, input.status);
|
|
625
|
-
const stored = this.raw
|
|
626
|
-
.prepare('SELECT id, run_id, sequence, event_type, payload, created_at FROM run_events WHERE run_id = ? AND sequence = ?')
|
|
627
|
-
.get(input.runId, input.sequence);
|
|
628
|
-
const value = event(stored);
|
|
629
|
-
this.projectRunEvent(value, input.status);
|
|
630
|
-
return value;
|
|
631
|
-
}
|
|
632
|
-
listRunEvents(runId, after = 0) {
|
|
633
|
-
return this.raw
|
|
634
|
-
.prepare(`SELECT id, run_id, sequence, event_type, payload, created_at FROM run_events
|
|
635
|
-
WHERE run_id = ? AND sequence > ? ORDER BY sequence ASC`)
|
|
636
|
-
.all(runId, after)
|
|
637
|
-
.map((row) => event(row));
|
|
638
|
-
}
|
|
639
|
-
/**
|
|
640
|
-
* Returns durable final item snapshots. Run events stay internal to the
|
|
641
|
-
* replay path; callers never need to reconstruct native runner payloads.
|
|
642
|
-
*/
|
|
643
|
-
listConversationTurns(input) {
|
|
644
|
-
if (this.getAgentSession(input.sessionId) === undefined)
|
|
645
|
-
throw new Error('SESSION_NOT_FOUND');
|
|
646
|
-
const limit = pageLimit(input.limit);
|
|
647
|
-
const cursor = decodeCursor(input.cursor, 'turn', input.sessionId);
|
|
648
|
-
const rows = this.raw
|
|
649
|
-
.prepare(`SELECT rowid AS cursor_id, id, session_id, run_id, user_item_id, status, model, effort, access, started_at, completed_at, created_at
|
|
650
|
-
FROM conversation_turns
|
|
651
|
-
WHERE session_id = ?
|
|
652
|
-
AND (? = 0 OR run_id IS NULL)
|
|
653
|
-
AND (? IS NULL OR rowid < ?)
|
|
654
|
-
ORDER BY rowid DESC LIMIT ?`)
|
|
655
|
-
.all(input.sessionId, input.nativeOnly === true ? 1 : 0, cursor?.value ?? null, cursor?.value ?? 0, limit + 1);
|
|
656
|
-
const page = rows.slice(0, limit);
|
|
657
|
-
const turns = page.map((row) => this.readConversationTurn(row)).reverse();
|
|
658
|
-
const last = page.at(-1);
|
|
659
|
-
return {
|
|
660
|
-
turns,
|
|
661
|
-
nextCursor: rows.length > limit && last !== undefined
|
|
662
|
-
? encodeCursor('turn', input.sessionId, numberValue(last, 'cursor_id'), '')
|
|
663
|
-
: null
|
|
664
|
-
};
|
|
665
|
-
}
|
|
666
|
-
hasNativeTranscript(sessionId) {
|
|
667
|
-
const row = this.raw
|
|
668
|
-
.prepare(`SELECT EXISTS(
|
|
669
|
-
SELECT 1 FROM native_session_checkpoints checkpoint
|
|
670
|
-
JOIN conversation_turns turn ON turn.session_id = checkpoint.session_id AND turn.run_id IS NULL
|
|
671
|
-
WHERE checkpoint.session_id = ?
|
|
672
|
-
) AS found`)
|
|
673
|
-
.get(sessionId);
|
|
674
|
-
return numberValue(row, 'found') === 1;
|
|
675
|
-
}
|
|
676
|
-
/** Session detail cursor is intentionally distinct from history paging. */
|
|
677
|
-
listConversationItems(input) {
|
|
678
|
-
if (this.getAgentSession(input.sessionId) === undefined)
|
|
679
|
-
throw new Error('SESSION_NOT_FOUND');
|
|
680
|
-
const limit = pageLimit(input.limit);
|
|
681
|
-
const cursor = decodeCursor(input.cursor, 'session-item', input.sessionId);
|
|
682
|
-
const rows = this.raw
|
|
683
|
-
.prepare(`SELECT cie.id AS cursor_id, ci.id, ci.session_id, ci.turn_id, ci.run_id, ci.parent_item_id,
|
|
684
|
-
ci.source_sequence, ci.revision, ci.kind, ci.status, ci.payload, ci.started_at, ci.completed_at
|
|
685
|
-
FROM conversation_item_events cie
|
|
686
|
-
JOIN conversation_items ci ON ci.id = cie.item_id
|
|
687
|
-
WHERE cie.session_id = ? AND (? IS NULL OR cie.id > ?)
|
|
688
|
-
ORDER BY cie.id ASC LIMIT ?`)
|
|
689
|
-
.all(input.sessionId, cursor?.value ?? null, cursor?.value ?? 0, limit + 1);
|
|
690
|
-
const page = rows.slice(0, limit);
|
|
691
|
-
const last = page.at(-1);
|
|
692
|
-
return {
|
|
693
|
-
items: page.map((row) => conversationItem(row)),
|
|
694
|
-
nextCursor: rows.length > limit && last !== undefined
|
|
695
|
-
? encodeCursor('session-item', input.sessionId, numberValue(last, 'cursor_id'), '')
|
|
696
|
-
: null
|
|
697
|
-
};
|
|
698
|
-
}
|
|
699
|
-
createApproval(input) {
|
|
700
|
-
if (this.getRun(input.runId) === undefined)
|
|
701
|
-
throw new Error('RUN_NOT_FOUND');
|
|
702
|
-
if (!Number.isSafeInteger(input.expiresAt) || input.expiresAt <= this.now())
|
|
703
|
-
throw new Error('APPROVAL_EXPIRED');
|
|
704
|
-
try {
|
|
705
|
-
this.raw
|
|
706
|
-
.prepare(`INSERT INTO approvals (id, run_id, status, payload, expires_at, created_at, updated_at)
|
|
707
|
-
VALUES (?, ?, 'PENDING', ?, ?, ?, ?)`)
|
|
708
|
-
.run(input.approvalId, input.runId, JSON.stringify(input.payload ?? null), input.expiresAt, this.now(), this.now());
|
|
709
|
-
}
|
|
710
|
-
catch (error) {
|
|
711
|
-
if (isConstraint(error))
|
|
712
|
-
throw new Error('APPROVAL_ALREADY_EXISTS');
|
|
713
|
-
throw error;
|
|
714
|
-
}
|
|
715
|
-
const result = this.getApproval(input.approvalId);
|
|
716
|
-
this.projectApproval(result);
|
|
717
|
-
return result;
|
|
718
|
-
}
|
|
719
|
-
getApproval(id) {
|
|
720
|
-
const row = this.raw
|
|
721
|
-
.prepare('SELECT id, run_id, status, payload, expires_at, created_at, decided_at FROM approvals WHERE id = ?')
|
|
722
|
-
.get(id);
|
|
723
|
-
if (row === undefined)
|
|
724
|
-
return undefined;
|
|
725
|
-
if (stringValue(row, 'status') === 'PENDING' && numberValue(row, 'expires_at') <= this.now()) {
|
|
726
|
-
return this.expireApproval(id);
|
|
727
|
-
}
|
|
728
|
-
return approval(row, this.now());
|
|
729
|
-
}
|
|
730
|
-
listApprovals(runId) {
|
|
731
|
-
return this.raw
|
|
732
|
-
.prepare('SELECT id FROM approvals WHERE run_id = ?')
|
|
733
|
-
.all(runId)
|
|
734
|
-
.map((row) => this.getApproval(stringValue(row, 'id')));
|
|
735
|
-
}
|
|
736
|
-
/** Persists an expiry so a later decision cannot resurrect an old prompt. */
|
|
737
|
-
expireApproval(id) {
|
|
738
|
-
const row = this.raw
|
|
739
|
-
.prepare('SELECT id, run_id, status, payload, expires_at, created_at, decided_at FROM approvals WHERE id = ?')
|
|
740
|
-
.get(id);
|
|
741
|
-
if (row === undefined)
|
|
742
|
-
throw new Error('APPROVAL_NOT_FOUND');
|
|
743
|
-
const storedStatus = stringValue(row, 'status');
|
|
744
|
-
if (storedStatus !== 'PENDING')
|
|
745
|
-
return approval(row, this.now());
|
|
746
|
-
if (numberValue(row, 'expires_at') > this.now())
|
|
747
|
-
throw new Error('APPROVAL_NOT_EXPIRED');
|
|
748
|
-
this.raw
|
|
749
|
-
.prepare(`UPDATE approvals SET status = 'EXPIRED', decided_at = ?, updated_at = ?
|
|
750
|
-
WHERE id = ? AND status = 'PENDING' AND expires_at <= ?`)
|
|
751
|
-
.run(this.now(), this.now(), id, this.now());
|
|
752
|
-
const result = this.getApproval(id);
|
|
753
|
-
this.projectApproval(result);
|
|
754
|
-
return result;
|
|
755
|
-
}
|
|
756
|
-
expireDueApprovals() {
|
|
757
|
-
const rows = this.raw
|
|
758
|
-
.prepare("SELECT id FROM approvals WHERE status = 'PENDING' AND expires_at <= ?")
|
|
759
|
-
.all(this.now());
|
|
760
|
-
return rows.map((row) => this.expireApproval(stringValue(row, 'id')));
|
|
761
|
-
}
|
|
762
|
-
decideApproval(id, decision) {
|
|
763
|
-
const current = this.getApproval(id);
|
|
764
|
-
if (current === undefined)
|
|
765
|
-
throw new Error('APPROVAL_NOT_FOUND');
|
|
766
|
-
if (current.status === 'EXPIRED')
|
|
767
|
-
throw new Error('APPROVAL_EXPIRED');
|
|
768
|
-
if (current.status !== 'PENDING')
|
|
769
|
-
throw new Error('APPROVAL_ALREADY_DECIDED');
|
|
770
|
-
const changed = this.raw
|
|
771
|
-
.prepare(`UPDATE approvals SET status = ?, decided_at = ?, updated_at = ?
|
|
772
|
-
WHERE id = ? AND status = 'PENDING' AND expires_at > ?`)
|
|
773
|
-
.run(decision, this.now(), this.now(), id, this.now());
|
|
774
|
-
if (Number(changed.changes) === 0) {
|
|
775
|
-
if (this.getApproval(id)?.status === 'EXPIRED')
|
|
776
|
-
throw new Error('APPROVAL_EXPIRED');
|
|
777
|
-
throw new Error('APPROVAL_ALREADY_DECIDED');
|
|
778
|
-
}
|
|
779
|
-
const result = this.getApproval(id);
|
|
780
|
-
this.projectApproval(result);
|
|
781
|
-
return result;
|
|
782
|
-
}
|
|
783
|
-
listNonterminalRuns() {
|
|
784
|
-
return this.raw
|
|
785
|
-
.prepare(`SELECT r.id, r.session_id, r.workspace_id, r.runner, r.status, r.recovery_state, r.version,
|
|
786
|
-
m.client_message_id, r.created_at, r.updated_at
|
|
787
|
-
FROM agent_runs r JOIN session_messages m ON m.id = r.message_id
|
|
788
|
-
WHERE r.status NOT IN ('SUCCEEDED', 'FAILED', 'CANCELLED', 'INTERRUPTED')
|
|
789
|
-
ORDER BY r.created_at ASC`)
|
|
790
|
-
.all()
|
|
791
|
-
.map((row) => run(row, this.nodeIdProvider()));
|
|
792
|
-
}
|
|
793
|
-
lastRunSequence(runId) {
|
|
794
|
-
const row = this.raw
|
|
795
|
-
.prepare('SELECT MAX(sequence) AS sequence FROM run_events WHERE run_id = ?')
|
|
796
|
-
.get(runId);
|
|
797
|
-
return row['sequence'] === null ? 0 : numberValue(row, 'sequence');
|
|
798
|
-
}
|
|
799
|
-
markActiveRunsSuspect() {
|
|
800
|
-
this.raw
|
|
801
|
-
.prepare("UPDATE agent_runs SET recovery_state = 'SUSPECT', recovery_updated_at = ? WHERE status NOT IN ('SUCCEEDED', 'FAILED', 'CANCELLED', 'INTERRUPTED')")
|
|
802
|
-
.run(this.now());
|
|
803
|
-
this.raw
|
|
804
|
-
.prepare("UPDATE workspace_leases SET state = 'SUSPECT', updated_at = ? WHERE state = 'ACTIVE'")
|
|
805
|
-
.run(this.now());
|
|
806
|
-
}
|
|
807
|
-
hasActiveWorkspaceLease(workspaceId) {
|
|
808
|
-
const row = this.raw
|
|
809
|
-
.prepare("SELECT 1 AS present FROM workspace_leases WHERE workspace_id = ? AND state IN ('ACTIVE', 'SUSPECT') LIMIT 1")
|
|
810
|
-
.get(workspaceId);
|
|
811
|
-
return row !== undefined;
|
|
812
|
-
}
|
|
813
|
-
reconcileRun(runId, active) {
|
|
814
|
-
const current = this.getRun(runId);
|
|
815
|
-
if (current === undefined || terminal(current.status))
|
|
816
|
-
return;
|
|
817
|
-
if (active) {
|
|
818
|
-
this.raw
|
|
819
|
-
.prepare("UPDATE agent_runs SET recovery_state = 'ACTIVE', recovery_updated_at = ? WHERE id = ?")
|
|
820
|
-
.run(this.now(), runId);
|
|
821
|
-
this.raw
|
|
822
|
-
.prepare("UPDATE workspace_leases SET state = 'ACTIVE', updated_at = ? WHERE run_id = ? AND state = 'SUSPECT'")
|
|
823
|
-
.run(this.now(), runId);
|
|
824
|
-
return;
|
|
825
|
-
}
|
|
826
|
-
this.raw
|
|
827
|
-
.prepare("UPDATE agent_runs SET recovery_state = 'LOST', recovery_updated_at = ? WHERE id = ?")
|
|
828
|
-
.run(this.now(), runId);
|
|
829
|
-
this.releaseLease(runId);
|
|
830
|
-
}
|
|
831
|
-
releaseLease(runId) {
|
|
832
|
-
this.raw
|
|
833
|
-
.prepare("UPDATE workspace_leases SET state = 'RELEASED', updated_at = ? WHERE run_id = ? AND state IN ('ACTIVE', 'SUSPECT')")
|
|
834
|
-
.run(this.now(), runId);
|
|
835
|
-
}
|
|
836
|
-
recordConversationItemChange(sessionId, itemId, revision) {
|
|
837
|
-
this.raw
|
|
838
|
-
.prepare(`INSERT INTO conversation_item_events (session_id, item_id, revision, created_at)
|
|
839
|
-
VALUES (?, ?, ?, ?)`)
|
|
840
|
-
.run(sessionId, itemId, revision, this.now());
|
|
841
|
-
}
|
|
842
|
-
projectApproval(value) {
|
|
843
|
-
const turn = this.raw
|
|
844
|
-
.prepare('SELECT id, session_id FROM conversation_turns WHERE run_id = ?')
|
|
845
|
-
.get(value.runId);
|
|
846
|
-
if (turn === undefined)
|
|
847
|
-
return;
|
|
848
|
-
const sessionId = stringValue(turn, 'session_id');
|
|
849
|
-
const turnId = stringValue(turn, 'id');
|
|
850
|
-
const status = value.status === 'PENDING'
|
|
851
|
-
? 'PENDING'
|
|
852
|
-
: value.status === 'APPROVED'
|
|
853
|
-
? 'COMPLETED'
|
|
854
|
-
: 'DECLINED';
|
|
855
|
-
const payload = value.payload;
|
|
856
|
-
const source = typeof payload?.method === 'string' ? payload.method : payload?.toolName;
|
|
857
|
-
const category = source === 'item/commandExecution/requestApproval' || source === 'Bash'
|
|
858
|
-
? 'COMMAND'
|
|
859
|
-
: source === 'item/fileChange/requestApproval'
|
|
860
|
-
? 'FILE_CHANGE'
|
|
861
|
-
: 'TOOL';
|
|
862
|
-
const timestamp = this.now();
|
|
863
|
-
this.raw
|
|
864
|
-
.prepare(`INSERT INTO conversation_items
|
|
865
|
-
(id, session_id, turn_id, run_id, parent_item_id, source_sequence, revision, kind, status, payload, started_at, completed_at, created_at, updated_at)
|
|
866
|
-
VALUES (?, ?, ?, ?, NULL, NULL, 0, 'approval', ?, ?, ?, ?, ?, ?)
|
|
867
|
-
ON CONFLICT(id) DO UPDATE SET revision = conversation_items.revision + 1,
|
|
868
|
-
status = excluded.status, payload = excluded.payload, completed_at = excluded.completed_at, updated_at = excluded.updated_at`)
|
|
869
|
-
.run(value.id, sessionId, turnId, value.runId, status, JSON.stringify({
|
|
870
|
-
approvalId: value.id,
|
|
871
|
-
category,
|
|
872
|
-
reason: null,
|
|
873
|
-
expiresAt: value.expiresAt,
|
|
874
|
-
resolvedDecision: value.status === 'PENDING' ? null : value.status
|
|
875
|
-
}), value.createdAt, value.status === 'PENDING' ? null : timestamp, value.createdAt, timestamp);
|
|
876
|
-
const item = this.raw
|
|
877
|
-
.prepare('SELECT revision FROM conversation_items WHERE id = ?')
|
|
878
|
-
.get(value.id);
|
|
879
|
-
this.recordConversationItemChange(sessionId, value.id, numberValue(item, 'revision'));
|
|
880
|
-
}
|
|
881
|
-
readConversationTurn(row) {
|
|
882
|
-
const turnId = stringValue(row, 'id');
|
|
883
|
-
const items = this.raw
|
|
884
|
-
.prepare(`SELECT id, session_id, turn_id, run_id, parent_item_id, source_sequence, revision, kind, status, payload, started_at, completed_at
|
|
885
|
-
FROM conversation_items WHERE turn_id = ?
|
|
886
|
-
ORDER BY source_sequence IS NOT NULL, source_sequence ASC, created_at ASC, id ASC`)
|
|
887
|
-
.all(turnId)
|
|
888
|
-
.map((item) => conversationItem(item));
|
|
889
|
-
return {
|
|
890
|
-
id: turnId,
|
|
891
|
-
sessionId: stringValue(row, 'session_id'),
|
|
892
|
-
runId: nullableString(row, 'run_id'),
|
|
893
|
-
userItemId: nullableString(row, 'user_item_id'),
|
|
894
|
-
status: stringValue(row, 'status'),
|
|
895
|
-
model: nullableString(row, 'model'),
|
|
896
|
-
effort: nullableString(row, 'effort'),
|
|
897
|
-
access: nullableString(row, 'access'),
|
|
898
|
-
items,
|
|
899
|
-
startedAt: nullableNumber(row, 'started_at'),
|
|
900
|
-
completedAt: nullableNumber(row, 'completed_at')
|
|
901
|
-
};
|
|
902
|
-
}
|
|
903
|
-
projectRunEvent(event, status) {
|
|
904
|
-
const turn = this.raw
|
|
905
|
-
.prepare('SELECT id, session_id, started_at FROM conversation_turns WHERE run_id = ?')
|
|
906
|
-
.get(event.runId);
|
|
907
|
-
if (turn === undefined)
|
|
908
|
-
return;
|
|
909
|
-
const turnId = stringValue(turn, 'id');
|
|
910
|
-
const sessionId = stringValue(turn, 'session_id');
|
|
911
|
-
const timestamp = this.now();
|
|
912
|
-
const payload = event.payload;
|
|
913
|
-
if ((event.eventType === 'text' || event.eventType === 'text.delta') &&
|
|
914
|
-
typeof payload?.text === 'string') {
|
|
915
|
-
const itemId = `${event.runId}:assistant`;
|
|
916
|
-
const existing = this.raw
|
|
917
|
-
.prepare('SELECT payload, revision FROM conversation_items WHERE id = ?')
|
|
918
|
-
.get(itemId);
|
|
919
|
-
const previous = existing === undefined
|
|
920
|
-
? ''
|
|
921
|
-
: (JSON.parse(stringValue(existing, 'payload')).text ?? '');
|
|
922
|
-
const text = `${typeof previous === 'string' ? previous : ''}${payload.text}`;
|
|
923
|
-
const revision = existing === undefined ? 0 : numberValue(existing, 'revision') + 1;
|
|
924
|
-
this.raw
|
|
925
|
-
.prepare(`INSERT INTO conversation_items
|
|
926
|
-
(id, session_id, turn_id, run_id, parent_item_id, source_sequence, revision, kind, status, payload, started_at, completed_at, created_at, updated_at)
|
|
927
|
-
VALUES (?, ?, ?, ?, NULL, ?, ?, 'assistant_message', 'IN_PROGRESS', ?, ?, NULL, ?, ?)
|
|
928
|
-
ON CONFLICT(id) DO UPDATE SET source_sequence = excluded.source_sequence, revision = excluded.revision,
|
|
929
|
-
payload = excluded.payload, updated_at = excluded.updated_at`)
|
|
930
|
-
.run(itemId, sessionId, turnId, event.runId, event.sequence, revision, JSON.stringify({ text, format: 'markdown', model: null }), timestamp, timestamp, timestamp);
|
|
931
|
-
this.recordConversationItemChange(sessionId, itemId, revision);
|
|
932
|
-
}
|
|
933
|
-
if (event.eventType === 'tool' && typeof payload?.name === 'string') {
|
|
934
|
-
this.raw
|
|
935
|
-
.prepare(`INSERT INTO conversation_items
|
|
936
|
-
(id, session_id, turn_id, run_id, parent_item_id, source_sequence, revision, kind, status, payload, started_at, completed_at, created_at, updated_at)
|
|
937
|
-
VALUES (?, ?, ?, ?, NULL, ?, 0, 'tool_call', 'COMPLETED', ?, ?, ?, ?, ?)`)
|
|
938
|
-
.run(`${event.runId}:tool:${event.sequence}`, sessionId, turnId, event.runId, event.sequence, JSON.stringify({
|
|
939
|
-
namespace: 'runner',
|
|
940
|
-
toolName: payload.name,
|
|
941
|
-
title: payload.name,
|
|
942
|
-
inputSummary: payload.input === undefined ? null : JSON.stringify(payload.input),
|
|
943
|
-
outputSummary: null,
|
|
944
|
-
progressLabel: null,
|
|
945
|
-
errorCode: null,
|
|
946
|
-
truncated: false
|
|
947
|
-
}), timestamp, timestamp, timestamp, timestamp);
|
|
948
|
-
this.recordConversationItemChange(sessionId, `${event.runId}:tool:${event.sequence}`, 0);
|
|
949
|
-
}
|
|
950
|
-
if (status !== undefined) {
|
|
951
|
-
const turnStatus = status === 'SUCCEEDED'
|
|
952
|
-
? 'SUCCEEDED'
|
|
953
|
-
: status === 'FAILED'
|
|
954
|
-
? 'FAILED'
|
|
955
|
-
: status === 'CANCELLED'
|
|
956
|
-
? 'CANCELLED'
|
|
957
|
-
: status === 'INTERRUPTED'
|
|
958
|
-
? 'INTERRUPTED'
|
|
959
|
-
: status === 'STARTING' || status === 'RUNNING'
|
|
960
|
-
? 'RUNNING'
|
|
961
|
-
: 'QUEUED';
|
|
962
|
-
const complete = terminal(status);
|
|
963
|
-
this.raw
|
|
964
|
-
.prepare('UPDATE conversation_turns SET status = ?, started_at = COALESCE(started_at, ?), completed_at = ?, updated_at = ? WHERE id = ?')
|
|
965
|
-
.run(turnStatus, timestamp, complete ? timestamp : null, timestamp, turnId);
|
|
966
|
-
if (complete) {
|
|
967
|
-
const pendingItems = this.raw
|
|
968
|
-
.prepare("SELECT id FROM conversation_items WHERE turn_id = ? AND status IN ('PENDING', 'IN_PROGRESS')")
|
|
969
|
-
.all(turnId);
|
|
970
|
-
this.raw
|
|
971
|
-
.prepare("UPDATE conversation_items SET status = ?, revision = revision + 1, completed_at = ?, updated_at = ? WHERE turn_id = ? AND status IN ('PENDING', 'IN_PROGRESS')")
|
|
972
|
-
.run(status === 'SUCCEEDED'
|
|
973
|
-
? 'COMPLETED'
|
|
974
|
-
: status === 'FAILED'
|
|
975
|
-
? 'FAILED'
|
|
976
|
-
: status === 'CANCELLED'
|
|
977
|
-
? 'CANCELLED'
|
|
978
|
-
: 'INTERRUPTED', timestamp, timestamp, turnId);
|
|
979
|
-
for (const item of pendingItems) {
|
|
980
|
-
const itemId = stringValue(item, 'id');
|
|
981
|
-
const current = this.raw
|
|
982
|
-
.prepare('SELECT revision FROM conversation_items WHERE id = ?')
|
|
983
|
-
.get(itemId);
|
|
984
|
-
this.recordConversationItemChange(sessionId, itemId, numberValue(current, 'revision'));
|
|
985
|
-
}
|
|
986
|
-
const summaryId = `${event.runId}:summary`;
|
|
987
|
-
const startedAt = nullableNumber(turn, 'started_at');
|
|
988
|
-
const durationMs = startedAt === null ? null : Math.max(0, timestamp - startedAt);
|
|
989
|
-
this.raw
|
|
990
|
-
.prepare(`INSERT INTO conversation_items
|
|
991
|
-
(id, session_id, turn_id, run_id, parent_item_id, source_sequence, revision, kind, status, payload, started_at, completed_at, created_at, updated_at)
|
|
992
|
-
VALUES (?, ?, ?, ?, NULL, ?, 0, 'turn_summary', 'COMPLETED', ?, ?, ?, ?, ?)
|
|
993
|
-
ON CONFLICT(id) DO UPDATE SET revision = conversation_items.revision + 1,
|
|
994
|
-
status = excluded.status, payload = excluded.payload, completed_at = excluded.completed_at, updated_at = excluded.updated_at`)
|
|
995
|
-
.run(summaryId, sessionId, turnId, event.runId, event.sequence, JSON.stringify({ status, durationMs }), startedAt ?? timestamp, timestamp, timestamp, timestamp);
|
|
996
|
-
const summary = this.raw
|
|
997
|
-
.prepare('SELECT revision FROM conversation_items WHERE id = ?')
|
|
998
|
-
.get(summaryId);
|
|
999
|
-
this.recordConversationItemChange(sessionId, summaryId, numberValue(summary, 'revision'));
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
this.raw
|
|
1003
|
-
.prepare('UPDATE legacy_agent_sessions SET last_activity_at = ?, updated_at = ? WHERE id = ?')
|
|
1004
|
-
.run(timestamp, timestamp, sessionId);
|
|
1005
|
-
}
|
|
1006
|
-
nodeIdProvider;
|
|
1007
|
-
}
|
|
1008
|
-
function migrate(database) {
|
|
1009
|
-
const existingApplicationTables = database
|
|
1010
|
-
.prepare("SELECT COUNT(*) AS count FROM sqlite_master WHERE type = 'table' AND name IN ('workspaces', 'agent_sessions', 'runner_defaults')")
|
|
1011
|
-
.get();
|
|
1012
|
-
const existingMigrationTable = database
|
|
1013
|
-
.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'node_schema_migrations'")
|
|
1014
|
-
.get();
|
|
1015
|
-
const existingMigrationRows = existingMigrationTable === undefined
|
|
1016
|
-
? 0
|
|
1017
|
-
: numberValue(database.prepare('SELECT COUNT(*) AS count FROM node_schema_migrations').get(), 'count');
|
|
1018
|
-
let currentUnversionedSchema = false;
|
|
1019
|
-
if (numberValue(existingApplicationTables, 'count') > 0 && existingMigrationRows === 0) {
|
|
1020
|
-
try {
|
|
1021
|
-
assertNodeSchemaV2(database);
|
|
1022
|
-
currentUnversionedSchema = true;
|
|
1023
|
-
}
|
|
1024
|
-
catch {
|
|
1025
|
-
assertNodeSchema(database);
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1028
|
-
if (currentUnversionedSchema) {
|
|
1029
|
-
database.exec('BEGIN IMMEDIATE');
|
|
1030
|
-
try {
|
|
1031
|
-
database
|
|
1032
|
-
.prepare('INSERT INTO node_schema_migrations (version, applied_at) VALUES (?, ?), (?, ?)')
|
|
1033
|
-
.run(1, Date.now(), 2, Date.now());
|
|
1034
|
-
database.exec('COMMIT');
|
|
1035
|
-
migrateNodeSchemaV3(database);
|
|
1036
|
-
assertNodeSchemaV3(database);
|
|
1037
|
-
migrateNodeSchemaV4(database);
|
|
1038
|
-
assertNodeSchemaV4(database);
|
|
1039
|
-
return;
|
|
1040
|
-
}
|
|
1041
|
-
catch (error) {
|
|
1042
|
-
database.exec('ROLLBACK');
|
|
1043
|
-
throw error;
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
if (numberValue(existingApplicationTables, 'count') === 0)
|
|
1047
|
-
database.exec(NODE_SCHEMA_V1);
|
|
1048
|
-
const migrations = database
|
|
1049
|
-
.prepare('SELECT version FROM node_schema_migrations ORDER BY version')
|
|
1050
|
-
.all();
|
|
1051
|
-
const versions = migrations.map((row) => numberValue(row, 'version'));
|
|
1052
|
-
const current = versions.at(-1) ?? 0;
|
|
1053
|
-
if (versions.some((version) => version > NODE_SCHEMA_VERSION))
|
|
1054
|
-
throw new Error('NODE_DATABASE_VERSION_UNSUPPORTED');
|
|
1055
|
-
if (versions.some((version, index) => version !== index + 1))
|
|
1056
|
-
throw new Error('NODE_DATABASE_MIGRATION_HISTORY_INVALID');
|
|
1057
|
-
const hasApplicationTables = database
|
|
1058
|
-
.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name IN ('workspaces', 'agent_sessions', 'runner_defaults') LIMIT 1")
|
|
1059
|
-
.get();
|
|
1060
|
-
if (current === 0 && hasApplicationTables !== undefined) {
|
|
1061
|
-
assertNodeSchema(database);
|
|
1062
|
-
database.exec('BEGIN IMMEDIATE');
|
|
1063
|
-
try {
|
|
1064
|
-
database
|
|
1065
|
-
.prepare('INSERT INTO node_schema_migrations (version, applied_at) VALUES (?, ?)')
|
|
1066
|
-
.run(1, Date.now());
|
|
1067
|
-
database.exec('COMMIT');
|
|
1068
|
-
}
|
|
1069
|
-
catch (error) {
|
|
1070
|
-
database.exec('ROLLBACK');
|
|
1071
|
-
throw error;
|
|
1072
|
-
}
|
|
1073
|
-
migrateNodeSchemaV2(database);
|
|
1074
|
-
assertNodeSchemaV2(database);
|
|
1075
|
-
migrateNodeSchemaV3(database);
|
|
1076
|
-
assertNodeSchemaV3(database);
|
|
1077
|
-
migrateNodeSchemaV4(database);
|
|
1078
|
-
assertNodeSchemaV4(database);
|
|
1079
|
-
return;
|
|
1080
|
-
}
|
|
1081
|
-
if (current === 0) {
|
|
1082
|
-
database.exec('BEGIN IMMEDIATE');
|
|
1083
|
-
try {
|
|
1084
|
-
database.exec('CREATE TABLE IF NOT EXISTS node_schema_migrations (version INTEGER PRIMARY KEY, applied_at INTEGER NOT NULL) STRICT');
|
|
1085
|
-
database
|
|
1086
|
-
.prepare('INSERT INTO node_schema_migrations (version, applied_at) VALUES (?, ?)')
|
|
1087
|
-
.run(1, Date.now());
|
|
1088
|
-
database.exec('COMMIT');
|
|
1089
|
-
}
|
|
1090
|
-
catch (error) {
|
|
1091
|
-
database.exec('ROLLBACK');
|
|
1092
|
-
throw error;
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
const afterBaseline = database
|
|
1096
|
-
.prepare('SELECT MAX(version) AS version FROM node_schema_migrations')
|
|
1097
|
-
.get();
|
|
1098
|
-
if (numberValue(afterBaseline, 'version') === 1)
|
|
1099
|
-
migrateNodeSchemaV2(database);
|
|
1100
|
-
const afterV2 = database
|
|
1101
|
-
.prepare('SELECT MAX(version) AS version FROM node_schema_migrations')
|
|
1102
|
-
.get();
|
|
1103
|
-
if (numberValue(afterV2, 'version') === 2)
|
|
1104
|
-
migrateNodeSchemaV3(database);
|
|
1105
|
-
const afterV3 = database
|
|
1106
|
-
.prepare('SELECT MAX(version) AS version FROM node_schema_migrations')
|
|
1107
|
-
.get();
|
|
1108
|
-
if (numberValue(afterV3, 'version') === 3)
|
|
1109
|
-
migrateNodeSchemaV4(database);
|
|
1110
|
-
assertNodeSchemaV3(database);
|
|
1111
|
-
assertNodeSchemaV4(database);
|
|
1112
|
-
}
|
|
1113
|
-
function mcpInstallation(row) {
|
|
1114
|
-
const runtime = mcpRuntimeDescriptorSchema.parse(JSON.parse(stringValue(row, 'runtime')));
|
|
1115
|
-
const configuration = mcpInstallationConfigurationSchema.parse(JSON.parse(stringValue(row, 'configuration')));
|
|
1116
|
-
return {
|
|
1117
|
-
targetKind: stringValue(row, 'target_kind'),
|
|
1118
|
-
targetId: stringValue(row, 'target_id'),
|
|
1119
|
-
catalogEntryId: stringValue(row, 'catalog_entry_id'),
|
|
1120
|
-
serverName: stringValue(row, 'server_name'),
|
|
1121
|
-
displayName: stringValue(row, 'display_name'),
|
|
1122
|
-
version: stringValue(row, 'version'),
|
|
1123
|
-
enabled: numberValue(row, 'enabled') === 1,
|
|
1124
|
-
runtime,
|
|
1125
|
-
configuration,
|
|
1126
|
-
installedAt: numberValue(row, 'installed_at')
|
|
1127
|
-
};
|
|
1128
|
-
}
|
|
1129
|
-
function sessionMetadata(row) {
|
|
1130
|
-
const raw = JSON.parse(stringValue(row, 'metadata'));
|
|
1131
|
-
if (raw['version'] !== 1)
|
|
1132
|
-
throw new Error('SESSION_METADATA_VERSION_UNSUPPORTED');
|
|
1133
|
-
const value = (key) => typeof raw[key] === 'string' ? raw[key] : null;
|
|
1134
|
-
return {
|
|
1135
|
-
customTitle: value('customTitle'),
|
|
1136
|
-
runnerTitle: value('runnerTitle'),
|
|
1137
|
-
runnerTitlePending: raw['runnerTitlePending'] === true,
|
|
1138
|
-
model: value('model'),
|
|
1139
|
-
effort: value('effort'),
|
|
1140
|
-
access: value('access')
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
/**
|
|
1144
|
-
* Legacy database helpers are still used by focused lifecycle tests, but the
|
|
1145
|
-
* product runtime lives in NodeRuntimeState. Keep those helpers explicitly
|
|
1146
|
-
* process-local so no Session/Run/Conversation state reaches the Node file.
|
|
1147
|
-
*/
|
|
1148
|
-
function initializeEphemeralRuntimeTables(database) {
|
|
1149
|
-
const runtimeTables = new Set([
|
|
1150
|
-
'agent_sessions',
|
|
1151
|
-
'native_session_checkpoints',
|
|
1152
|
-
'session_messages',
|
|
1153
|
-
'message_attachments',
|
|
1154
|
-
'agent_runs',
|
|
1155
|
-
'run_events',
|
|
1156
|
-
'conversation_turns',
|
|
1157
|
-
'conversation_items',
|
|
1158
|
-
'conversation_item_events',
|
|
1159
|
-
'approvals',
|
|
1160
|
-
'workspace_leases'
|
|
1161
|
-
]);
|
|
1162
|
-
for (const raw of NODE_SCHEMA_V1.split(';')) {
|
|
1163
|
-
const statement = raw.trim();
|
|
1164
|
-
const match = statement.match(/^CREATE TABLE IF NOT EXISTS ([a-z_]+)/);
|
|
1165
|
-
if (match === null || !runtimeTables.has(match[1] ?? ''))
|
|
1166
|
-
continue;
|
|
1167
|
-
database.exec(statement
|
|
1168
|
-
.replaceAll("runner IN ('codex', 'claude-code')", "runner IN ('codex', 'claude-code', 'opencode')")
|
|
1169
|
-
.replace(/^CREATE TABLE IF NOT EXISTS/, 'CREATE TEMP TABLE IF NOT EXISTS')
|
|
1170
|
-
.replace('CREATE TEMP TABLE IF NOT EXISTS agent_sessions', 'CREATE TEMP TABLE IF NOT EXISTS legacy_agent_sessions')
|
|
1171
|
-
.replaceAll('REFERENCES agent_sessions', 'REFERENCES legacy_agent_sessions')
|
|
1172
|
-
.replaceAll(/ REFERENCES workspaces\(id\)(?: ON DELETE (?:CASCADE|SET NULL))?/g, '') + ';');
|
|
1173
|
-
}
|
|
1174
|
-
database.exec(`CREATE UNIQUE INDEX IF NOT EXISTS temp.workspace_leases_active_workspace_idx
|
|
1175
|
-
ON workspace_leases(workspace_id) WHERE state IN ('ACTIVE', 'SUSPECT')`);
|
|
1176
|
-
}
|
|
1177
|
-
function acquireNodeMigrationLock(databasePath) {
|
|
1178
|
-
if (databasePath === ':memory:')
|
|
1179
|
-
return () => undefined;
|
|
1180
|
-
const lockPath = `${databasePath}.migration.lock`;
|
|
1181
|
-
const deadline = Date.now() + 5_000;
|
|
1182
|
-
while (true) {
|
|
1183
|
-
try {
|
|
1184
|
-
const descriptor = openSync(lockPath, 'wx', 0o600);
|
|
1185
|
-
return () => {
|
|
1186
|
-
closeSync(descriptor);
|
|
1187
|
-
if (existsSync(lockPath))
|
|
1188
|
-
rmSync(lockPath);
|
|
1189
|
-
};
|
|
1190
|
-
}
|
|
1191
|
-
catch (error) {
|
|
1192
|
-
const code = error instanceof Error && 'code' in error ? error.code : undefined;
|
|
1193
|
-
if (code !== 'EEXIST' || Date.now() >= deadline)
|
|
1194
|
-
throw new Error('NODE_DATABASE_MIGRATION_LOCK_UNAVAILABLE');
|
|
1195
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 50);
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
function workspace(row) {
|
|
1200
|
-
const summary = nullableString(row, 'git_summary');
|
|
1201
|
-
return {
|
|
1202
|
-
id: stringValue(row, 'id'),
|
|
1203
|
-
path: stringValue(row, 'path'),
|
|
1204
|
-
kind: stringValue(row, 'kind'),
|
|
1205
|
-
gitSummary: summary === null ? null : JSON.parse(summary)
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
function terminalSession(row) {
|
|
1209
|
-
const state = stringValue(row, 'state');
|
|
1210
|
-
if (state !== 'RUNNING' && state !== 'EXITED' && state !== 'CLOSED')
|
|
1211
|
-
throw new Error('DATABASE_VALUE_INVALID:terminal_state');
|
|
1212
|
-
return {
|
|
1213
|
-
id: stringValue(row, 'id'),
|
|
1214
|
-
workspaceId: nullableString(row, 'workspace_id'),
|
|
1215
|
-
profileId: stringValue(row, 'profile_id'),
|
|
1216
|
-
state,
|
|
1217
|
-
exitCode: nullableNumber(row, 'exit_code'),
|
|
1218
|
-
rows: numberValue(row, 'rows'),
|
|
1219
|
-
cols: numberValue(row, 'cols'),
|
|
1220
|
-
latestSequence: numberValue(row, 'latest_sequence'),
|
|
1221
|
-
createdAt: numberValue(row, 'created_at'),
|
|
1222
|
-
updatedAt: numberValue(row, 'updated_at')
|
|
1223
|
-
};
|
|
1224
|
-
}
|
|
1225
|
-
function session(row, nodeId) {
|
|
1226
|
-
return {
|
|
1227
|
-
id: stringValue(row, 'id'),
|
|
1228
|
-
nodeId,
|
|
1229
|
-
workspaceId: stringValue(row, 'workspace_id'),
|
|
1230
|
-
runner: stringValue(row, 'runner'),
|
|
1231
|
-
externalSessionId: nullableString(row, 'external_session_id'),
|
|
1232
|
-
nativeControl: stringValue(row, 'native_control') === 'MAR_MANAGED' ? 'MAR_MANAGED' : 'EXTERNAL',
|
|
1233
|
-
channelToken: nullableString(row, 'channel_token'),
|
|
1234
|
-
cwd: stringValue(row, 'cwd'),
|
|
1235
|
-
model: nullableString(row, 'model'),
|
|
1236
|
-
effort: nullableString(row, 'effort'),
|
|
1237
|
-
access: nullableString(row, 'access'),
|
|
1238
|
-
customTitle: nullableString(row, 'custom_title'),
|
|
1239
|
-
runnerTitle: nullableString(row, 'runner_title'),
|
|
1240
|
-
pinnedAt: row['pinned_at'] === null ? null : numberValue(row, 'pinned_at'),
|
|
1241
|
-
titleSource: stringValue(row, 'title_source') === 'CUSTOM'
|
|
1242
|
-
? 'CUSTOM'
|
|
1243
|
-
: stringValue(row, 'title_source') === 'RUNNER'
|
|
1244
|
-
? 'RUNNER'
|
|
1245
|
-
: 'AUTO',
|
|
1246
|
-
lastActivityAt: numberValue(row, 'last_activity_at'),
|
|
1247
|
-
createdAt: numberValue(row, 'created_at')
|
|
1248
|
-
};
|
|
1249
|
-
}
|
|
1250
|
-
function run(row, nodeId) {
|
|
1251
|
-
const recovery = stringValue(row, 'recovery_state');
|
|
1252
|
-
return {
|
|
1253
|
-
id: stringValue(row, 'id'),
|
|
1254
|
-
sessionId: stringValue(row, 'session_id'),
|
|
1255
|
-
nodeId,
|
|
1256
|
-
workspaceId: stringValue(row, 'workspace_id'),
|
|
1257
|
-
runner: stringValue(row, 'runner'),
|
|
1258
|
-
status: stringValue(row, 'status'),
|
|
1259
|
-
recoveryState: recovery === 'SUSPECT' || recovery === 'LOST' ? recovery : 'ACTIVE',
|
|
1260
|
-
version: numberValue(row, 'version'),
|
|
1261
|
-
clientMessageId: stringValue(row, 'client_message_id'),
|
|
1262
|
-
createdAt: numberValue(row, 'created_at'),
|
|
1263
|
-
updatedAt: numberValue(row, 'updated_at')
|
|
1264
|
-
};
|
|
1265
|
-
}
|
|
1266
|
-
function event(row) {
|
|
1267
|
-
return {
|
|
1268
|
-
id: numberValue(row, 'id'),
|
|
1269
|
-
runId: stringValue(row, 'run_id'),
|
|
1270
|
-
sequence: numberValue(row, 'sequence'),
|
|
1271
|
-
eventType: stringValue(row, 'event_type'),
|
|
1272
|
-
payload: JSON.parse(stringValue(row, 'payload')),
|
|
1273
|
-
createdAt: numberValue(row, 'created_at')
|
|
1274
|
-
};
|
|
1275
|
-
}
|
|
1276
|
-
function conversationItem(row) {
|
|
1277
|
-
return {
|
|
1278
|
-
id: stringValue(row, 'id'),
|
|
1279
|
-
sessionId: stringValue(row, 'session_id'),
|
|
1280
|
-
turnId: stringValue(row, 'turn_id'),
|
|
1281
|
-
runId: nullableString(row, 'run_id'),
|
|
1282
|
-
parentItemId: nullableString(row, 'parent_item_id'),
|
|
1283
|
-
sourceSequence: nullableNumber(row, 'source_sequence'),
|
|
1284
|
-
revision: numberValue(row, 'revision'),
|
|
1285
|
-
kind: stringValue(row, 'kind'),
|
|
1286
|
-
status: stringValue(row, 'status'),
|
|
1287
|
-
payload: JSON.parse(stringValue(row, 'payload')),
|
|
1288
|
-
startedAt: nullableNumber(row, 'started_at'),
|
|
1289
|
-
completedAt: nullableNumber(row, 'completed_at')
|
|
1290
|
-
};
|
|
1291
|
-
}
|
|
1292
|
-
function pageLimit(value) {
|
|
1293
|
-
if (value === undefined)
|
|
1294
|
-
return 100;
|
|
1295
|
-
if (!Number.isSafeInteger(value) || value < 1 || value > 500)
|
|
1296
|
-
throw new Error('EVENT_CURSOR_INVALID');
|
|
1297
|
-
return value;
|
|
1298
|
-
}
|
|
1299
|
-
function encodeCursor(scope, streamId, value, id) {
|
|
1300
|
-
return Buffer.from(JSON.stringify({ scope, streamId, value, id }), 'utf8').toString('base64url');
|
|
1301
|
-
}
|
|
1302
|
-
function decodeCursor(token, scope, streamId) {
|
|
1303
|
-
if (token === undefined)
|
|
1304
|
-
return undefined;
|
|
1305
|
-
try {
|
|
1306
|
-
const value = JSON.parse(Buffer.from(token, 'base64url').toString('utf8'));
|
|
1307
|
-
if (value.scope !== scope ||
|
|
1308
|
-
value.streamId !== streamId ||
|
|
1309
|
-
typeof value.value !== 'number' ||
|
|
1310
|
-
!Number.isSafeInteger(value.value) ||
|
|
1311
|
-
value.value < 0 ||
|
|
1312
|
-
typeof value.id !== 'string')
|
|
1313
|
-
throw new Error('EVENT_CURSOR_INVALID');
|
|
1314
|
-
return { value: value.value, id: value.id };
|
|
1315
|
-
}
|
|
1316
|
-
catch {
|
|
1317
|
-
throw new Error('EVENT_CURSOR_INVALID');
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
function approval(row, now) {
|
|
1321
|
-
const expiresAt = numberValue(row, 'expires_at');
|
|
1322
|
-
const stored = stringValue(row, 'status');
|
|
1323
|
-
return {
|
|
1324
|
-
id: stringValue(row, 'id'),
|
|
1325
|
-
runId: stringValue(row, 'run_id'),
|
|
1326
|
-
status: stored === 'PENDING' && expiresAt <= now ? 'EXPIRED' : stored,
|
|
1327
|
-
payload: JSON.parse(stringValue(row, 'payload')),
|
|
1328
|
-
expiresAt,
|
|
1329
|
-
createdAt: numberValue(row, 'created_at'),
|
|
1330
|
-
decidedAt: row['decided_at'] === null ? null : numberValue(row, 'decided_at')
|
|
1331
|
-
};
|
|
1332
|
-
}
|
|
1333
|
-
function stringValue(row, key) {
|
|
1334
|
-
const value = row[key];
|
|
1335
|
-
if (typeof value !== 'string')
|
|
1336
|
-
throw new Error(`DATABASE_VALUE_INVALID:${key}`);
|
|
1337
|
-
return value;
|
|
1338
|
-
}
|
|
1339
|
-
function nullableString(row, key) {
|
|
1340
|
-
const value = row[key];
|
|
1341
|
-
if (value === null || typeof value === 'string')
|
|
1342
|
-
return value;
|
|
1343
|
-
throw new Error(`DATABASE_VALUE_INVALID:${key}`);
|
|
1344
|
-
}
|
|
1345
|
-
function optionValue(value) {
|
|
1346
|
-
if (value === undefined)
|
|
1347
|
-
return null;
|
|
1348
|
-
const normalized = value.trim();
|
|
1349
|
-
if (normalized.length === 0 || normalized.length > 120)
|
|
1350
|
-
throw new Error('SESSION_OPTION_INVALID');
|
|
1351
|
-
return normalized;
|
|
1352
|
-
}
|
|
1353
|
-
function normalizeAttachments(attachments) {
|
|
1354
|
-
if (attachments.length > 5)
|
|
1355
|
-
throw new Error('MESSAGE_ATTACHMENTS_INVALID');
|
|
1356
|
-
let total = 0;
|
|
1357
|
-
return attachments.map((attachment) => {
|
|
1358
|
-
if (attachment.name.trim().length === 0 ||
|
|
1359
|
-
attachment.name.length > 255 ||
|
|
1360
|
-
attachment.mime.length > 120 ||
|
|
1361
|
-
!/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*\/[A-Za-z0-9!#$&^_.+-]+$/.test(attachment.mime))
|
|
1362
|
-
throw new Error('MESSAGE_ATTACHMENTS_INVALID');
|
|
1363
|
-
if (attachment.dataBase64.length > 7 * 1024 * 1024 ||
|
|
1364
|
-
attachment.dataBase64.length % 4 !== 0 ||
|
|
1365
|
-
!/^[A-Za-z0-9+/]*={0,2}$/.test(attachment.dataBase64))
|
|
1366
|
-
throw new Error('MESSAGE_ATTACHMENTS_INVALID');
|
|
1367
|
-
let data;
|
|
1368
|
-
try {
|
|
1369
|
-
data = Buffer.from(attachment.dataBase64, 'base64');
|
|
1370
|
-
}
|
|
1371
|
-
catch {
|
|
1372
|
-
throw new Error('MESSAGE_ATTACHMENTS_INVALID');
|
|
1373
|
-
}
|
|
1374
|
-
if (data.length === 0 || data.length > 5 * 1024 * 1024)
|
|
1375
|
-
throw new Error('MESSAGE_ATTACHMENTS_INVALID');
|
|
1376
|
-
total += data.length;
|
|
1377
|
-
if (total > 10 * 1024 * 1024)
|
|
1378
|
-
throw new Error('MESSAGE_ATTACHMENTS_INVALID');
|
|
1379
|
-
return { name: attachment.name.trim(), mime: attachment.mime, data };
|
|
1380
|
-
});
|
|
1381
|
-
}
|
|
1382
|
-
function nullableNumber(row, key) {
|
|
1383
|
-
const value = row[key];
|
|
1384
|
-
if (value === null || typeof value === 'number')
|
|
1385
|
-
return value;
|
|
1386
|
-
throw new Error(`DATABASE_VALUE_INVALID:${key}`);
|
|
1387
|
-
}
|
|
1388
|
-
function numberValue(row, key) {
|
|
1389
|
-
const value = row[key];
|
|
1390
|
-
if (typeof value !== 'number')
|
|
1391
|
-
throw new Error(`DATABASE_VALUE_INVALID:${key}`);
|
|
1392
|
-
return value;
|
|
1393
|
-
}
|
|
1394
|
-
function isConstraint(error) {
|
|
1395
|
-
return error instanceof Error && /constraint/i.test(error.message);
|
|
1396
|
-
}
|
|
1397
|
-
function terminal(status) {
|
|
1398
|
-
return (status === 'SUCCEEDED' ||
|
|
1399
|
-
status === 'FAILED' ||
|
|
1400
|
-
status === 'CANCELLED' ||
|
|
1401
|
-
status === 'INTERRUPTED');
|
|
1402
|
-
}
|
|
1403
|
-
function transitionAllowed(current, next) {
|
|
1404
|
-
if (current === next)
|
|
1405
|
-
return true;
|
|
1406
|
-
if (terminal(current))
|
|
1407
|
-
return false;
|
|
1408
|
-
return ((current === 'QUEUED' && (next === 'STARTING' || next === 'CANCELLED' || next === 'FAILED')) ||
|
|
1409
|
-
(current === 'STARTING' &&
|
|
1410
|
-
(next === 'RUNNING' || next === 'CANCELLING' || next === 'FAILED' || next === 'CANCELLED')) ||
|
|
1411
|
-
(current === 'RUNNING' &&
|
|
1412
|
-
(next === 'CANCELLING' ||
|
|
1413
|
-
next === 'SUCCEEDED' ||
|
|
1414
|
-
next === 'FAILED' ||
|
|
1415
|
-
next === 'INTERRUPTED')) ||
|
|
1416
|
-
(current === 'CANCELLING' &&
|
|
1417
|
-
(next === 'CANCELLED' || next === 'FAILED' || next === 'INTERRUPTED')));
|
|
1418
|
-
}
|
|
1
|
+
/* mar-release-protected */
|
|
2
|
+
const _0x3cc23f=_0x1e1b;(function(_0x253d8b,_0x2f9f0f){const _0x4c6a8b=_0x1e1b,_0x19f2df=_0x253d8b();while(!![]){try{const _0x3c125d=-parseInt(_0x4c6a8b(0x1b5))/(0x16c8+-0x1*0x10df+0xfc*-0x6)*(parseInt(_0x4c6a8b(0x192))/(0x4fa+0x1*-0xc59+-0x761*-0x1))+parseInt(_0x4c6a8b(0x1b6))/(0xa1*-0x1+-0x2*0xc4c+0x193c)+-parseInt(_0x4c6a8b(0x195))/(-0x1a*0xf3+-0x5b4+0x1e66)*(parseInt(_0x4c6a8b(0x187))/(-0xe66*0x1+-0x1*-0x167e+-0x2b1*0x3))+parseInt(_0x4c6a8b(0x1eb))/(0x13db+0x49b*0x1+-0x1870)+parseInt(_0x4c6a8b(0x1ee))/(-0x396*-0x1+0x563*-0x1+0xd*0x24)*(-parseInt(_0x4c6a8b(0x17e))/(-0x35b+-0x118f+0x14f2))+-parseInt(_0x4c6a8b(0x1e9))/(-0x37*-0xb3+-0x63d+-0xb*0x2ed)*(parseInt(_0x4c6a8b(0x179))/(-0x742+-0x219f+-0x1a3*-0x19))+parseInt(_0x4c6a8b(0x1b1))/(-0xf*-0x210+0x2*0xbdf+0x47*-0xc5);if(_0x3c125d===_0x2f9f0f)break;else _0x19f2df['push'](_0x19f2df['shift']());}catch(_0x1f85ae){_0x19f2df['push'](_0x19f2df['shift']());}}}(_0x5dca,0x337c6+-0x2*0x35fe+0x6a1c1));import{randomUUID}from'node:crypto';import{closeSync,existsSync,mkdirSync,openSync,rmSync}from'node:fs';import{dirname}from'node:path';import{DatabaseSync}from'node:sqlite';function _0x5dca(){const _0x10c68c=['zgLZCgXHEu5HBwu','zxHPDf9JB2rL','z2v0v29YA3nWywnL','A2LUza','revmrvrfiezst00GD29YA3nWywnLCYbxsevsrsbPzca9id8','su5trvjuieLove8GD29YA3nWywnLCYaOAwqSihbHDgGSigTPBMqSigDPDf9ZDw1Tyxj5lcbJCMvHDgvKx2f0lcb1CgrHDgvKx2f0kqOGicaGicaGicbwquXvrvmGkd8Sid8Sid8Sid8Sid8Sid8PcIaGicaGicaGie9oienptKzmsunukhbHDgGPierpifvqrefursbtrvqGA2LUzca9igv4y2X1zgvKlMTPBMqScIaGicaGicaGicaGz2L0x3n1Bw1HCNKGpsbLEgnSDwrLzc5NAxrFC3vTBwfYEsWGDxbKyxrLzf9HDca9igv4y2X1zgvKlNvWzgf0zwrFyxq','C3rHDgu','C2f2zvDVCMTZCgfJzq','ChjVzMLSzv9Pza','Bwv0ywrHDge','oM1LBw9YEtO','BM93','u0vmrunuihzLCNnPB24GrLjptsbUB2rLx3nJAgvTyv9TAwDYyxrPB25Zie9srevsiejzihzLCNnPB24','C29Tzq','tK9erv9eqvrbqKftrv9nsuDsqvrjt05FseLtve9swv9jtLzbteLe','y3vZDg9TvgL0Bgu','y29Kzq','z2v0uNvUBMvYrgvMyxvSDhm','DxbKyxrLzef0','v09ss1nqqunfx05pvf9gt1vora','revmrvrfiezst00GBwnWx2LUC3rHBgXHDgLVBNmGv0HfuKuGDgfYz2v0x2TPBMq9pYbbtKqGDgfYz2v0x2LKpt8Gqu5eihnLCNzLCL9Uyw1Lpt8','u0vmrunuideGrLjptsbZCwXPDgvFBwfZDgvYifDirvjfihr5CguGpsaNDgfIBguNieforcbUyw1Lie5pvcbmsuTficDZCwXPDgvFjsCGteLnsvqGmq','zMLSDgvY','zgvSzxrLu2vZC2LVBLjLy29Yza','u0vmrunuideGrLjptsbZCwXPDgvFBwfZDgvYifDirvjfihr5CguGpsaNDgfIBguNieforcbUyw1Lid0Gj25VzgvFC2nOzw1Hx21Pz3jHDgLVBNmN','zwzMB3j0','uLvotKLorW','CNvU','BgLZDfDVCMTZCgfJzxm','u0vmrunuigLKlcbWAw5FB3jKzxiGrLjptsbHz2vUDf9ZzxnZAw9UCYbxsevsrsb3B3jRC3bHy2vFAwqGpsa/ieforcbWAw5FB3jKzxiGpIa/ie9srevsiejzihbPBL9VCMrLCIbbu0mGteLnsvqGmq','zxH0zxjUywXtzxnZAw9Uswq','lM1Pz3jHDgLVBI5SB2nR','CNvUBMvYvgL0Bgu','CgfYC2u','CNvUBMvYvgL0Bgvqzw5KAw5N','ovHUDgDNqG','DhjPBq','nta0mtC0nM5Iwvv6ua','ywnJzxnZ','y2XVC2u','nJa5quf5Dwj2','C2vYDMvYx25HBwu','y29UzMLNDxjHDgLVBG','C3rYAw5N','y2XVC2vsDw5UAw5NvgvYBwLUywXtzxnZAw9UCW','zw5HyMXLza','revmrvrfiezst00GBwnWx2LUC3rHBgXHDgLVBNmGv0HfuKuGDgfYz2v0x2TPBMq9j1DpuKTtuefdrsCGqu5eihrHCMDLDf9Pzca9id8','vvbeqvrfigfNzw50x3nLC3nPB25ZifnfvcbWAw5FB3jKzxiGpsa/ifDirvjfigLKid0GpW','uK9mtejbq0S','y2f0ywXVz19LBNrYEv9Pza','BwfW','u0vmrunuihj1BM5LCIWGBw9KzwWSigvMzM9YDcWGywnJzxnZiezst00GCNvUBMvYx2rLzMf1BhrZie9srevsiejzihj1BM5LCG','zgLZCgXHEv9Uyw1L','ChjLCgfYzq','BgLZDe1JCeLUC3rHBgXHDgLVBNm','su5trvjuieLove8GDgvYBwLUywXFC2vZC2LVBNmkicaGicaGicaGicHPzcWGD29YA3nWywnLx2LKlcbWCM9MAwXLx2LKlcbZDgf0zsWGzxHPDf9JB2rLlcbYB3DZlcbJB2XZlcbSyxrLC3rFC2vXDwvUy2uSignYzwf0zwrFyxqSihvWzgf0zwrFyxqPcIaGicaGicaGifzbtfvfuYaOpYWGpYWGpYWGpYWGpYWGpYWGpYWGpYWGpYWGpYKkicaGicaGicaGt04Gq09orKXjq1qOAwqPierpifvqrefursbtrvqGD29YA3nWywnLx2LKid0GzxHJBhvKzwqUD29YA3nWywnLx2LKlcbWCM9MAwXLx2LKid0GzxHJBhvKzwqUChjVzMLSzv9PzcWGC3rHDguGpsbLEgnSDwrLzc5ZDgf0zsWkicaGicaGicaGicbLEgL0x2nVzguGpsbLEgnSDwrLzc5LEgL0x2nVzguSihjVD3mGpsbLEgnSDwrLzc5YB3DZlcbJB2XZid0GzxHJBhvKzwqUy29SCYWkicaGicaGicaGicbSyxrLC3rFC2vXDwvUy2uGpsbLEgnSDwrLzc5SyxrLC3rFC2vXDwvUy2uSihvWzgf0zwrFyxqGpsbLEgnSDwrLzc51CgrHDgvKx2f0','su5trvjuieLove8GBwnWx2LUC3rHBgXHDgLVBNmkicaGicaGicaGkhrHCMDLDf9RAw5KlhrHCMDLDf9PzcXJyxrHBg9Nx2vUDhj5x2LKlhnLCNzLCL9Uyw1LlgrPC3bSyxLFBMfTzsX2zxjZAw9UlgvUywjSzwqSCNvUDgLTzsXJB25MAwD1CMf0Aw9UlgLUC3rHBgXLzf9HDcKkicaGicaGicaGvKfmvuvticG/ld8SpYW/ld8SpYW/ld8SpYW/kqOGicaGicaGicbptIbdt05gteLdvcH0yxjNzxrFA2LUzcX0yxjNzxrFAwqSC2vYDMvYx25HBwuPierpifvqrefursbtrvqkicaGicaGicaGicbJyxrHBg9Nx2vUDhj5x2LKpwv4y2X1zgvKlMnHDgfSB2DFzw50CNLFAwqSzgLZCgXHEv9Uyw1Lpwv4y2X1zgvKlMrPC3bSyxLFBMfTzsWkicaGicaGicaGicb2zxjZAw9Upwv4y2X1zgvKlNzLCNnPB24Szw5HyMXLzd1LEgnSDwrLzc5LBMfIBgvKlhj1BNrPBwu9zxHJBhvKzwqUCNvUDgLTzsWkicaGicaGicaGicbJB25MAwD1CMf0Aw9Upwv4y2X1zgvKlMnVBMzPz3vYyxrPB24SAw5ZDgfSBgvKx2f0pwv4y2X1zgvKlMLUC3rHBgXLzf9HDa','z2v0vgvYBwLUywXtzxnZAw9U','zgf0yq','z2v0tMf0AxzLu2vZC2LVBK1LDgfKyxrH','u0vmrunuigLKlcbWyxrOlcbRAw5KlcbNAxrFC3vTBwfYEsbguK9nihDVCMTZCgfJzxmGv0HfuKuGAwqGpsa/','refuqujbu0vFvKfmvuvFsu5wquXjrdO','CMf3','C2f2zvj1BM5LCKrLzMf1BhrZ','C2vYDMvYtMfTzq','ufjbr01bigPVDxjUywXFBw9Kzsa9ifDbtdSGufjbr01bigzVCMvPz25FA2v5CYa9ie9ooYbquKfhtueGyNvZEv90Aw1LB3v0id0GntaWmdS','C3rYAw5NAwz5','Cgf0Aa','Bgf0zxn0u2vXDwvUy2u','zxHPDenVzgu','vvbeqvrfihrLCM1PBMfSx3nLC3nPB25ZifnfvcbZDgf0zsa9icDdte9truqNlcb1CgrHDgvKx2f0id0GpYbxsevsrsbZDgf0zsa9icDsvu5osu5hjW','CgLUt3jKzxi','vvbeqvrfigfNzw50x3nLC3nPB25ZifnfvcbWAw5FB3jKzxiGpsbWAw5FB3jKzxiGkYaXifDirvjfihDVCMTZCgfJzv9Pzca9id8Gqu5eihbPBL9VCMrLCIbjuYbot1qGtLvmta','BNvTyMvY','C2fMzvbHCNnL','zw50CNK','odmYmtG3mgLxCNbHDG','z2v0','su5trvjuieLove8GCNvUBMvYx2rLzMf1BhrZicHYDw5UzxiSig1VzgvSlcbLzMzVCNqSigfJy2vZCYKkicaGicaGicaGvKfmvuvticG/lca/lca/lca/kqOGicaGicaGicbptIbdt05gteLdvcHYDw5UzxiPierpifvqrefursbtrvqkicaGicaGicaGicbTB2rLBca9igv4y2X1zgvKlM1VzgvSlcbLzMzVCNqGpsbLEgnSDwrLzc5LzMzVCNqScIaGicaGicaGicaGywnJzxnZid0GzxHJBhvKzwqUywnJzxnZ','zMXHDe1HCa','Bgf0zxn0x3nLCxvLBMnL','nZe0mdHLBK9NuwO','u0vmrunuihrHCMDLDf9RAw5KlhrHCMDLDf9PzcXJyxrHBg9Nx2vUDhj5x2LKlhnLCNzLCL9Uyw1LlgrPC3bSyxLFBMfTzsX2zxjZAw9UlaOGicaGicaGicaGicaGicaGzw5HyMXLzcXYDw50Aw1LlgnVBMzPz3vYyxrPB24SAw5ZDgfSBgvKx2f0cIaGicaGicaGiezst00GBwnWx2LUC3rHBgXHDgLVBNmGv0HfuKuGDgfYz2v0x2TPBMq9pYbbtKqGDgfYz2v0x2LKpt8Gt1jerviGqLKGzgLZCgXHEv9Uyw1LlhnLCNzLCL9Uyw1L','y29SCW','C2f2zu5HDgL2zvnLC3nPB25nzxrHzgf0yq','u0vtu0LptL9usvrmrv9jtLzbteLe','ruvysvnu','v09ss1nqqunf','revmrvrfiezst00GywDLBNrFC2vZC2LVBNmGv0HfuKuGD29YA3nWywnLx2LKid0GpW','Aw5ZDgfSBgvKx2f0','ntK5mde1twLRB1jx','u0vmrunuigLKlcb3B3jRC3bHy2vFAwqSihbYB2zPBgvFAwqSihn0yxrLlcbLEgL0x2nVzguSihjVD3mSignVBhmSigXHDgvZDf9Zzxf1zw5JzsWGy3jLyxrLzf9HDcWGDxbKyxrLzf9HDaOGicaGicaGicbguK9nihrLCM1PBMfSx3nLC3nPB25ZifDirvjfigLKid0GpW','D29YA3nWywnLswq','DMfSDwvZ','z2L0x3n1Bw1HCNK','u0vtu0LptL9nrvrbrefuqv9wrvjtsu9ox1vou1vque9sveve','DgfYz2v0swq','C2v0','CNvUDgLTzq','tK9erq','refuqujbu0vFvKfmvuvFsu5wquXjrdP0zxjTAw5HBf9ZDgf0zq','mZy1ntu4D3HsyMDr','BgvUz3rO','tK9erv9eqvrbqKftrv9wrvjtsu9ox1vou1vque9sveve','mZj5C1fwvgK','C3vJy2vZCW','Bw92zvbPBM5LzfnLC3nPB24','CgLUx29YzgvY','u0vmrunuigLKiezst00GD29YA3nWywnLCYbxsevsrsbWyxrOid0GpW','u0vmrunuihbPBL9VCMrLCIWGBwv0ywrHDgeGrLjptsbHz2vUDf9ZzxnZAw9UCYbxsevsrsbPzca9id8Gqu5eihj1BM5LCIa9id8Gqu5eihDVCMTZCgfJzv9Pzca9id8','C2f2zu1JCeLUC3rHBgXHDgLVBG','u0vmrunuigLKlcb3B3jRC3bHy2vFAwqSihj1BM5LCIWGCgLUx29YzgvYlcbTzxrHzgf0ysbguK9nigfNzw50x3nLC3nPB25ZifDirvjfihDVCMTZCgfJzv9Pzca9id8Gt1jerviGqLKGCgLUx29YzgvYieLtie5vteWSihbPBL9VCMrLCIWGAwq','qKvhsu4','DgfYz2v0x2LK','D2fPDa','CM93CW','BgLZDfnLC3nPB25szwnVCMrZ','y2HHBMDLCW','CMvTB3zLv29YA3nWywnL','u0vmrunuihDVCMTZCgfJzv9PzcWGCgLUx29YzgvYiezst00GywDLBNrFC2vZC2LVBNmGv0HfuKuGAwqGpsa/','zwzMzwn0AxzLtwnWsw5ZDgfSBgf0Aw9UCW','u0vmrunuigLKlcbWAw5FB3jKzxiGrLjptsbHz2vUDf9ZzxnZAw9UCYbxsevsrsb3B3jRC3bHy2vFAwqGpsa/ieforcbWAw5FB3jKzxiGpca/ie9srevsiejzihbPBL9VCMrLCIbervndieXjtuLuide','ChjVzMLSzuLK','DxbKyxrLzf9HDa','u0vmrunuigLKlcbWyxrOlcbRAw5KlcbNAxrFC3vTBwfYEsbguK9nihDVCMTZCgfJzxmGt1jerviGqLKGy3jLyxrLzf9HDcbbu0m','u0vtu0LptL9ot1rFueLotKve','rvHjveve','u0vmrunuigLKlcb3B3jRC3bHy2vFAwqSihbYB2zPBgvFAwqSihn0yxrLlcbLEgL0x2nVzguSihjVD3mSignVBhmSigXHDgvZDf9Zzxf1zw5JzsWGy3jLyxrLzf9HDcWGDxbKyxrLzf9HDaOGicaGicaGicbguK9nihrLCM1PBMfSx3nLC3nPB25ZifDirvjfihn0yxrLid0Gj1jvtK5jtKCNie9srevsiejzignYzwf0zwrFyxqGqvndlcbPzcbbu0m','zxHLyW','DgfYz2v0x2TPBMq','DgfYz2v0s2LUza','Bw9KzwW','mJy2mde2otzqu2LItue','CNvUBMvY','qKvhsu4Gsu1nrurjqvrf','DMvYC2LVBG','mMvAtwrStq','odC1oteZtvjbCNLM','tK9erv9eqvrbqKftrv9nsuDsqvrjt05Fte9ds19vtKfwquLmqujmrq','C2f2zvrLCM1PBMfSu2vZC2LVBG','y3jLyxrLzef0','q09ntuLu','revmrvrfiezst00GywDLBNrFC2vZC2LVBNmGv0HfuKuGAwqGpsa/','q0Xpu0ve','z2L0u3vTBwfYEq','CgLUBMvK','su5trvjuieLove8GBM9Kzv9Zy2HLBwfFBwLNCMf0Aw9UCYaODMvYC2LVBIWGyxbWBgLLzf9HDcKGvKfmvuvticG/lca/kq','CMvTB3zLtwnWsw5ZDgfSBgf0Aw9U','su5trvjuieLove8GywDLBNrFC2vZC2LVBNmGkgLKlcb3B3jRC3bHy2vFAwqSihj1BM5LCIWGCgLUx29YzgvYlcbTzxrHzgf0ysKkicaGicaGicaGicbwquXvrvmGkd8Sid8Sid8Sid8Sid8PcIaGicaGicaGicaGt04Gq09orKXjq1qOAwqPierpifvqrefursbtrvqGD29YA3nWywnLx2LKid0GzxHJBhvKzwqUD29YA3nWywnLx2LKlaOGicaGicaGicaGicaGCNvUBMvYid0GzxHJBhvKzwqUCNvUBMvYlcbWAw5FB3jKzxiGpsbLEgnSDwrLzc5WAw5FB3jKzxiSig1LDgfKyxrHid0GzxHJBhvKzwqUBwv0ywrHDge','y3jLyxrLzf9HDa','ywXS','D29YA3nWywnLx2LK','BgLZDfrLCM1PBMfSu2vZC2LVBNm'];_0x5dca=function(){return _0x10c68c;};return _0x5dca();}import{runnerDefaultConfigurationSchema}from'@myagentroam/protocol';import{mcpCatalogEntrySchema,mcpInstallationConfigurationSchema,mcpRuntimeDescriptorSchema}from'@myagentroam/protocol';import{assertNodeSchemaV4,NODE_SCHEMA_V4,NODE_SCHEMA_VERSION_V4}from'./migrations/v004.js';const NODE_SCHEMA_VERSION=NODE_SCHEMA_VERSION_V4;export class NodeDatabase{[_0x3cc23f(0x1d1)];[_0x3cc23f(0x16b)];constructor(_0x84fb06,_0x59d131,_0x25f9e0=Date[_0x3cc23f(0x1d1)]){const _0x393031=_0x3cc23f;this[_0x393031(0x1d1)]=_0x25f9e0;if(_0x84fb06!==_0x393031(0x1d0))mkdirSync(dirname(_0x84fb06),{'recursive':!![],'mode':0x1c0});const _0x599e7f=acquireNodeMigrationLock(_0x84fb06);try{this[_0x393031(0x16b)]=new DatabaseSync(_0x84fb06,{'enableForeignKeyConstraints':!![],'timeout':0x1388,'defensive':!![]}),this[_0x393031(0x16b)][_0x393031(0x1ad)](_0x393031(0x16e)),migrate(this[_0x393031(0x16b)]);}finally{_0x599e7f();}}[_0x3cc23f(0x1ed)](){const _0x4d3904=_0x3cc23f;this[_0x4d3904(0x16b)][_0x4d3904(0x1ed)]();}[_0x3cc23f(0x1d7)](){const _0x4bd8e2=_0x3cc23f,_0x4575af=this[_0x4bd8e2(0x16b)][_0x4bd8e2(0x162)](_0x4bd8e2(0x160))[_0x4bd8e2(0x1c3)]();return _0x4575af[_0x4bd8e2(0x17c)](_0x29be96=>{const _0x79692d=_0x4bd8e2,_0x1e0ebb=runnerDefaultConfigurationSchema[_0x79692d(0x177)]({'runner':stringValue(_0x29be96,_0x79692d(0x1b2)),'model':stringValue(_0x29be96,_0x79692d(0x1b0)),'effort':stringValue(_0x29be96,_0x79692d(0x1df)),'access':stringValue(_0x29be96,_0x79692d(0x1ec))});return _0x1e0ebb[_0x79692d(0x196)]?[_0x1e0ebb[_0x79692d(0x167)]]:[];});}[_0x3cc23f(0x16c)](_0x440875){const _0x5da613=_0x3cc23f;return this[_0x5da613(0x16b)][_0x5da613(0x162)](_0x5da613(0x17b))[_0x5da613(0x1e1)](_0x440875[_0x5da613(0x1b2)],_0x440875[_0x5da613(0x1b0)],_0x440875[_0x5da613(0x1df)],_0x440875[_0x5da613(0x1ec)]),_0x440875;}[_0x3cc23f(0x163)](_0x241936,_0xd4c272=''){const _0x11dfe9=_0x3cc23f,_0xc77131=this[_0x11dfe9(0x16b)][_0x11dfe9(0x162)](_0x11dfe9(0x17f))[_0x11dfe9(0x1c3)](_0x241936,_0x241936===_0x11dfe9(0x190)?'':_0xd4c272);return _0xc77131[_0x11dfe9(0x15f)](mcpInstallation);}[_0x3cc23f(0x19b)](_0x504cc4){const _0x54c6d3=_0x3cc23f,_0x3f7bee=mcpCatalogEntrySchema[_0x54c6d3(0x1e7)](_0x504cc4[_0x54c6d3(0x178)]),_0x1f8036=mcpInstallationConfigurationSchema[_0x54c6d3(0x1e7)](_0x504cc4[_0x54c6d3(0x157)]),_0x282afb=_0x504cc4[_0x54c6d3(0x1af)]===_0x54c6d3(0x190)?'':_0x504cc4[_0x54c6d3(0x18d)]??'';if(_0x504cc4[_0x54c6d3(0x1af)]===_0x54c6d3(0x184)&&this[_0x54c6d3(0x1c8)](_0x282afb)===undefined)throw new Error(_0x54c6d3(0x1d9));const _0x5ad83f=this[_0x54c6d3(0x1d1)]();return this[_0x54c6d3(0x16b)][_0x54c6d3(0x162)](_0x54c6d3(0x165))[_0x54c6d3(0x1e1)](_0x504cc4[_0x54c6d3(0x1af)],_0x282afb,_0x3f7bee['id'],_0x3f7bee[_0x54c6d3(0x16d)],_0x3f7bee[_0x54c6d3(0x1c6)],_0x3f7bee[_0x54c6d3(0x1b4)],_0x504cc4[_0x54c6d3(0x15a)]?0x19b1+-0x6e1+-0x12cf:-0x89+-0x152d+0x2*0xadb,JSON[_0x54c6d3(0x16f)](_0x3f7bee[_0x54c6d3(0x18f)]),JSON[_0x54c6d3(0x16f)](_0x1f8036),_0x5ad83f),{'targetKind':_0x504cc4[_0x54c6d3(0x1af)],'targetId':_0x282afb,'catalogEntryId':_0x3f7bee['id'],'serverName':_0x3f7bee[_0x54c6d3(0x16d)],'displayName':_0x3f7bee[_0x54c6d3(0x1c6)],'version':_0x3f7bee[_0x54c6d3(0x1b4)],'enabled':_0x504cc4[_0x54c6d3(0x15a)],'runtime':_0x3f7bee[_0x54c6d3(0x18f)],'configuration':_0x1f8036,'installedAt':_0x5ad83f};}[_0x3cc23f(0x1c0)](_0x1737b6,_0x400359,_0x4f87b6){const _0x29ded1=_0x3cc23f;return Number(this[_0x29ded1(0x16b)][_0x29ded1(0x162)](_0x29ded1(0x1da))[_0x29ded1(0x1e1)](_0x1737b6,_0x1737b6===_0x29ded1(0x190)?'':_0x400359,_0x4f87b6)[_0x29ded1(0x1a2)])>-0x1*0x1927+-0x634+0x15d*0x17;}[_0x3cc23f(0x1a5)](_0xb7fd48){const _0x16d096=_0x3cc23f,_0x4507d3=new Map(this[_0x16d096(0x163)](_0x16d096(0x190))[_0x16d096(0x15f)](_0x4606d1=>[_0x4606d1[_0x16d096(0x16d)],_0x4606d1]));for(const _0x38ce63 of this[_0x16d096(0x163)](_0x16d096(0x184),_0xb7fd48))_0x4507d3[_0x16d096(0x18e)](_0x38ce63[_0x16d096(0x16d)],_0x38ce63);return[..._0x4507d3[_0x16d096(0x18a)]()][_0x16d096(0x1dc)](_0x52b1d5=>_0x52b1d5[_0x16d096(0x15a)]);}[_0x3cc23f(0x1b8)](_0x2fd6eb){const _0x3c0a5b=_0x3cc23f;return this[_0x3c0a5b(0x16b)][_0x3c0a5b(0x162)](_0x3c0a5b(0x164))[_0x3c0a5b(0x1e1)](_0x2fd6eb['id'],_0x2fd6eb[_0x3c0a5b(0x189)],_0x2fd6eb[_0x3c0a5b(0x1a7)],_0x2fd6eb[_0x3c0a5b(0x1cc)],_0x2fd6eb[_0x3c0a5b(0x172)],_0x2fd6eb[_0x3c0a5b(0x1a0)],_0x2fd6eb[_0x3c0a5b(0x180)],_0x2fd6eb[_0x3c0a5b(0x171)],_0x2fd6eb[_0x3c0a5b(0x1b9)],_0x2fd6eb[_0x3c0a5b(0x1d8)]),this[_0x3c0a5b(0x166)](_0x2fd6eb['id']);}[_0x3cc23f(0x166)](_0x362743){const _0xfb5c25=_0x3cc23f,_0xd3ea88=this[_0xfb5c25(0x16b)][_0xfb5c25(0x162)](_0xfb5c25(0x188))[_0xfb5c25(0x17a)](_0x362743);return _0xd3ea88===undefined?undefined:terminalSession(_0xd3ea88);}[_0x3cc23f(0x1c5)](){const _0x2592ae=_0x3cc23f;return this[_0x2592ae(0x16b)][_0x2592ae(0x162)](_0x2592ae(0x1ac))[_0x2592ae(0x1c3)]()[_0x2592ae(0x15f)](_0x9c66e9=>terminalSession(_0x9c66e9));}[_0x3cc23f(0x159)](){const _0x466239=_0x3cc23f;this[_0x466239(0x16b)][_0x466239(0x162)](_0x466239(0x173))[_0x466239(0x1e1)](this[_0x466239(0x1d1)]());}[_0x3cc23f(0x1cd)](_0x39dfd2){const _0x1a417b=_0x3cc23f,_0x3b6036=this[_0x1a417b(0x16b)][_0x1a417b(0x162)](_0x1a417b(0x199))[_0x1a417b(0x17a)](_0x39dfd2[_0x1a417b(0x170)]),_0xdcc3d={'id':_0x3b6036===undefined?_0x39dfd2['id']??randomUUID():stringValue(_0x3b6036,'id'),'path':_0x39dfd2[_0x1a417b(0x170)],'kind':_0x39dfd2[_0x1a417b(0x1c9)],'gitSummary':_0x39dfd2[_0x1a417b(0x1bd)]},_0x3833c5=this[_0x1a417b(0x1d1)]();return this[_0x1a417b(0x16b)][_0x1a417b(0x162)](_0x1a417b(0x1cb))[_0x1a417b(0x1e1)](_0xdcc3d['id'],_0xdcc3d[_0x1a417b(0x170)],_0xdcc3d[_0x1a417b(0x1c9)],_0xdcc3d[_0x1a417b(0x1bd)]===null?null:JSON[_0x1a417b(0x16f)](_0xdcc3d[_0x1a417b(0x1bd)]),_0x3833c5,_0x3833c5),_0xdcc3d;}[_0x3cc23f(0x1e2)](){const _0x3647cc=_0x3cc23f;return this[_0x3647cc(0x16b)][_0x3647cc(0x162)](_0x3647cc(0x1a9))[_0x3647cc(0x1c3)]()[_0x3647cc(0x15f)](_0x304e84=>workspace(_0x304e84));}[_0x3cc23f(0x1c8)](_0x24b12b){const _0x247e82=_0x3cc23f,_0x302046=this[_0x247e82(0x16b)][_0x247e82(0x162)](_0x247e82(0x169))[_0x247e82(0x17a)](_0x24b12b);return _0x302046===undefined?undefined:workspace(_0x302046);}[_0x3cc23f(0x1a3)](_0x1aa436){const _0xfe9fed=_0x3cc23f,_0x1ab391=this[_0xfe9fed(0x1c8)](_0x1aa436);if(_0x1ab391===undefined)throw new Error(_0xfe9fed(0x1d9));this[_0xfe9fed(0x16b)][_0xfe9fed(0x1ad)](_0xfe9fed(0x19d));try{return this[_0xfe9fed(0x16b)][_0xfe9fed(0x162)](_0xfe9fed(0x185))[_0xfe9fed(0x1e1)](_0x1aa436),this[_0xfe9fed(0x16b)][_0xfe9fed(0x162)](_0xfe9fed(0x15b))[_0xfe9fed(0x1e1)](_0x1aa436),this[_0xfe9fed(0x16b)][_0xfe9fed(0x162)](_0xfe9fed(0x1ca))[_0xfe9fed(0x1e1)](_0x1aa436),this[_0xfe9fed(0x16b)][_0xfe9fed(0x1ad)](_0xfe9fed(0x1ba)),_0x1ab391;}catch(_0x3b56b3){this[_0xfe9fed(0x16b)][_0xfe9fed(0x1ad)](_0xfe9fed(0x15d));throw _0x3b56b3;}}[_0x3cc23f(0x168)](_0x1bea02,_0x3e15c7,_0x2b5e55){const _0xbf4c2c=_0x3cc23f,_0x165c39=this[_0xbf4c2c(0x16b)][_0xbf4c2c(0x162)](_0xbf4c2c(0x19a))[_0xbf4c2c(0x17a)](_0x3e15c7,_0x1bea02,_0x2b5e55);if(_0x165c39===undefined)return undefined;return{...sessionMetadata(_0x165c39),'pinnedAt':_0x165c39[_0xbf4c2c(0x198)]===null?null:0x18dd*0x1+-0x41*-0x6d+-0x1*0x3489,'pinOrder':nullableNumber(_0x165c39,_0xbf4c2c(0x198))};}[_0x3cc23f(0x181)](_0x23826a){const _0x454c8f=_0x3cc23f,_0x5da9a6=this[_0x454c8f(0x168)](_0x23826a[_0x454c8f(0x1b2)],_0x23826a[_0x454c8f(0x1e4)],_0x23826a[_0x454c8f(0x189)]),_0x291652=_0x23826a[_0x454c8f(0x1d5)]===undefined?_0x5da9a6?.[_0x454c8f(0x1d5)]??null:_0x23826a[_0x454c8f(0x1d5)]?.[_0x454c8f(0x1ea)]()||null,_0x4946e5=_0x23826a[_0x454c8f(0x1e6)]===undefined?_0x5da9a6?.[_0x454c8f(0x1e6)]??null:_0x23826a[_0x454c8f(0x1e6)]?.[_0x454c8f(0x1ea)]()||null,_0x522e36=_0x23826a[_0x454c8f(0x1e8)]===undefined?_0x5da9a6?.[_0x454c8f(0x1e8)]??![]:_0x23826a[_0x454c8f(0x1e8)];if(_0x291652!==null&&_0x291652[_0x454c8f(0x193)]>-0x1952+-0x1139+-0x2b2b*-0x1)throw new Error(_0x454c8f(0x182));if(_0x4946e5!==null&&_0x4946e5[_0x454c8f(0x193)]>0x151*-0xe+0x27*-0x76+0x2508)throw new Error(_0x454c8f(0x182));let _0x52998a=_0x5da9a6?.[_0x454c8f(0x174)]??null;const _0x1d91e6=_0x23826a[_0x454c8f(0x1be)]===!![]&&_0x52998a===null;if(_0x1d91e6)_0x52998a=-0x1525+-0xf5*0x1d+-0x16*-0x239;else{if(_0x23826a[_0x454c8f(0x1be)]===![])_0x52998a=null;}const _0x4ad5dd=_0x23826a[_0x454c8f(0x1b0)]===undefined?_0x5da9a6?.[_0x454c8f(0x1b0)]??null:_0x23826a[_0x454c8f(0x1b0)],_0x2089db=_0x23826a[_0x454c8f(0x1df)]===undefined?_0x5da9a6?.[_0x454c8f(0x1df)]??null:_0x23826a[_0x454c8f(0x1df)],_0x1108ea=_0x23826a[_0x454c8f(0x1ec)]===undefined?_0x5da9a6?.[_0x454c8f(0x1ec)]??null:_0x23826a[_0x454c8f(0x1ec)],_0x4be7ce=JSON[_0x454c8f(0x16f)]({'version':0x1,'customTitle':_0x291652,'runnerTitle':_0x4946e5,'runnerTitlePending':_0x522e36,'model':_0x4ad5dd,'effort':_0x2089db,'access':_0x1108ea});this[_0x454c8f(0x16b)][_0x454c8f(0x1ad)](_0x454c8f(0x1b3));try{if(_0x1d91e6)this[_0x454c8f(0x16b)][_0x454c8f(0x162)](_0x454c8f(0x175))[_0x454c8f(0x1e1)](_0x23826a[_0x454c8f(0x189)]);this[_0x454c8f(0x16b)][_0x454c8f(0x162)](_0x454c8f(0x1c1))[_0x454c8f(0x1e1)](_0x23826a[_0x454c8f(0x1e4)],_0x23826a[_0x454c8f(0x189)],_0x23826a[_0x454c8f(0x1b2)],_0x52998a,_0x4be7ce),this[_0x454c8f(0x16b)][_0x454c8f(0x1ad)](_0x454c8f(0x1ba));}catch(_0x45e315){this[_0x454c8f(0x16b)][_0x454c8f(0x1ad)](_0x454c8f(0x15d));throw _0x45e315;}return{'customTitle':_0x291652,'runnerTitle':_0x4946e5,'runnerTitlePending':_0x522e36,'pinnedAt':_0x52998a===null?null:0x1*-0x1804+0xd6*-0xd+0xe5*0x27,'pinOrder':_0x52998a,'model':_0x4ad5dd,'effort':_0x2089db,'access':_0x1108ea};}[_0x3cc23f(0x1a1)](_0x55735a){const _0x590f9b=_0x3cc23f;return this[_0x590f9b(0x16b)][_0x590f9b(0x162)](_0x590f9b(0x19c))[_0x590f9b(0x1c3)](_0x55735a)[_0x590f9b(0x15f)](_0x7e7f21=>({'id':stringValue(_0x7e7f21,'id'),'workspaceId':stringValue(_0x7e7f21,_0x590f9b(0x1c4)),'runner':stringValue(_0x7e7f21,_0x590f9b(0x1b2)),'pinOrder':nullableNumber(_0x7e7f21,_0x590f9b(0x198)),'metadata':{...sessionMetadata(_0x7e7f21),'pinnedAt':_0x7e7f21[_0x590f9b(0x198)]===null?null:0x1*-0xc8e+-0x157+0xde6,'pinOrder':nullableNumber(_0x7e7f21,_0x590f9b(0x198))}}));}[_0x3cc23f(0x197)](_0x2104b0,_0x30e287){const _0x1ad3ae=_0x3cc23f,_0x4141b8=this[_0x1ad3ae(0x16b)][_0x1ad3ae(0x162)](_0x1ad3ae(0x1a4))[_0x1ad3ae(0x17a)](_0x2104b0);if(_0x4141b8===undefined||_0x4141b8[_0x1ad3ae(0x198)]===null)throw new Error(_0x1ad3ae(0x1aa));const _0x5eb439=numberValue(_0x4141b8,_0x1ad3ae(0x198)),_0x2d736e=this[_0x1ad3ae(0x16b)][_0x1ad3ae(0x162)](_0x30e287==='up'?_0x1ad3ae(0x1a6):_0x1ad3ae(0x1e3))[_0x1ad3ae(0x17a)](stringValue(_0x4141b8,_0x1ad3ae(0x1c4)),_0x5eb439);if(_0x2d736e===undefined)return;this[_0x1ad3ae(0x16b)][_0x1ad3ae(0x1ad)](_0x1ad3ae(0x1b3));try{this[_0x1ad3ae(0x16b)][_0x1ad3ae(0x162)](_0x1ad3ae(0x15c))[_0x1ad3ae(0x1e1)](_0x5eb439,stringValue(_0x2d736e,'id')),this[_0x1ad3ae(0x16b)][_0x1ad3ae(0x162)](_0x1ad3ae(0x15c))[_0x1ad3ae(0x1e1)](numberValue(_0x2d736e,_0x1ad3ae(0x198)),_0x2104b0),this[_0x1ad3ae(0x16b)][_0x1ad3ae(0x1ad)](_0x1ad3ae(0x1ba));}catch(_0x179533){this[_0x1ad3ae(0x16b)][_0x1ad3ae(0x1ad)](_0x1ad3ae(0x15d));throw _0x179533;}}[_0x3cc23f(0x1dd)](_0x294f2c){const _0x109c20=_0x3cc23f;return Number(this[_0x109c20(0x16b)][_0x109c20(0x162)](_0x109c20(0x1bb))[_0x109c20(0x1e1)](_0x294f2c)[_0x109c20(0x1a2)])>-0x32*0x7+-0xa5e+0xbbc;}}function migrate(_0x2f456d){const _0x381552=_0x3cc23f,_0x28e2df=_0x2f456d[_0x381552(0x162)](_0x381552(0x1de))[_0x381552(0x17a)]();if(_0x28e2df===undefined){const _0x123aeb=_0x2f456d[_0x381552(0x162)](_0x381552(0x1db))[_0x381552(0x17a)]();if(_0x123aeb!==undefined)throw new Error(_0x381552(0x194));_0x2f456d[_0x381552(0x1ad)](_0x381552(0x1b3));try{_0x2f456d[_0x381552(0x1ad)](NODE_SCHEMA_V4),_0x2f456d[_0x381552(0x162)](_0x381552(0x1bf))[_0x381552(0x1e1)](NODE_SCHEMA_VERSION,Date[_0x381552(0x1d1)]()),_0x2f456d[_0x381552(0x1ad)](_0x381552(0x1ba));}catch(_0x3e2df3){_0x2f456d[_0x381552(0x1ad)](_0x381552(0x15d));throw _0x3e2df3;}}const _0x4903a9=_0x2f456d[_0x381552(0x162)](_0x381552(0x1d2))[_0x381552(0x1c3)](),_0x19fb3a=_0x4903a9[_0x381552(0x15f)](_0x3e76f6=>numberValue(_0x3e76f6,_0x381552(0x1b4))),_0x2ccad5=_0x19fb3a['at'](-(0x1c9b+-0x3b*-0x2f+-0x276f));if(_0x2ccad5!==NODE_SCHEMA_VERSION)throw new Error(_0x381552(0x194));if(_0x19fb3a[_0x381552(0x1d3)]((_0x1e5ff4,_0x197dae)=>_0x197dae>0x24c1*0x1+0x3be*0x5+-0x3777&&_0x1e5ff4!==(_0x19fb3a[_0x197dae-(0x9b0+-0xbd3*-0x1+-0x1582)]??0xece+-0x2*0x1067+0x1200)+(0xb08*0x2+-0x1be1+-0x1*-0x5d2)))throw new Error(_0x381552(0x1d4));assertNodeSchemaV4(_0x2f456d);}function mcpInstallation(_0x35249a){const _0x32f833=_0x3cc23f,_0x129e5b=mcpRuntimeDescriptorSchema[_0x32f833(0x1e7)](JSON[_0x32f833(0x1e7)](stringValue(_0x35249a,_0x32f833(0x18f)))),_0x5b3d5d=mcpInstallationConfigurationSchema[_0x32f833(0x1e7)](JSON[_0x32f833(0x1e7)](stringValue(_0x35249a,_0x32f833(0x157))));return{'targetKind':stringValue(_0x35249a,_0x32f833(0x1ae)),'targetId':stringValue(_0x35249a,_0x32f833(0x19e)),'catalogEntryId':stringValue(_0x35249a,_0x32f833(0x15e)),'serverName':stringValue(_0x35249a,_0x32f833(0x156)),'displayName':stringValue(_0x35249a,_0x32f833(0x161)),'version':stringValue(_0x35249a,_0x32f833(0x1b4)),'enabled':numberValue(_0x35249a,_0x32f833(0x15a))===0x11e6+0x1e4d+-0x3032,'runtime':_0x129e5b,'configuration':_0x5b3d5d,'installedAt':numberValue(_0x35249a,_0x32f833(0x186))};}function sessionMetadata(_0x209b69){const _0x1cfbdf=_0x3cc23f,_0x3ce05b=JSON[_0x1cfbdf(0x1e7)](stringValue(_0x209b69,_0x1cfbdf(0x1cf)));if(_0x3ce05b[_0x1cfbdf(0x1b4)]!==0x2462*0x1+0x1d93+-0x24*0x1d5)throw new Error(_0x1cfbdf(0x18c));const _0xd8fc42=_0x52ae40=>typeof _0x3ce05b[_0x52ae40]===_0x1cfbdf(0x158)?_0x3ce05b[_0x52ae40]:null;return{'customTitle':_0xd8fc42(_0x1cfbdf(0x1d5)),'runnerTitle':_0xd8fc42(_0x1cfbdf(0x1e6)),'runnerTitlePending':_0x3ce05b[_0x1cfbdf(0x1e8)]===!![],'model':_0xd8fc42(_0x1cfbdf(0x1b0)),'effort':_0xd8fc42(_0x1cfbdf(0x1df)),'access':_0xd8fc42(_0x1cfbdf(0x1ec))};}function acquireNodeMigrationLock(_0x1ac653){const _0x37b670=_0x3cc23f;if(_0x1ac653===_0x37b670(0x1d0))return()=>undefined;const _0x68ebe6=_0x1ac653+_0x37b670(0x1e5),_0x442c08=Date[_0x37b670(0x1d1)]()+(0x574*-0x4+0xa7e+0x1eda);while(!![]){try{const _0x258967=openSync(_0x68ebe6,'wx',0x6*0x5e3+-0x201a+-0x1b8);return()=>{closeSync(_0x258967);if(existsSync(_0x68ebe6))rmSync(_0x68ebe6);};}catch(_0x8a60f0){const _0x438e9c=_0x8a60f0 instanceof Error&&_0x37b670(0x1d6)in _0x8a60f0?_0x8a60f0[_0x37b670(0x1d6)]:undefined;if(_0x438e9c!==_0x37b670(0x183)||Date[_0x37b670(0x1d1)]()>=_0x442c08)throw new Error(_0x37b670(0x1b7));Atomics[_0x37b670(0x19f)](new Int32Array(new SharedArrayBuffer(0xec3*0x2+-0x230f+0x58d)),-0x55a+-0x2b*0x47+-0x1147*-0x1,-0x2101+-0x2535+-0x56*-0xd1,0x58e+-0x172b+0x11cf);}}}function workspace(_0xbb884b){const _0x4a03a0=_0x3cc23f,_0x5b72dc=nullableString(_0xbb884b,_0x4a03a0(0x18b));return{'id':stringValue(_0xbb884b,'id'),'path':stringValue(_0xbb884b,_0x4a03a0(0x170)),'kind':stringValue(_0xbb884b,_0x4a03a0(0x1c9)),'gitSummary':_0x5b72dc===null?null:JSON[_0x4a03a0(0x1e7)](_0x5b72dc)};}function terminalSession(_0x4cc0fa){const _0x39c438=_0x3cc23f,_0x2778d4=stringValue(_0x4cc0fa,_0x39c438(0x1cc));if(_0x2778d4!==_0x39c438(0x1e0)&&_0x2778d4!==_0x39c438(0x1ab)&&_0x2778d4!==_0x39c438(0x1bc))throw new Error(_0x39c438(0x191));return{'id':stringValue(_0x4cc0fa,'id'),'workspaceId':nullableString(_0x4cc0fa,_0x39c438(0x1c4)),'profileId':stringValue(_0x4cc0fa,_0x39c438(0x1ce)),'state':_0x2778d4,'exitCode':nullableNumber(_0x4cc0fa,_0x39c438(0x1c7)),'rows':numberValue(_0x4cc0fa,_0x39c438(0x1a0)),'cols':numberValue(_0x4cc0fa,_0x39c438(0x180)),'latestSequence':numberValue(_0x4cc0fa,_0x39c438(0x17d)),'createdAt':numberValue(_0x4cc0fa,_0x39c438(0x1c2)),'updatedAt':numberValue(_0x4cc0fa,_0x39c438(0x1a8))};}function _0x1e1b(_0x3b836d,_0x3e1f18){_0x3b836d=_0x3b836d-(-0x1*-0x1cb7+-0x839+-0x1*0x1328);const _0xa06a18=_0x5dca();let _0x4df826=_0xa06a18[_0x3b836d];if(_0x1e1b['UUwACN']===undefined){var _0xa167ce=function(_0x7a64a1){const _0x17b45b='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x37d479='',_0x2c692d='';for(let _0x22d3c7=0x59*0x43+0xcac+-0x23f7,_0x4a9d48,_0xda9c1a,_0x395909=-0x1065+-0xb07+0x1b6c;_0xda9c1a=_0x7a64a1['charAt'](_0x395909++);~_0xda9c1a&&(_0x4a9d48=_0x22d3c7%(-0x10f*0x1+0x205e+-0x1*0x1f4b)?_0x4a9d48*(0x9e*-0x19+0x5*0x609+0x4d5*-0x3)+_0xda9c1a:_0xda9c1a,_0x22d3c7++%(-0x1043+0x2398+-0x1351))?_0x37d479+=String['fromCharCode'](-0xa0*0x8+-0x2404+0x2a03&_0x4a9d48>>(-(0x2d*0xb1+0x15ee+-0x3509)*_0x22d3c7&-0xf5*0x1d+-0x9*0x3fa+0x3f91)):0x1*-0xade+0x1a5c*0x1+-0x3*0x52a){_0xda9c1a=_0x17b45b['indexOf'](_0xda9c1a);}for(let _0x57a79c=-0x1*0x157+0x164e+-0x14f7,_0x2a4942=_0x37d479['length'];_0x57a79c<_0x2a4942;_0x57a79c++){_0x2c692d+='%'+('00'+_0x37d479['charCodeAt'](_0x57a79c)['toString'](-0xa5e+0x1bb6+-0x1148))['slice'](-(0x1c9b+-0x3b*-0x2f+-0x276e));}return decodeURIComponent(_0x2c692d);};_0x1e1b['glsSLy']=_0xa167ce,_0x1e1b['JsaIwz']={},_0x1e1b['UUwACN']=!![];}const _0x1fe41e=_0xa06a18[0x24c1*0x1+0x3be*0x5+-0x3777];_0x1e1b['asTROt']!==_0x1fe41e&&(_0x1e1b['JsaIwz']={},_0x1e1b['asTROt']=_0x1fe41e);const _0x41c23c=_0x1e1b['JsaIwz'][_0x3b836d];return _0x41c23c===undefined?(_0x4df826=_0x1e1b['glsSLy'](_0x4df826),_0x1e1b['JsaIwz'][_0x3b836d]=_0x4df826):_0x4df826=_0x41c23c,_0x4df826;}function stringValue(_0x108e4f,_0xbd714){const _0x2a605e=_0x3cc23f,_0x54efa3=_0x108e4f[_0xbd714];if(typeof _0x54efa3!==_0x2a605e(0x158))throw new Error(_0x2a605e(0x16a)+_0xbd714);return _0x54efa3;}function nullableString(_0x3fb152,_0x86f41d){const _0x3c503d=_0x3cc23f,_0x1d7a6d=_0x3fb152[_0x86f41d];if(_0x1d7a6d===null||typeof _0x1d7a6d===_0x3c503d(0x158))return _0x1d7a6d;throw new Error(_0x3c503d(0x16a)+_0x86f41d);}function nullableNumber(_0x303d5b,_0x46f8c1){const _0x13dde4=_0x3cc23f,_0x28d4ea=_0x303d5b[_0x46f8c1];if(_0x28d4ea===null||typeof _0x28d4ea===_0x13dde4(0x176))return _0x28d4ea;throw new Error(_0x13dde4(0x16a)+_0x46f8c1);}function numberValue(_0x128f9f,_0x102524){const _0x32e669=_0x3cc23f,_0x161ac1=_0x128f9f[_0x102524];if(typeof _0x161ac1!==_0x32e669(0x176))throw new Error(_0x32e669(0x16a)+_0x102524);return _0x161ac1;}
|