@platless/axom-cli 0.3.13 → 0.5.9
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/axom-patch/cli/README.md +30 -8
- package/dist/axom-patch/cli/account-limits/README.md +27 -0
- package/dist/axom-patch/cli/account-limits/antigravity-proxy.mjs +47 -0
- package/dist/axom-patch/cli/account-limits/antigravity-read.mjs +90 -0
- package/dist/axom-patch/cli/account-limits/antigravity.mjs +46 -0
- package/dist/axom-patch/cli/account-limits/generate.py +120 -0
- package/dist/axom-patch/cli/account-limits/kimi-proxy.mjs +64 -0
- package/dist/axom-patch/cli/account-limits/normalize.mjs +151 -0
- package/dist/axom-patch/cli/claude-account-limits.json +37 -0
- package/dist/axom-patch/cli/codex-account-limits.json +37 -0
- package/dist/axom-patch/cli/commandcode-account-limits.json +30 -0
- package/dist/axom-patch/cli/nightly-task.md +152 -0
- package/dist/axom-patch/cli/pi-subagent-subwork.json +23 -0
- package/dist/axom-patch/cli/probes/claude-late-async-terminal.mjs +5 -1
- package/dist/axom-patch/cli/probes/pi-subagent-subwork.mjs +211 -0
- package/dist/axom-patch/cli/probes/qoder-steering.mjs +1 -1
- package/dist/axom-patch/cli/probes/qoder-subagent-origin.mjs +20 -8
- package/dist/axom-patch/cli/probes/zcode-subagent-subwork.mjs +257 -0
- package/dist/axom-patch/cli/qoder-background-terminal.md +2 -1
- package/dist/axom-patch/cli/qoder-foreground-output.md +4 -3
- package/dist/axom-patch/cli/qoder-steering.json +15 -15
- package/dist/axom-patch/cli/qoder-subagent-origin.json +21 -21
- package/dist/axom-patch/cli/runtime.json +34 -8
- package/dist/axom-patch/cli/zcode-account-limits.json +31 -0
- package/dist/axom-patch/cli/zcode-models.json +38 -0
- package/dist/axom-patch/cli/zcode-subagent-subwork.json +73 -0
- package/dist/cli.js +33 -6
- package/dist/keepers/acp/keeper.mjs +3083 -0
- package/dist/keepers/acp/manifest.json +9 -0
- package/dist/keepers/terminal/keeper.mjs +8469 -0
- package/dist/keepers/terminal/manifest.json +9 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/conpty_console_list_agent.js +25 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/eventEmitter2.js +47 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/index.js +52 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/interfaces.js +7 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/shared/conout.js +10 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/terminal.js +190 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/types.js +7 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/unixTerminal.js +351 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/utils.js +38 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsConoutConnection.js +131 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsPtyAgent.js +344 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsTerminal.js +209 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/dist/keepers/terminal/node_modules/node-pty/package.json +66 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-x64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/linux-arm64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/linux-x64/pty.node +0 -0
- package/dist/runtime-deps/qoder-sdk/package-lock.json +1189 -0
- package/dist/runtime-deps/qoder-sdk/package.json +8 -0
- package/dist/test/keeperKit.js +67 -0
- package/dist/workstation/acp/acpAgents.js +2163 -611
- package/dist/workstation/acp/acpClient.js +60 -497
- package/dist/workstation/acp/adoption.js +10 -396
- package/dist/workstation/acp/binaryInstall.js +100 -27
- package/dist/workstation/acp/builds/gc.js +245 -0
- package/dist/workstation/acp/builds/install/binary.js +28 -0
- package/dist/workstation/acp/builds/install/npm.js +235 -0
- package/dist/workstation/acp/builds/install/uv.js +254 -0
- package/dist/workstation/acp/builds/migrate.js +195 -0
- package/dist/workstation/acp/builds/model.js +128 -0
- package/dist/workstation/acp/builds/nodeGate.js +100 -0
- package/dist/workstation/acp/builds/store.js +352 -0
- package/dist/workstation/acp/commandTableProbe.js +68 -0
- package/dist/workstation/acp/configOptions.js +103 -1
- package/dist/workstation/acp/envSecrets.js +27 -0
- package/dist/workstation/acp/initializeResponse.js +285 -0
- package/dist/workstation/acp/installErrors.js +12 -2
- package/dist/workstation/acp/installProbe.js +1 -1
- package/dist/workstation/acp/managedPatches.js +76 -160
- package/dist/workstation/acp/outbox.js +330 -0
- package/dist/workstation/acp/patchAssets.js +20 -3
- package/dist/workstation/acp/permission.js +42 -10
- package/dist/workstation/acp/processor/checkpoint.js +87 -0
- package/dist/workstation/acp/processor/commands.js +35 -0
- package/dist/workstation/acp/processor/control.js +355 -0
- package/dist/workstation/acp/processor/emit.js +26 -0
- package/dist/workstation/acp/processor/jsonrpc.js +172 -0
- package/dist/workstation/acp/processor/memoryLog.js +49 -0
- package/dist/workstation/acp/processor/origins.js +48 -0
- package/dist/workstation/acp/processor/output.js +67 -0
- package/dist/workstation/acp/processor/projection.js +42 -0
- package/dist/workstation/acp/processor/record.js +128 -0
- package/dist/workstation/acp/processor/runtime.js +181 -0
- package/dist/workstation/acp/processor/sdkSchemas.js +61 -0
- package/dist/workstation/acp/processor/session.js +525 -0
- package/dist/workstation/acp/processor/sideChannel.js +80 -0
- package/dist/workstation/acp/processor/state.js +74 -0
- package/dist/workstation/acp/processor/step.js +459 -0
- package/dist/workstation/acp/processor/test/fixtureLog.js +65 -0
- package/dist/workstation/acp/processor/test/harness.js +120 -0
- package/dist/workstation/acp/processor/test/largeIdEcho.js +50 -0
- package/dist/workstation/acp/processor/test/rawAgent.js +70 -0
- package/dist/workstation/acp/processor/transport/generations.js +76 -0
- package/dist/workstation/acp/processor/transport/keeper.js +130 -0
- package/dist/workstation/acp/processor/transport/local.js +269 -0
- package/dist/workstation/acp/processor/transport/types.js +78 -0
- package/dist/workstation/acp/processor/updates.js +364 -0
- package/dist/workstation/acp/processorSession.js +1512 -0
- package/dist/workstation/acp/qoderStartup.js +1 -1
- package/dist/workstation/acp/registry/catalog.js +154 -32
- package/dist/workstation/acp/registry/launch.js +61 -119
- package/dist/workstation/acp/sessionUpdateMapper.js +18 -7
- package/dist/workstation/acp/steering.js +58 -0
- package/dist/workstation/acp/switching.js +114 -0
- package/dist/workstation/acp/terminalLogin.js +16 -42
- package/dist/workstation/acp/terminalLoginSpec.js +41 -0
- package/dist/workstation/acp/test/adapterFixtures.js +256 -0
- package/dist/workstation/acp/test/daemonLife.js +106 -0
- package/dist/workstation/acp/test/keeperWorld.js +267 -0
- package/dist/workstation/acp/test/memoryOutbox.js +55 -0
- package/dist/workstation/acp/test/raw/fixtures.js +196 -0
- package/dist/workstation/acp/test/raw/qoderCaptures.js +125 -0
- package/dist/workstation/acp/test/raw/sanitize.js +344 -0
- package/dist/workstation/acp/test/raw/sources.js +249 -0
- package/dist/workstation/acp/test/realAdapter.js +377 -0
- package/dist/workstation/acp/test/scriptAgent.js +206 -0
- package/dist/workstation/acp/test/sessionFrames.js +42 -0
- package/dist/workstation/acp/timedCommand.js +4 -2
- package/dist/workstation/acp/uvxInstall.js +72 -122
- package/dist/workstation/agentFlow.js +103 -0
- package/dist/workstation/agentSessions.js +1324 -474
- package/dist/workstation/channels/agent.js +7 -5
- package/dist/workstation/channels/computer.js +69 -21
- package/dist/workstation/channels/computerExecs.js +200 -0
- package/dist/workstation/channels/management.js +84 -4
- package/dist/workstation/daemon.js +288 -7
- package/dist/workstation/daemonctl.js +28 -2
- package/dist/workstation/exec/attach.js +126 -0
- package/dist/workstation/exec/command.js +40 -0
- package/dist/workstation/exec/durable.js +517 -0
- package/dist/workstation/exec/fallback.js +106 -0
- package/dist/workstation/exec/policy.js +837 -0
- package/dist/workstation/exec/shaping.js +211 -0
- package/dist/workstation/exec.js +3 -112
- package/dist/workstation/files/adapters/computerFileFrames.js +51 -0
- package/dist/workstation/files/adapters/toolRequests.js +121 -0
- package/dist/workstation/files/client.js +455 -0
- package/dist/workstation/files/errors.js +28 -0
- package/dist/workstation/files/fence.js +350 -0
- package/dist/workstation/files/find/fileIndex.js +153 -0
- package/dist/workstation/files/find/fuzzy.js +155 -0
- package/dist/workstation/files/host.js +122 -0
- package/dist/workstation/files/hostProtocol.js +2 -0
- package/dist/workstation/files/media/cache.js +620 -0
- package/dist/workstation/files/media/encoding.js +308 -0
- package/dist/workstation/files/media/estimator.js +100 -0
- package/dist/workstation/files/media/media.js +325 -0
- package/dist/workstation/files/media/packedAudio.js +23 -0
- package/dist/workstation/files/media/scheduler.js +551 -0
- package/dist/workstation/files/media/types.js +5 -0
- package/dist/workstation/files/scope.js +45 -0
- package/dist/workstation/files/structured.js +284 -0
- package/dist/workstation/{fileOps.js → files/text.js} +117 -38
- package/dist/workstation/files/uploads.js +351 -0
- package/dist/workstation/journal.js +65 -236
- package/dist/workstation/keepers/acp/client.js +101 -0
- package/dist/workstation/keepers/acp/envelope.js +62 -0
- package/dist/workstation/keepers/acp/host.js +419 -0
- package/dist/workstation/keepers/acp/main.js +18 -0
- package/dist/workstation/keepers/acp/memoryStream.js +121 -0
- package/dist/workstation/keepers/acp/params.js +137 -0
- package/dist/workstation/keepers/acp/protocol.js +66 -0
- package/dist/workstation/keepers/acp/recover.js +120 -0
- package/dist/workstation/keepers/acp/session.js +584 -0
- package/dist/workstation/keepers/acp/stderr.js +154 -0
- package/dist/workstation/keepers/kit/activity.js +103 -0
- package/dist/workstation/keepers/kit/bootstrap.js +164 -0
- package/dist/workstation/keepers/kit/buildVersion.js +51 -0
- package/dist/workstation/keepers/kit/bundle.js +120 -0
- package/dist/workstation/keepers/kit/client.js +432 -0
- package/dist/workstation/keepers/kit/identity.js +21 -0
- package/dist/workstation/keepers/kit/ipc.js +112 -0
- package/dist/workstation/keepers/kit/launchConfig.js +8 -0
- package/dist/workstation/keepers/kit/launcher.js +249 -0
- package/dist/workstation/keepers/kit/lock.js +123 -0
- package/dist/workstation/keepers/kit/orphanSweep.js +86 -0
- package/dist/workstation/keepers/kit/paths.js +75 -0
- package/dist/workstation/keepers/kit/protocol.js +43 -0
- package/dist/workstation/keepers/kit/server.js +518 -0
- package/dist/workstation/keepers/kit/streamLog.js +697 -0
- package/dist/workstation/keepers/legacy.js +296 -0
- package/dist/workstation/keepers/policy.js +576 -0
- package/dist/workstation/keepers/stop.js +34 -0
- package/dist/workstation/keepers/terminal/client.js +213 -0
- package/dist/workstation/keepers/terminal/exec.js +981 -0
- package/dist/workstation/keepers/terminal/generations.js +129 -0
- package/dist/workstation/keepers/terminal/keeper.js +62 -0
- package/dist/workstation/keepers/terminal/main.js +43 -0
- package/dist/workstation/keepers/terminal/orphanSweep.js +3 -0
- package/dist/workstation/keepers/terminal/params.js +27 -0
- package/dist/workstation/keepers/terminal/protocol.js +56 -0
- package/dist/workstation/keepers/terminal/pty.js +330 -0
- package/dist/workstation/protocol/accountLimits.js +47 -0
- package/dist/workstation/protocol/agent.js +48 -4
- package/dist/workstation/protocol/common.js +30 -0
- package/dist/workstation/protocol/computer.js +15 -4
- package/dist/workstation/protocol/management.js +50 -2
- package/dist/workstation/qoderAdapter/backgroundProcess.js +18 -6
- package/dist/workstation/qoderAdapter/backgroundTerminal.js +78 -147
- package/dist/workstation/qoderAdapter/backgroundTerminalFold.js +372 -0
- package/dist/workstation/qoderAdapter/callbackContext.js +76 -0
- package/dist/workstation/qoderAdapter/foregroundOutput.js +15 -9
- package/dist/workstation/qoderAdapter/history.js +1 -3
- package/dist/workstation/qoderAdapter/main.js +4 -2
- package/dist/workstation/qoderAdapter/sdkDriver.js +1 -2
- package/dist/workstation/qoderAdapter/sdkRuntime.js +93 -0
- package/dist/workstation/qoderAdapter/sdkRuntimeInstall.js +145 -0
- package/dist/workstation/qoderAdapter/session.js +1 -1
- package/dist/workstation/qoderAdapter/subwork.js +15 -7
- package/dist/workstation/systemMetrics.js +110 -1
- package/dist/workstation/tools/client.js +9 -1
- package/dist/workstation/tools/info.js +50 -0
- package/dist/workstation/tools/keeperProcess.js +15 -5
- package/dist/workstation/tools/router.js +55 -0
- package/dist/workstation/tools/terminalRouter.js +222 -0
- package/dist/workstation/tools/validation.js +37 -1
- package/dist/workstation/update/coordinator.js +3 -0
- package/dist/workstation/update/ptyPreflight.js +21 -0
- package/dist/workstation/update/taskRegistry.js +105 -11
- package/package.json +10 -7
- package/dist/workstation/acp/acpSession.js +0 -1475
- package/dist/workstation/acp/contract.js +0 -499
- package/dist/workstation/acp/draftInterceptor.js +0 -163
- package/dist/workstation/acp/sessionScope.js +0 -19
- package/dist/workstation/filePaths.js +0 -174
- package/dist/workstation/fileWorker.js +0 -81
- package/dist/workstation/fileWorkerClient.js +0 -121
- package/dist/workstation/qoderAdapter/taskEvent.js +0 -26
- package/dist/workstation/tools/core.js +0 -50
- package/dist/workstation/tools/files.js +0 -525
- package/dist/workstation/tools/terminal.js +0 -214
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
/** Qoder 1.1.61 drops native background task notifications from both live ACP and session/load.
|
|
2
2
|
* This read-only compatibility boundary repairs only a known root Agent tool, never a session.
|
|
3
3
|
* Lifecycle/removal contract: axom-patch/cli/qoder-background-terminal.md.
|
|
4
|
+
*
|
|
5
|
+
* The impure half (Task 17c): this file reads the side files; everything the repair decides is the
|
|
6
|
+
* pure fold in `backgroundTerminalFold.ts`. {@link BackgroundSideNotes} is the daemon side of the deterministic
|
|
7
|
+
* processor: a poll returns the facts as `qoder_side` note payloads for the raw log; the processor folds them only when it
|
|
8
|
+
* reads those notes, so a replay never touches the files. (The old live path's in-process driver, `BackgroundTerminalRepair`,
|
|
9
|
+
* was deleted with that path in Task 29.)
|
|
4
10
|
*/
|
|
5
11
|
import { constants } from 'node:fs';
|
|
6
12
|
import { open } from 'node:fs/promises';
|
|
7
13
|
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
8
14
|
import { BackgroundProcess } from './backgroundProcess.js';
|
|
15
|
+
import { address, MAX_TASKS, object, rootRowFacts, sideNotes, } from './backgroundTerminalFold.js';
|
|
16
|
+
export { TerminalRepairFold, newTerminalRepairData, sideNotes } from './backgroundTerminalFold.js';
|
|
9
17
|
const CHUNK = 64 * 1024;
|
|
10
18
|
const MAX_LINE = 2 * 1024 * 1024;
|
|
11
19
|
const MAX_POLL = 4 * 1024 * 1024;
|
|
12
|
-
const MAX_TASKS = 512;
|
|
13
|
-
const MAX_RESULT = 128 * 1024;
|
|
14
|
-
const MAX_RESULTS = 4 * 1024 * 1024;
|
|
15
|
-
const TERMINALS = new Set(['completed', 'failed', 'cancelled']);
|
|
16
|
-
function object(value) {
|
|
17
|
-
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
18
|
-
}
|
|
19
|
-
function address(value) {
|
|
20
|
-
return typeof value === 'string' && /^[a-zA-Z0-9_-]{1,160}$/.test(value) ? value : undefined;
|
|
21
|
-
}
|
|
22
20
|
export function nativeTerminalHistoryPath(identity, sessionId, cwd, historyHome) {
|
|
23
21
|
if (identity?.name !== 'qoder-cli' || identity.version !== '1.1.61' ||
|
|
24
22
|
!address(sessionId) || !isAbsolute(cwd) || !isAbsolute(historyHome))
|
|
@@ -27,89 +25,50 @@ export function nativeTerminalHistoryPath(identity, sessionId, cwd, historyHome)
|
|
|
27
25
|
// identity: every accepted row is checked again against the exact native session and directory.
|
|
28
26
|
return join(historyHome, '.qoder', 'projects', resolve(cwd).replace(/[^a-zA-Z0-9]/g, '-'), sessionId + '.jsonl');
|
|
29
27
|
}
|
|
30
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Reads the root transcript and the background children's transcripts incrementally (≤ 4 MiB per
|
|
30
|
+
* poll and file, lines ≤ 2 MiB, `O_NOFOLLOW`, never written) and hands each derived {@link SideFact}
|
|
31
|
+
* to the sink, in transcript order: root facts, then each followed child's rows and catch-up status,
|
|
32
|
+
* then `poll_end` — only when the root read completed. Its offsets are its own (not checkpointed): a
|
|
33
|
+
* new reader starts at 0 and the fold drops what it already has.
|
|
34
|
+
*/
|
|
35
|
+
export class BackgroundSideReader {
|
|
31
36
|
options;
|
|
32
|
-
calls = new Map();
|
|
33
37
|
launches = new Map();
|
|
34
|
-
terminals = new Map();
|
|
35
|
-
delivered = new Set();
|
|
36
38
|
processes = new Map();
|
|
37
|
-
pendingProcesses = new Set();
|
|
38
39
|
offset = 0;
|
|
39
40
|
fileIdentity = '';
|
|
40
41
|
pendingLine = Buffer.alloc(0);
|
|
41
42
|
skipLine = false;
|
|
42
43
|
closed = false;
|
|
43
|
-
timer;
|
|
44
|
-
inFlight;
|
|
45
44
|
warned = false;
|
|
46
|
-
resultBytes = 0;
|
|
47
45
|
restoring;
|
|
48
46
|
constructor(options) {
|
|
49
47
|
this.options = options;
|
|
50
48
|
this.restoring = options.restoreCalls === true;
|
|
51
49
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.timer = setInterval(() => { void this.poll(); }, 1000);
|
|
56
|
-
this.timer.unref();
|
|
57
|
-
}
|
|
58
|
-
observe(event) {
|
|
59
|
-
if (this.closed || (event.acpSessionId && event.acpSessionId !== this.options.nativeSessionId) ||
|
|
60
|
-
!['tool_call', 'tool_call_update'].includes(event.eventName))
|
|
61
|
-
return;
|
|
62
|
-
const payload = event.payload;
|
|
63
|
-
const id = address(payload.toolCallId);
|
|
64
|
-
if (!id)
|
|
65
|
-
return;
|
|
66
|
-
let call = this.calls.get(id);
|
|
67
|
-
const input = object(payload.rawInput);
|
|
68
|
-
if (!call && input.run_in_background === true && typeof input.prompt === 'string' &&
|
|
69
|
-
(input.subagent_type == null || typeof input.subagent_type === 'string') && payload.kind === 'think' &&
|
|
70
|
-
object(object(payload._meta).qoder).toolName === 'Agent' && this.calls.size < MAX_TASKS) {
|
|
71
|
-
const meta = object(object(payload._meta).qoder);
|
|
72
|
-
call = { input, invocationComplete: false, nativeTerminal: false,
|
|
73
|
-
process: this.options.includeProcess === true && meta.version === 1 && meta.source === 'native-acp-patch' };
|
|
74
|
-
this.calls.set(id, call);
|
|
75
|
-
}
|
|
76
|
-
if (!call)
|
|
50
|
+
/** One poll. Never rejects: a missing, replaced or unreadable file is not evidence. */
|
|
51
|
+
async read(demand, sink) {
|
|
52
|
+
if (this.closed || (!this.restoring && !demand.active()))
|
|
77
53
|
return;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const output = object(payload.rawOutput);
|
|
81
|
-
if (output.kind === 'agent-result' && (TERMINALS.has(String(output.state)) || output.state === 'error')) {
|
|
82
|
-
call.nativeTerminal = true; // Upstream's structured evidence always wins.
|
|
54
|
+
try {
|
|
55
|
+
await this.readIncrement(demand, sink);
|
|
83
56
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const code = object(error).code;
|
|
91
|
-
if (!['ENOENT', 'ELOOP', 'ENOTDIR', 'EACCES'].includes(String(code)) && !this.warned) {
|
|
92
|
-
this.warned = true;
|
|
93
|
-
console.warn('[acp:qoder] background terminal repair unavailable; retaining native ACP state');
|
|
94
|
-
}
|
|
95
|
-
}).finally(() => { this.inFlight = undefined; });
|
|
57
|
+
catch (error) {
|
|
58
|
+
const code = object(error).code;
|
|
59
|
+
if (!['ENOENT', 'ELOOP', 'ENOTDIR', 'EACCES'].includes(String(code)) && !this.warned) {
|
|
60
|
+
this.warned = true;
|
|
61
|
+
console.warn('[acp:qoder] background terminal repair unavailable; retaining native ACP state');
|
|
62
|
+
}
|
|
96
63
|
}
|
|
97
|
-
return this.inFlight;
|
|
98
64
|
}
|
|
99
65
|
close() {
|
|
100
66
|
this.closed = true;
|
|
101
|
-
if (this.timer)
|
|
102
|
-
clearInterval(this.timer);
|
|
103
|
-
this.timer = undefined;
|
|
104
|
-
this.calls.clear();
|
|
105
67
|
this.launches.clear();
|
|
106
|
-
this.terminals.clear();
|
|
107
|
-
this.delivered.clear();
|
|
108
68
|
this.processes.clear();
|
|
109
|
-
this.pendingProcesses.clear();
|
|
110
69
|
this.pendingLine = Buffer.alloc(0);
|
|
111
70
|
}
|
|
112
|
-
async readIncrement() {
|
|
71
|
+
async readIncrement(demand, sink) {
|
|
113
72
|
// O_NOFOLLOW avoids importing a transcript through a replaced symlink. File is never written.
|
|
114
73
|
const file = await open(this.options.path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
115
74
|
try {
|
|
@@ -130,29 +89,32 @@ export class BackgroundTerminalRepair {
|
|
|
130
89
|
if (!bytesRead)
|
|
131
90
|
break;
|
|
132
91
|
this.offset += bytesRead;
|
|
133
|
-
this.lines(chunk.subarray(0, bytesRead));
|
|
92
|
+
this.lines(chunk.subarray(0, bytesRead), sink);
|
|
134
93
|
}
|
|
135
94
|
if (this.offset >= stat.size)
|
|
136
95
|
this.restoring = false;
|
|
137
96
|
if (!this.closed) {
|
|
138
|
-
await this.pollProcesses();
|
|
97
|
+
await this.pollProcesses(demand, sink);
|
|
139
98
|
if (!this.closed)
|
|
140
|
-
|
|
99
|
+
sink({ kind: 'poll_end' });
|
|
141
100
|
}
|
|
142
101
|
}
|
|
143
102
|
finally {
|
|
144
103
|
await file.close();
|
|
145
104
|
}
|
|
146
105
|
}
|
|
147
|
-
lines(chunk) {
|
|
106
|
+
lines(chunk, sink) {
|
|
148
107
|
let start = 0;
|
|
149
108
|
for (let end = chunk.indexOf(10); end !== -1; end = chunk.indexOf(10, start)) {
|
|
150
109
|
if (!this.skipLine && this.pendingLine.length + end - start <= MAX_LINE) {
|
|
151
110
|
const line = Buffer.concat([this.pendingLine, chunk.subarray(start, end)]).toString('utf8');
|
|
111
|
+
let row;
|
|
152
112
|
try {
|
|
153
|
-
|
|
113
|
+
row = object(JSON.parse(line));
|
|
154
114
|
}
|
|
155
115
|
catch { /* partial/corrupt non-evidence */ }
|
|
116
|
+
if (row)
|
|
117
|
+
this.consume(row, sink);
|
|
156
118
|
}
|
|
157
119
|
this.pendingLine = Buffer.alloc(0);
|
|
158
120
|
this.skipLine = false;
|
|
@@ -167,96 +129,65 @@ export class BackgroundTerminalRepair {
|
|
|
167
129
|
this.skipLine = true;
|
|
168
130
|
}
|
|
169
131
|
}
|
|
170
|
-
consume(row) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return;
|
|
177
|
-
// resume deliberately sends no historical ACP openings. Recover only certified root Agent
|
|
178
|
-
// background inputs; no opening is emitted and the existing exact-ID notification rules apply.
|
|
179
|
-
if (this.options.restoreCalls && row.type === 'assistant') {
|
|
180
|
-
for (const block of content.map(object)) {
|
|
181
|
-
const input = object(block.input), id = address(block.id);
|
|
182
|
-
if (block.type === 'tool_use' && block.name === 'Agent' && id && input.run_in_background === true &&
|
|
183
|
-
typeof input.prompt === 'string' && (input.subagent_type == null || typeof input.subagent_type === 'string') &&
|
|
184
|
-
!this.calls.has(id) && this.calls.size < MAX_TASKS) {
|
|
185
|
-
this.calls.set(id, { input, invocationComplete: false, nativeTerminal: false, process: false });
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
if (row.type !== 'user')
|
|
191
|
-
return;
|
|
192
|
-
const output = object(row.toolUseResult);
|
|
193
|
-
if (output.isAsync === true && output.status === 'async_launched') {
|
|
194
|
-
const results = content.map(object).filter(c => c.type === 'tool_result');
|
|
195
|
-
const id = results.length === 1 ? address(results[0].tool_use_id) : undefined;
|
|
196
|
-
const agent = address(output.agentId);
|
|
197
|
-
if (this.options.restoreCalls && id && this.calls.has(id))
|
|
198
|
-
this.calls.get(id).invocationComplete = true;
|
|
199
|
-
if (id && agent && this.launches.size < MAX_TASKS && !this.launches.has(id))
|
|
200
|
-
this.launches.set(id, agent);
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
if (row.isMeta !== true || object(row.origin).kind !== 'task-notification')
|
|
204
|
-
return;
|
|
205
|
-
for (const block of content.map(object)) {
|
|
206
|
-
if (block.type !== 'text' || typeof block.text !== 'string' ||
|
|
207
|
-
!block.text.startsWith('[SYSTEM NOTIFICATION - NOT USER INPUT]\n'))
|
|
208
|
-
continue;
|
|
209
|
-
// Match the authoritative envelope before result text; tags inside a result cannot change IDs.
|
|
210
|
-
const match = block.text.match(/<task-notification>\n<task-id>([a-zA-Z0-9_-]{1,160})<\/task-id>\n<tool-use-id>([a-zA-Z0-9_-]{1,160})<\/tool-use-id>\n(?:<output-file>[^\n]*<\/output-file>\n)?<status>(completed|failed|cancelled)<\/status>\n<summary>[^\n]*<\/summary>\n<result>([\s\S]*)<\/result>\n(?:<usage>[^\n]*<\/usage>\n)?<\/task-notification>\s*$/);
|
|
211
|
-
const bytes = match ? Buffer.byteLength(match[4]) : 0;
|
|
212
|
-
if (match && bytes <= MAX_RESULT && this.resultBytes + bytes <= MAX_RESULTS &&
|
|
213
|
-
this.terminals.size < MAX_TASKS && !this.terminals.has(match[2])) {
|
|
214
|
-
this.resultBytes += bytes;
|
|
215
|
-
this.terminals.set(match[2], { taskId: match[1], state: match[3], result: match[4] });
|
|
132
|
+
consume(row, sink) {
|
|
133
|
+
const { nativeSessionId, cwd } = this.options;
|
|
134
|
+
for (const fact of rootRowFacts(row, { nativeSessionId, cwd, restoreCalls: this.options.restoreCalls === true })) {
|
|
135
|
+
// The reader's own copy of the receipts (same rule as the fold's): which child transcripts exist.
|
|
136
|
+
if (fact.kind === 'launch' && fact.agentId && this.launches.size < MAX_TASKS && !this.launches.has(fact.toolUseId)) {
|
|
137
|
+
this.launches.set(fact.toolUseId, fact.agentId);
|
|
216
138
|
}
|
|
139
|
+
sink(fact);
|
|
217
140
|
}
|
|
218
141
|
}
|
|
219
|
-
|
|
220
|
-
for (const [id, terminal] of this.terminals) {
|
|
221
|
-
const call = this.calls.get(id), agentId = this.launches.get(id);
|
|
222
|
-
if (this.delivered.has(id) || this.pendingProcesses.has(id) || !call?.invocationComplete || call.nativeTerminal || !agentId)
|
|
223
|
-
continue;
|
|
224
|
-
this.delivered.add(id);
|
|
225
|
-
this.options.emit({ eventName: 'tool_call_update', payload: {
|
|
226
|
-
name: 'Agent', kind: 'think', toolCallId: id, rawInput: call.input, status: 'completed',
|
|
227
|
-
rawOutput: { kind: 'agent-result', state: terminal.state, agentId, result: terminal.result },
|
|
228
|
-
content: [{ type: 'content', content: { type: 'text', text: terminal.result } }],
|
|
229
|
-
_meta: { qoder: { toolName: 'Agent' }, axomNativeTerminalRepair: {
|
|
230
|
-
patch: 'qoder-background-terminal', nativeSessionId: this.options.nativeSessionId,
|
|
231
|
-
taskId: terminal.taskId, source: 'native-task-notification',
|
|
232
|
-
} },
|
|
233
|
-
} });
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
async pollProcesses() {
|
|
142
|
+
async pollProcesses(demand, sink) {
|
|
237
143
|
for (const [id, agentId] of this.launches) {
|
|
238
|
-
|
|
239
|
-
if (this.closed || this.delivered.has(id) || !call?.process || call.nativeTerminal)
|
|
144
|
+
if (this.closed || !demand.wantsProcess(id))
|
|
240
145
|
continue;
|
|
241
146
|
let process = this.processes.get(id);
|
|
242
147
|
if (!process) {
|
|
243
148
|
process = new BackgroundProcess({
|
|
244
149
|
path: join(dirname(this.options.path), this.options.nativeSessionId, 'subagents', `agent-${agentId}.jsonl`),
|
|
245
150
|
sessionId: this.options.nativeSessionId, cwd: this.options.cwd, agentId, parentToolUseId: id,
|
|
246
|
-
emit:
|
|
247
|
-
|
|
151
|
+
emit: () => { },
|
|
152
|
+
onRow: (uuid, events) => { if (!this.closed)
|
|
153
|
+
sink({ kind: 'child', toolUseId: id, uuid, events }); },
|
|
248
154
|
});
|
|
249
155
|
this.processes.set(id, process);
|
|
250
156
|
}
|
|
157
|
+
let caughtUp;
|
|
251
158
|
try {
|
|
252
|
-
|
|
253
|
-
this.pendingProcesses.delete(id);
|
|
254
|
-
else
|
|
255
|
-
this.pendingProcesses.add(id);
|
|
159
|
+
caughtUp = await process.poll();
|
|
256
160
|
}
|
|
257
161
|
catch {
|
|
258
|
-
|
|
162
|
+
caughtUp = true; /* missing/corrupt transcript is not execution evidence */
|
|
259
163
|
}
|
|
164
|
+
sink({ kind: 'child_status', toolUseId: id, caughtUp });
|
|
260
165
|
}
|
|
261
166
|
}
|
|
262
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* The daemon side of the processor (T19 runs it on its own timer, for a session whose processor
|
|
170
|
+
* folded a `qoder_terminal_repair` note): one {@link poll} reads what is new and returns the note
|
|
171
|
+
* payloads to append to the raw log, in order. `demand` is asked of the processor's current state
|
|
172
|
+
* (`acp/processor/sideChannel.ts` `sideDemand`); what it answered is recorded only through the facts,
|
|
173
|
+
* so the processor's fold never depends on when the daemon polled.
|
|
174
|
+
*/
|
|
175
|
+
export class BackgroundSideNotes {
|
|
176
|
+
reader;
|
|
177
|
+
/** Facts over `MAX_SIDE_FACT_BYTES` that could not be recorded (diagnostics). */
|
|
178
|
+
droppedFacts = 0;
|
|
179
|
+
constructor(options) {
|
|
180
|
+
this.reader = new BackgroundSideReader(options);
|
|
181
|
+
}
|
|
182
|
+
async poll(demand) {
|
|
183
|
+
const notes = [];
|
|
184
|
+
await this.reader.read(demand, (fact) => {
|
|
185
|
+
const encoded = sideNotes(fact);
|
|
186
|
+
if (encoded.length === 0)
|
|
187
|
+
this.droppedFacts += 1;
|
|
188
|
+
notes.push(...encoded);
|
|
189
|
+
});
|
|
190
|
+
return notes;
|
|
191
|
+
}
|
|
192
|
+
close() { this.reader.close(); }
|
|
193
|
+
}
|