@myagentroam/node 0.1.3 → 0.1.6
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/README.md +9 -1
- package/dist/capabilities.d.ts +2 -0
- package/dist/capabilities.js +15 -4
- package/dist/claude-agent-sdk.d.ts +4 -16
- package/dist/claude-agent-sdk.js +18 -79
- package/dist/claude-channel.js +0 -1
- package/dist/codex-app-server.d.ts +5 -0
- package/dist/codex-app-server.js +26 -5
- package/dist/config.d.ts +3 -0
- package/dist/config.js +18 -2
- package/dist/connector/node-connector-options.d.ts +26 -0
- package/dist/connector/node-connector-options.js +1 -0
- package/dist/connector/node-operation-router.d.ts +9 -0
- package/dist/connector/node-operation-router.js +22 -0
- package/dist/connector.d.ts +62 -356
- package/dist/connector.js +714 -6176
- package/dist/control-outbound-scheduler.d.ts +26 -0
- package/dist/control-outbound-scheduler.js +121 -0
- package/dist/database.d.ts +4 -0
- package/dist/database.js +15 -10
- package/dist/event-buffer.js +0 -1
- package/dist/fake-runner.js +0 -1
- package/dist/health.js +0 -1
- package/dist/main.js +6 -1
- package/dist/migrations/v001.js +0 -1
- package/dist/migrations/v002.js +0 -1
- package/dist/migrations/v003.d.ts +4 -0
- package/dist/migrations/v003.js +44 -0
- package/dist/native-jsonl-reader.d.ts +14 -0
- package/dist/native-jsonl-reader.js +97 -0
- package/dist/native-session-history.d.ts +41 -4
- package/dist/native-session-history.js +340 -159
- package/dist/opencode-runtime.d.ts +33 -0
- package/dist/opencode-runtime.js +80 -0
- package/dist/opencode-server.d.ts +47 -0
- package/dist/opencode-server.js +250 -0
- package/dist/operational.js +10 -3
- package/dist/process-tree.js +0 -1
- package/dist/runner/abstract-runner.d.ts +153 -0
- package/dist/runner/abstract-runner.js +154 -0
- package/dist/runner/claude/managed-run-controller.d.ts +52 -0
- package/dist/runner/claude/managed-run-controller.js +326 -0
- package/dist/runner/claude-code-runner.d.ts +70 -0
- package/dist/runner/claude-code-runner.js +286 -0
- package/dist/runner/codex/conversation-parser.d.ts +59 -0
- package/dist/runner/codex/conversation-parser.js +816 -0
- package/dist/runner/codex/managed-run-controller.d.ts +80 -0
- package/dist/runner/codex/managed-run-controller.js +388 -0
- package/dist/runner/codex-runner.d.ts +85 -0
- package/dist/runner/codex-runner.js +365 -0
- package/dist/runner/fake-test-runner.d.ts +26 -0
- package/dist/runner/fake-test-runner.js +47 -0
- package/dist/runner/opencode/conversation-parser.d.ts +27 -0
- package/dist/runner/opencode/conversation-parser.js +217 -0
- package/dist/runner/opencode/managed-run-controller.d.ts +76 -0
- package/dist/runner/opencode/managed-run-controller.js +451 -0
- package/dist/runner/opencode-runner.d.ts +60 -0
- package/dist/runner/opencode-runner.js +330 -0
- package/dist/runner/runner-registry.d.ts +19 -0
- package/dist/runner/runner-registry.js +75 -0
- package/dist/runner-command-engine.js +0 -1
- package/dist/runner-profiles.d.ts +4 -0
- package/dist/runner-profiles.js +76 -3
- package/dist/runner-usage.d.ts +2 -2
- package/dist/runner-usage.js +3 -6
- package/dist/runtime-state.js +26 -14
- package/dist/service/attachment-domain-state.d.ts +5 -0
- package/dist/service/attachment-domain-state.js +5 -0
- package/dist/service/conversation-history-service.d.ts +34 -0
- package/dist/service/conversation-history-service.js +158 -0
- package/dist/service/external-session-resume-service.d.ts +32 -0
- package/dist/service/external-session-resume-service.js +98 -0
- package/dist/service/fake-managed-run-service.d.ts +29 -0
- package/dist/service/fake-managed-run-service.js +62 -0
- package/dist/service/managed-runner-session-service.d.ts +12 -0
- package/dist/service/managed-runner-session-service.js +35 -0
- package/dist/service/native-session-projection-service.d.ts +51 -0
- package/dist/service/native-session-projection-service.js +271 -0
- package/dist/service/native-session-watch-service.d.ts +37 -0
- package/dist/service/native-session-watch-service.js +150 -0
- package/dist/service/node-connection-lifecycle-service.d.ts +37 -0
- package/dist/service/node-connection-lifecycle-service.js +85 -0
- package/dist/service/node-control-channel.d.ts +32 -0
- package/dist/service/node-control-channel.js +85 -0
- package/dist/service/node-control-message-service.d.ts +28 -0
- package/dist/service/node-control-message-service.js +104 -0
- package/dist/service/node-request-service.d.ts +14 -0
- package/dist/service/node-request-service.js +50 -0
- package/dist/service/node-run-event-bridge.d.ts +40 -0
- package/dist/service/node-run-event-bridge.js +83 -0
- package/dist/service/node-terminal-channel.d.ts +29 -0
- package/dist/service/node-terminal-channel.js +182 -0
- package/dist/service/node-upgrade-coordinator.d.ts +29 -0
- package/dist/service/node-upgrade-coordinator.js +137 -0
- package/dist/service/node-workspace-coordinator.d.ts +32 -0
- package/dist/service/node-workspace-coordinator.js +80 -0
- package/dist/service/run-attachment-service.d.ts +37 -0
- package/dist/service/run-attachment-service.js +160 -0
- package/dist/service/run-domain-state.d.ts +4 -0
- package/dist/service/run-domain-state.js +4 -0
- package/dist/service/run-event-service.d.ts +31 -0
- package/dist/service/run-event-service.js +102 -0
- package/dist/service/run-workbench-service.d.ts +27 -0
- package/dist/service/run-workbench-service.js +113 -0
- package/dist/service/runner-channel-message-service.d.ts +13 -0
- package/dist/service/runner-channel-message-service.js +20 -0
- package/dist/service/runner-interaction-service.d.ts +40 -0
- package/dist/service/runner-interaction-service.js +246 -0
- package/dist/service/runner-service.d.ts +44 -0
- package/dist/service/runner-service.js +68 -0
- package/dist/service/session-catalog-service.d.ts +45 -0
- package/dist/service/session-catalog-service.js +224 -0
- package/dist/service/session-command-service.d.ts +23 -0
- package/dist/service/session-command-service.js +69 -0
- package/dist/service/session-context-service.d.ts +34 -0
- package/dist/service/session-context-service.js +87 -0
- package/dist/service/session-domain-state.d.ts +8 -0
- package/dist/service/session-domain-state.js +8 -0
- package/dist/service/session-identity-service.d.ts +24 -0
- package/dist/service/session-identity-service.js +86 -0
- package/dist/service/session-lifecycle-service.d.ts +31 -0
- package/dist/service/session-lifecycle-service.js +242 -0
- package/dist/service/session-message-service.d.ts +33 -0
- package/dist/service/session-message-service.js +157 -0
- package/dist/service/session-presentation-service.d.ts +33 -0
- package/dist/service/session-presentation-service.js +36 -0
- package/dist/service/session-query-service.d.ts +31 -0
- package/dist/service/session-query-service.js +77 -0
- package/dist/service/terminal-relay-state.d.ts +6 -0
- package/dist/service/terminal-relay-state.js +3 -0
- package/dist/service/terminal-service.d.ts +12 -0
- package/dist/service/terminal-service.js +52 -0
- package/dist/service/workbench-event-service.d.ts +21 -0
- package/dist/service/workbench-event-service.js +53 -0
- package/dist/service/workbench-manifest-service.d.ts +89 -0
- package/dist/service/workbench-manifest-service.js +70 -0
- package/dist/service/workspace-change-service.d.ts +9 -0
- package/dist/service/workspace-change-service.js +86 -0
- package/dist/service/workspace-content-search-service.d.ts +14 -0
- package/dist/service/workspace-content-search-service.js +477 -0
- package/dist/service/workspace-domain-state.d.ts +75 -0
- package/dist/service/workspace-domain-state.js +40 -0
- package/dist/service/workspace-file-service.d.ts +17 -0
- package/dist/service/workspace-file-service.js +109 -0
- package/dist/service/workspace-queue-workbench-service.d.ts +55 -0
- package/dist/service/workspace-queue-workbench-service.js +226 -0
- package/dist/service/workspace-service.d.ts +15 -0
- package/dist/service/workspace-service.js +67 -0
- package/dist/service/workspace-session-service.d.ts +23 -0
- package/dist/service/workspace-session-service.js +139 -0
- package/dist/service/workspace-upload-service.d.ts +37 -0
- package/dist/service/workspace-upload-service.js +240 -0
- package/dist/service/workspace-watch-service.d.ts +18 -0
- package/dist/service/workspace-watch-service.js +120 -0
- package/dist/service/workspace-workbench-service.d.ts +47 -0
- package/dist/service/workspace-workbench-service.js +223 -0
- package/dist/service.js +2 -3
- package/dist/storage.js +0 -1
- package/dist/supervisor.d.ts +1 -0
- package/dist/supervisor.js +154 -0
- package/dist/terminal.d.ts +1 -0
- package/dist/terminal.js +1 -2
- package/dist/util/node-operation-parsers.d.ts +92 -0
- package/dist/util/node-operation-parsers.js +382 -0
- package/dist/util/runner-native-session-parsers.d.ts +72 -0
- package/dist/util/runner-native-session-parsers.js +381 -0
- package/dist/util/secret-environment.d.ts +1 -0
- package/dist/util/secret-environment.js +25 -0
- package/dist/workspace.d.ts +62 -2
- package/dist/workspace.js +539 -57
- package/package.json +3 -2
- package/dist/capabilities.js.map +0 -1
- package/dist/claude-agent-sdk.js.map +0 -1
- package/dist/claude-channel.js.map +0 -1
- package/dist/codex-app-server.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/connector.js.map +0 -1
- package/dist/database.js.map +0 -1
- package/dist/event-buffer.js.map +0 -1
- package/dist/fake-runner.js.map +0 -1
- package/dist/health.js.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/migrations/v001.js.map +0 -1
- package/dist/migrations/v002.js.map +0 -1
- package/dist/native-session-history.js.map +0 -1
- package/dist/operational.js.map +0 -1
- package/dist/process-tree.js.map +0 -1
- package/dist/runner-command-engine.js.map +0 -1
- package/dist/runner-profiles.js.map +0 -1
- package/dist/runner-usage.js.map +0 -1
- package/dist/runtime-state.js.map +0 -1
- package/dist/service.js.map +0 -1
- package/dist/storage.js.map +0 -1
- package/dist/terminal.js.map +0 -1
- package/dist/workspace.js.map +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { NodeEnvelope } from '@myagentroam/protocol';
|
|
2
|
+
interface WritableControlSocket {
|
|
3
|
+
readonly readyState: number;
|
|
4
|
+
readonly bufferedAmount: number;
|
|
5
|
+
send(value: string): void;
|
|
6
|
+
}
|
|
7
|
+
/** Keeps control responses responsive while reliable Workbench events are busy. */
|
|
8
|
+
export declare class ControlOutboundScheduler {
|
|
9
|
+
private readonly socket;
|
|
10
|
+
private readonly high;
|
|
11
|
+
private readonly normal;
|
|
12
|
+
private scheduled;
|
|
13
|
+
private retryTimer;
|
|
14
|
+
private backpressureStartedAt;
|
|
15
|
+
private backpressureLogged;
|
|
16
|
+
private maximumHighDepth;
|
|
17
|
+
private maximumNormalDepth;
|
|
18
|
+
constructor(socket: () => WritableControlSocket | undefined);
|
|
19
|
+
enqueue(envelope: NodeEnvelope, priority: 'high' | 'normal'): void;
|
|
20
|
+
reset(): void;
|
|
21
|
+
private schedule;
|
|
22
|
+
private flush;
|
|
23
|
+
private waitForBackpressure;
|
|
24
|
+
private finishBackpressure;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { nodeLog } from './operational.js';
|
|
2
|
+
const MAX_FRAMES_PER_TURN = 32;
|
|
3
|
+
const MAX_BYTES_PER_TURN = 256 * 1024;
|
|
4
|
+
const SOCKET_NORMAL_DIRECT_WATER_BYTES = 256 * 1024;
|
|
5
|
+
const SOCKET_HIGH_WATER_BYTES = 1024 * 1024;
|
|
6
|
+
const BACKPRESSURE_RETRY_MS = 5;
|
|
7
|
+
/** Keeps control responses responsive while reliable Workbench events are busy. */
|
|
8
|
+
export class ControlOutboundScheduler {
|
|
9
|
+
socket;
|
|
10
|
+
high = [];
|
|
11
|
+
normal = [];
|
|
12
|
+
scheduled = false;
|
|
13
|
+
retryTimer;
|
|
14
|
+
backpressureStartedAt;
|
|
15
|
+
backpressureLogged = false;
|
|
16
|
+
maximumHighDepth = 0;
|
|
17
|
+
maximumNormalDepth = 0;
|
|
18
|
+
constructor(socket) {
|
|
19
|
+
this.socket = socket;
|
|
20
|
+
}
|
|
21
|
+
enqueue(envelope, priority) {
|
|
22
|
+
const socket = this.socket();
|
|
23
|
+
const bufferedAmount = socket?.bufferedAmount ?? 0;
|
|
24
|
+
if (socket !== undefined &&
|
|
25
|
+
socket.readyState === 1 &&
|
|
26
|
+
this.high.length === 0 &&
|
|
27
|
+
(priority === 'high' || this.normal.length === 0) &&
|
|
28
|
+
bufferedAmount <= SOCKET_NORMAL_DIRECT_WATER_BYTES) {
|
|
29
|
+
socket.send(JSON.stringify(envelope));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
(priority === 'high' ? this.high : this.normal).push(envelope);
|
|
33
|
+
this.maximumHighDepth = Math.max(this.maximumHighDepth, this.high.length);
|
|
34
|
+
this.maximumNormalDepth = Math.max(this.maximumNormalDepth, this.normal.length);
|
|
35
|
+
this.schedule();
|
|
36
|
+
}
|
|
37
|
+
reset() {
|
|
38
|
+
this.high.length = 0;
|
|
39
|
+
this.normal.length = 0;
|
|
40
|
+
this.scheduled = false;
|
|
41
|
+
if (this.retryTimer !== undefined)
|
|
42
|
+
clearTimeout(this.retryTimer);
|
|
43
|
+
this.retryTimer = undefined;
|
|
44
|
+
this.finishBackpressure('reset');
|
|
45
|
+
}
|
|
46
|
+
schedule() {
|
|
47
|
+
if (this.scheduled || this.retryTimer !== undefined)
|
|
48
|
+
return;
|
|
49
|
+
this.scheduled = true;
|
|
50
|
+
setImmediate(() => this.flush());
|
|
51
|
+
}
|
|
52
|
+
flush() {
|
|
53
|
+
this.scheduled = false;
|
|
54
|
+
const socket = this.socket();
|
|
55
|
+
if (socket === undefined || socket.readyState !== 1)
|
|
56
|
+
return;
|
|
57
|
+
if ((socket.bufferedAmount ?? 0) > SOCKET_HIGH_WATER_BYTES) {
|
|
58
|
+
this.waitForBackpressure(socket, 'high');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
let frames = 0;
|
|
62
|
+
let bytes = 0;
|
|
63
|
+
while (frames < MAX_FRAMES_PER_TURN) {
|
|
64
|
+
const queue = this.high.length > 0 ? this.high : this.normal;
|
|
65
|
+
const envelope = queue[0];
|
|
66
|
+
if (envelope === undefined)
|
|
67
|
+
break;
|
|
68
|
+
// Reliable Workbench events may be replayed in a large burst after a
|
|
69
|
+
// reconnect. Stop normal traffic early so a later HTTP/control response
|
|
70
|
+
// always has WebSocket buffer headroom instead of waiting behind that burst.
|
|
71
|
+
if (queue === this.normal &&
|
|
72
|
+
(socket.bufferedAmount ?? 0) > SOCKET_NORMAL_DIRECT_WATER_BYTES) {
|
|
73
|
+
this.waitForBackpressure(socket, 'normal');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const serialized = JSON.stringify(envelope);
|
|
77
|
+
const size = Buffer.byteLength(serialized);
|
|
78
|
+
if (frames > 0 && bytes + size > MAX_BYTES_PER_TURN)
|
|
79
|
+
break;
|
|
80
|
+
queue.shift();
|
|
81
|
+
socket.send(serialized);
|
|
82
|
+
frames += 1;
|
|
83
|
+
bytes += size;
|
|
84
|
+
if ((socket.bufferedAmount ?? 0) > SOCKET_HIGH_WATER_BYTES)
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
if (this.high.length > 0 || this.normal.length > 0)
|
|
88
|
+
this.schedule();
|
|
89
|
+
else
|
|
90
|
+
this.finishBackpressure('drained');
|
|
91
|
+
}
|
|
92
|
+
waitForBackpressure(socket, level) {
|
|
93
|
+
this.backpressureStartedAt ??= Date.now();
|
|
94
|
+
if (!this.backpressureLogged && Date.now() - this.backpressureStartedAt >= 250) {
|
|
95
|
+
this.backpressureLogged = true;
|
|
96
|
+
nodeLog('control.outbound.backpressure', {
|
|
97
|
+
level,
|
|
98
|
+
bufferedBytes: socket.bufferedAmount,
|
|
99
|
+
highDepth: this.high.length,
|
|
100
|
+
normalDepth: this.normal.length
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
this.retryTimer = setTimeout(() => {
|
|
104
|
+
this.retryTimer = undefined;
|
|
105
|
+
this.schedule();
|
|
106
|
+
}, BACKPRESSURE_RETRY_MS);
|
|
107
|
+
}
|
|
108
|
+
finishBackpressure(reason) {
|
|
109
|
+
if (this.backpressureLogged)
|
|
110
|
+
nodeLog('control.outbound.backpressure.recovered', {
|
|
111
|
+
reason,
|
|
112
|
+
durationMs: Date.now() - (this.backpressureStartedAt ?? Date.now()),
|
|
113
|
+
maximumHighDepth: this.maximumHighDepth,
|
|
114
|
+
maximumNormalDepth: this.maximumNormalDepth
|
|
115
|
+
});
|
|
116
|
+
this.backpressureStartedAt = undefined;
|
|
117
|
+
this.backpressureLogged = false;
|
|
118
|
+
this.maximumHighDepth = 0;
|
|
119
|
+
this.maximumNormalDepth = 0;
|
|
120
|
+
}
|
|
121
|
+
}
|
package/dist/database.d.ts
CHANGED
|
@@ -106,6 +106,10 @@ export interface NodeConversationTurn {
|
|
|
106
106
|
readonly model: string | null;
|
|
107
107
|
readonly effort: string | null;
|
|
108
108
|
readonly access: string | null;
|
|
109
|
+
readonly rewind?: {
|
|
110
|
+
readonly before: string | null;
|
|
111
|
+
readonly after: string;
|
|
112
|
+
};
|
|
109
113
|
readonly items: readonly NodeConversationItem[];
|
|
110
114
|
readonly startedAt: number | null;
|
|
111
115
|
readonly completedAt: number | null;
|
package/dist/database.js
CHANGED
|
@@ -4,8 +4,9 @@ import { dirname } from 'node:path';
|
|
|
4
4
|
import { DatabaseSync } from 'node:sqlite';
|
|
5
5
|
import { runnerDefaultConfigurationSchema } from '@myagentroam/protocol';
|
|
6
6
|
import { assertNodeSchema, NODE_SCHEMA_V1 } from './migrations/v001.js';
|
|
7
|
-
import { assertNodeSchemaV2, migrateNodeSchemaV2
|
|
8
|
-
|
|
7
|
+
import { assertNodeSchemaV2, migrateNodeSchemaV2 } from './migrations/v002.js';
|
|
8
|
+
import { assertNodeSchemaV3, migrateNodeSchemaV3, NODE_SCHEMA_VERSION_V3 } from './migrations/v003.js';
|
|
9
|
+
const NODE_SCHEMA_VERSION = NODE_SCHEMA_VERSION_V3;
|
|
9
10
|
export class NodeDatabase {
|
|
10
11
|
now;
|
|
11
12
|
activeWorkspaceLeaseCount() {
|
|
@@ -610,7 +611,7 @@ export class NodeDatabase {
|
|
|
610
611
|
ORDER BY rowid DESC LIMIT ?`)
|
|
611
612
|
.all(input.sessionId, input.nativeOnly === true ? 1 : 0, cursor?.value ?? null, cursor?.value ?? 0, limit + 1);
|
|
612
613
|
const page = rows.slice(0, limit);
|
|
613
|
-
const turns = page.map((row) => this.readConversationTurn(row));
|
|
614
|
+
const turns = page.map((row) => this.readConversationTurn(row)).reverse();
|
|
614
615
|
const last = page.at(-1);
|
|
615
616
|
return {
|
|
616
617
|
turns,
|
|
@@ -1025,6 +1026,8 @@ function migrate(database) {
|
|
|
1025
1026
|
.prepare('INSERT INTO node_schema_migrations (version, applied_at) VALUES (?, ?), (?, ?)')
|
|
1026
1027
|
.run(1, Date.now(), 2, Date.now());
|
|
1027
1028
|
database.exec('COMMIT');
|
|
1029
|
+
migrateNodeSchemaV3(database);
|
|
1030
|
+
assertNodeSchemaV3(database);
|
|
1028
1031
|
return;
|
|
1029
1032
|
}
|
|
1030
1033
|
catch (error) {
|
|
@@ -1061,6 +1064,8 @@ function migrate(database) {
|
|
|
1061
1064
|
}
|
|
1062
1065
|
migrateNodeSchemaV2(database);
|
|
1063
1066
|
assertNodeSchemaV2(database);
|
|
1067
|
+
migrateNodeSchemaV3(database);
|
|
1068
|
+
assertNodeSchemaV3(database);
|
|
1064
1069
|
return;
|
|
1065
1070
|
}
|
|
1066
1071
|
if (current === 0) {
|
|
@@ -1082,12 +1087,12 @@ function migrate(database) {
|
|
|
1082
1087
|
.get();
|
|
1083
1088
|
if (numberValue(afterBaseline, 'version') === 1)
|
|
1084
1089
|
migrateNodeSchemaV2(database);
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1090
|
+
const afterV2 = database
|
|
1091
|
+
.prepare('SELECT MAX(version) AS version FROM node_schema_migrations')
|
|
1092
|
+
.get();
|
|
1093
|
+
if (numberValue(afterV2, 'version') === 2)
|
|
1094
|
+
migrateNodeSchemaV3(database);
|
|
1095
|
+
assertNodeSchemaV3(database);
|
|
1091
1096
|
}
|
|
1092
1097
|
function sessionMetadata(row) {
|
|
1093
1098
|
const raw = JSON.parse(stringValue(row, 'metadata'));
|
|
@@ -1130,6 +1135,7 @@ function initializeEphemeralRuntimeTables(database) {
|
|
|
1130
1135
|
if (match === null || !runtimeTables.has(match[1] ?? ''))
|
|
1131
1136
|
continue;
|
|
1132
1137
|
database.exec(statement
|
|
1138
|
+
.replaceAll("runner IN ('codex', 'claude-code')", "runner IN ('codex', 'claude-code', 'opencode')")
|
|
1133
1139
|
.replace(/^CREATE TABLE IF NOT EXISTS/, 'CREATE TEMP TABLE IF NOT EXISTS')
|
|
1134
1140
|
.replace('CREATE TEMP TABLE IF NOT EXISTS agent_sessions', 'CREATE TEMP TABLE IF NOT EXISTS legacy_agent_sessions')
|
|
1135
1141
|
.replaceAll('REFERENCES agent_sessions', 'REFERENCES legacy_agent_sessions')
|
|
@@ -1389,4 +1395,3 @@ function transitionAllowed(current, next) {
|
|
|
1389
1395
|
(current === 'CANCELLING' &&
|
|
1390
1396
|
(next === 'CANCELLED' || next === 'FAILED' || next === 'INTERRUPTED')));
|
|
1391
1397
|
}
|
|
1392
|
-
//# sourceMappingURL=database.js.map
|
package/dist/event-buffer.js
CHANGED
package/dist/fake-runner.js
CHANGED
package/dist/health.js
CHANGED
package/dist/main.js
CHANGED
|
@@ -4,6 +4,7 @@ import { NodeConnector } from './connector.js';
|
|
|
4
4
|
import { loadNodeConfig, nodeConfigPath, nodeDatabasePath } from './config.js';
|
|
5
5
|
import { getNodeHealth } from './health.js';
|
|
6
6
|
import { removeServiceDefinition, writeServiceDefinition } from './service.js';
|
|
7
|
+
import { superviseNode } from './supervisor.js';
|
|
7
8
|
const [command = 'status', ...args] = process.argv.slice(2);
|
|
8
9
|
const config = readOption(args, '--config') ?? nodeConfigPath();
|
|
9
10
|
const output = readOption(args, '--output') ?? defaultServicePath();
|
|
@@ -14,6 +15,11 @@ if (command === 'run') {
|
|
|
14
15
|
process.once(signal, () => connector.stop());
|
|
15
16
|
}
|
|
16
17
|
}
|
|
18
|
+
else if (command === 'supervise') {
|
|
19
|
+
if (process.argv[1] === undefined)
|
|
20
|
+
throw new Error('NODE_ENTRYPOINT_UNAVAILABLE');
|
|
21
|
+
await superviseNode(config, process.argv[1]);
|
|
22
|
+
}
|
|
17
23
|
else if (command === 'install') {
|
|
18
24
|
await writeCurrentServiceDefinition(output, config);
|
|
19
25
|
process.stdout.write(`${output}\n`);
|
|
@@ -44,4 +50,3 @@ async function writeCurrentServiceDefinition(output, configPath) {
|
|
|
44
50
|
const nodeConfig = await loadNodeConfig(configPath);
|
|
45
51
|
await writeServiceDefinition(output, process.execPath, configPath, process.platform, process.argv[1], [dirname(nodeDatabasePath(nodeConfig, configPath)), ...nodeConfig.allowedRoots]);
|
|
46
52
|
}
|
|
47
|
-
//# sourceMappingURL=main.js.map
|
package/dist/migrations/v001.js
CHANGED
package/dist/migrations/v002.js
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export const NODE_SCHEMA_VERSION_V3 = 3;
|
|
2
|
+
export function migrateNodeSchemaV3(database) {
|
|
3
|
+
database.exec('PRAGMA foreign_keys = OFF');
|
|
4
|
+
database.exec('BEGIN IMMEDIATE');
|
|
5
|
+
try {
|
|
6
|
+
database.exec(`ALTER TABLE agent_sessions RENAME TO agent_sessions_v2;
|
|
7
|
+
CREATE TABLE agent_sessions (
|
|
8
|
+
id TEXT PRIMARY KEY,
|
|
9
|
+
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
10
|
+
runner TEXT NOT NULL CHECK (runner IN ('codex', 'claude-code', 'opencode')),
|
|
11
|
+
pin_order INTEGER CHECK (pin_order IS NULL OR pin_order >= 0),
|
|
12
|
+
metadata TEXT NOT NULL CHECK (json_valid(metadata))
|
|
13
|
+
) STRICT;
|
|
14
|
+
INSERT INTO agent_sessions SELECT * FROM agent_sessions_v2;
|
|
15
|
+
DROP TABLE agent_sessions_v2;
|
|
16
|
+
ALTER TABLE runner_defaults RENAME TO runner_defaults_v2;
|
|
17
|
+
CREATE TABLE runner_defaults (
|
|
18
|
+
runner TEXT PRIMARY KEY CHECK (runner IN ('codex', 'claude-code', 'opencode')),
|
|
19
|
+
model TEXT NOT NULL, effort TEXT NOT NULL, access TEXT NOT NULL
|
|
20
|
+
) STRICT;
|
|
21
|
+
INSERT INTO runner_defaults SELECT * FROM runner_defaults_v2;
|
|
22
|
+
DROP TABLE runner_defaults_v2;`);
|
|
23
|
+
database
|
|
24
|
+
.prepare('INSERT INTO node_schema_migrations (version, applied_at) VALUES (?, ?)')
|
|
25
|
+
.run(NODE_SCHEMA_VERSION_V3, Date.now());
|
|
26
|
+
database.exec('COMMIT');
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
database.exec('ROLLBACK');
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
database.exec('PRAGMA foreign_keys = ON');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function assertNodeSchemaV3(database) {
|
|
37
|
+
for (const table of ['agent_sessions', 'runner_defaults']) {
|
|
38
|
+
const row = database
|
|
39
|
+
.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?")
|
|
40
|
+
.get(table);
|
|
41
|
+
if (typeof row?.sql !== 'string' || !row.sql.includes("'opencode'"))
|
|
42
|
+
throw new Error(`NODE_DATABASE_SCHEMA_INVALID:${table}:runner`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface JsonlWindow {
|
|
2
|
+
readonly content: string;
|
|
3
|
+
readonly truncated: boolean;
|
|
4
|
+
readonly size: number;
|
|
5
|
+
}
|
|
6
|
+
/** Reads bounded head/tail windows without ever loading an unbounded transcript. */
|
|
7
|
+
export declare function readJsonlWindow(path: string, options: {
|
|
8
|
+
readonly headBytes?: number;
|
|
9
|
+
readonly tailBytes?: number;
|
|
10
|
+
}): Promise<JsonlWindow | undefined>;
|
|
11
|
+
/** Parses records one at a time, avoiding the allocation of a full line array. */
|
|
12
|
+
export declare function forEachJsonlRecord(content: string, visit: (record: Record<string, unknown>) => void): void;
|
|
13
|
+
export declare function listJsonlFiles(directory: string): Promise<readonly string[]>;
|
|
14
|
+
export declare function mapConcurrent<T, R>(values: readonly T[], concurrency: number, map: (value: T, index: number) => Promise<R>): Promise<readonly R[]>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { open, readdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/** Reads bounded head/tail windows without ever loading an unbounded transcript. */
|
|
4
|
+
export async function readJsonlWindow(path, options) {
|
|
5
|
+
try {
|
|
6
|
+
const handle = await open(path, 'r');
|
|
7
|
+
try {
|
|
8
|
+
const metadata = await handle.stat();
|
|
9
|
+
const headSize = Math.min(options.headBytes ?? 0, metadata.size);
|
|
10
|
+
const remaining = metadata.size - headSize;
|
|
11
|
+
const tailSize = Math.min(options.tailBytes ?? 0, remaining);
|
|
12
|
+
const head = await readAt(handle, headSize, 0);
|
|
13
|
+
const tailOffset = metadata.size - tailSize;
|
|
14
|
+
const tail = await readAt(handle, tailSize, tailOffset);
|
|
15
|
+
const contiguous = headSize > 0 && tailSize > 0 && tailOffset === headSize;
|
|
16
|
+
return {
|
|
17
|
+
content: contiguous
|
|
18
|
+
? Buffer.concat([head, tail]).toString('utf8')
|
|
19
|
+
: `${head.toString('utf8')}${headSize > 0 && tailSize > 0 ? '\n' : ''}${tail.toString('utf8')}`,
|
|
20
|
+
truncated: headSize + tailSize < metadata.size,
|
|
21
|
+
size: metadata.size
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
await handle.close();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Parses records one at a time, avoiding the allocation of a full line array. */
|
|
33
|
+
export function forEachJsonlRecord(content, visit) {
|
|
34
|
+
let start = 0;
|
|
35
|
+
while (start < content.length) {
|
|
36
|
+
const newline = content.indexOf('\n', start);
|
|
37
|
+
const end = newline < 0 ? content.length : newline;
|
|
38
|
+
if (end > start) {
|
|
39
|
+
try {
|
|
40
|
+
const value = JSON.parse(content.slice(start, end));
|
|
41
|
+
if (isRecord(value))
|
|
42
|
+
visit(value);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// A partial or damaged record does not hide subsequent valid records.
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (newline < 0)
|
|
49
|
+
return;
|
|
50
|
+
start = newline + 1;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export async function listJsonlFiles(directory) {
|
|
54
|
+
const files = [];
|
|
55
|
+
const walk = async (current) => {
|
|
56
|
+
let entries;
|
|
57
|
+
try {
|
|
58
|
+
entries = await readdir(current, { withFileTypes: true });
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
for (const entry of entries) {
|
|
64
|
+
const path = join(current, entry.name);
|
|
65
|
+
if (entry.isDirectory())
|
|
66
|
+
await walk(path);
|
|
67
|
+
else if (entry.isFile() && entry.name.endsWith('.jsonl'))
|
|
68
|
+
files.push(path);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
await walk(directory);
|
|
72
|
+
return files;
|
|
73
|
+
}
|
|
74
|
+
export async function mapConcurrent(values, concurrency, map) {
|
|
75
|
+
const results = Array(values.length);
|
|
76
|
+
let next = 0;
|
|
77
|
+
const worker = async () => {
|
|
78
|
+
while (true) {
|
|
79
|
+
const index = next++;
|
|
80
|
+
if (index >= values.length)
|
|
81
|
+
return;
|
|
82
|
+
results[index] = await map(values[index], index);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
await Promise.all(Array.from({ length: Math.min(Math.max(1, concurrency), values.length) }, worker));
|
|
86
|
+
return results;
|
|
87
|
+
}
|
|
88
|
+
async function readAt(handle, size, position) {
|
|
89
|
+
if (size === 0)
|
|
90
|
+
return Buffer.alloc(0);
|
|
91
|
+
const buffer = Buffer.allocUnsafe(size);
|
|
92
|
+
const { bytesRead } = await handle.read(buffer, 0, size, position);
|
|
93
|
+
return buffer.subarray(0, bytesRead);
|
|
94
|
+
}
|
|
95
|
+
function isRecord(value) {
|
|
96
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
97
|
+
}
|
|
@@ -4,6 +4,7 @@ export interface NativeTranscriptMessage {
|
|
|
4
4
|
readonly role: 'USER' | 'ASSISTANT';
|
|
5
5
|
readonly text: string;
|
|
6
6
|
readonly createdAt: number | null;
|
|
7
|
+
readonly nativeId?: string;
|
|
7
8
|
}
|
|
8
9
|
export interface NativeTranscriptToolCall {
|
|
9
10
|
readonly kind: 'tool_call';
|
|
@@ -14,10 +15,35 @@ export interface NativeTranscriptToolCall {
|
|
|
14
15
|
readonly inputTruncated: boolean;
|
|
15
16
|
readonly outputSummary: string | null;
|
|
16
17
|
readonly outputTruncated: boolean;
|
|
18
|
+
/** Metadata only: native transcript image bytes are never retained here. */
|
|
19
|
+
readonly imageAttachments?: readonly NativeTranscriptImageAttachment[];
|
|
17
20
|
readonly failed: boolean;
|
|
18
21
|
readonly createdAt: number | null;
|
|
22
|
+
readonly nativeId?: string;
|
|
19
23
|
}
|
|
20
|
-
export
|
|
24
|
+
export interface NativeTranscriptUnknown {
|
|
25
|
+
readonly kind: 'unknown';
|
|
26
|
+
readonly sourceEventType: string;
|
|
27
|
+
readonly label: string;
|
|
28
|
+
readonly createdAt: number | null;
|
|
29
|
+
readonly nativeId?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface NativeTranscriptReasoningSummary {
|
|
32
|
+
readonly kind: 'reasoning_summary';
|
|
33
|
+
readonly sections: readonly {
|
|
34
|
+
readonly index: number;
|
|
35
|
+
readonly text: string;
|
|
36
|
+
}[];
|
|
37
|
+
readonly createdAt: number | null;
|
|
38
|
+
readonly nativeId?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface NativeTranscriptImageAttachment {
|
|
41
|
+
readonly name: string;
|
|
42
|
+
readonly mime: string;
|
|
43
|
+
/** Codex-owned local artifact path; never sent to Web. */
|
|
44
|
+
readonly localPath?: string;
|
|
45
|
+
}
|
|
46
|
+
export type NativeTranscriptItem = NativeTranscriptMessage | NativeTranscriptToolCall | NativeTranscriptReasoningSummary | NativeTranscriptUnknown;
|
|
21
47
|
export interface NativeSessionHistory {
|
|
22
48
|
readonly runner: RunnerName;
|
|
23
49
|
readonly externalSessionId: string;
|
|
@@ -39,9 +65,11 @@ export interface NativeCodexContextUsage {
|
|
|
39
65
|
readonly usedTokens: number;
|
|
40
66
|
readonly maxTokens: number;
|
|
41
67
|
}
|
|
42
|
-
export
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
export interface NativeClaudeContextUsage {
|
|
69
|
+
readonly model: string;
|
|
70
|
+
readonly usedTokens: number;
|
|
71
|
+
readonly maxTokens: number;
|
|
72
|
+
}
|
|
45
73
|
/**
|
|
46
74
|
* Read-only adapter for the supported vendor JSONL stores. It requires an
|
|
47
75
|
* explicit cwd on the record and returns normalized visible messages and tool
|
|
@@ -63,6 +91,15 @@ export declare function readNativeSession(runner: RunnerName, workspacePath: str
|
|
|
63
91
|
* full-history scan.
|
|
64
92
|
*/
|
|
65
93
|
export declare function readCodexNativeContextUsage(workspacePath: string, externalSessionId: string): Promise<NativeCodexContextUsage | undefined>;
|
|
94
|
+
/** Reads the latest actual Claude prompt occupancy without starting a CLI/SDK control stream. */
|
|
95
|
+
export declare function readClaudeNativeContextUsage(workspacePath: string, externalSessionId: string, options?: {
|
|
96
|
+
readonly environment?: NodeJS.ProcessEnv;
|
|
97
|
+
readonly settingsPath?: string;
|
|
98
|
+
}): Promise<NativeClaudeContextUsage | undefined>;
|
|
99
|
+
export declare function claudeContextWindowTokens(options?: {
|
|
100
|
+
readonly environment?: NodeJS.ProcessEnv;
|
|
101
|
+
readonly settingsPath?: string;
|
|
102
|
+
}): Promise<number>;
|
|
66
103
|
/**
|
|
67
104
|
* Permanently removes exactly one previously discovered transcript. The
|
|
68
105
|
* caller supplies no path: the in-process discovery index resolves it, then
|