@myagentroam/node 0.9.0 → 0.9.3
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/connector.d.ts +2 -0
- package/dist/connector.js +50 -25
- package/dist/control-outbound-scheduler.d.ts +4 -1
- package/dist/control-outbound-scheduler.js +39 -6
- package/dist/database.d.ts +0 -19
- package/dist/database.js +1 -62
- package/dist/event-buffer.d.ts +2 -5
- package/dist/event-buffer.js +3 -12
- package/dist/native-session-history.js +105 -26
- package/dist/runner/abstract-runner.d.ts +1 -1
- package/dist/runner/abstract-runner.js +2 -2
- package/dist/runner/claude/managed-run-controller.d.ts +0 -1
- package/dist/runner/claude/managed-run-controller.js +32 -17
- package/dist/runner/claude-code-runner.js +3 -4
- package/dist/runner/codex/conversation-parser.d.ts +3 -3
- package/dist/runner/codex/conversation-parser.js +33 -12
- package/dist/runner/codex/managed-run-controller.d.ts +2 -2
- package/dist/runner/codex/managed-run-controller.js +26 -10
- package/dist/runner/codex-runner.d.ts +3 -1
- package/dist/runner/codex-runner.js +40 -10
- package/dist/runner/opencode/conversation-parser.d.ts +11 -7
- package/dist/runner/opencode/conversation-parser.js +16 -16
- package/dist/runner/opencode/managed-run-controller.d.ts +8 -2
- package/dist/runner/opencode/managed-run-controller.js +94 -22
- package/dist/runner/opencode-runner.d.ts +3 -0
- package/dist/runner/opencode-runner.js +25 -0
- package/dist/runner-command-engine.js +1 -1
- package/dist/runner-profiles.js +29 -17
- package/dist/runner-usage.js +5 -5
- package/dist/runtime-state.d.ts +5 -12
- package/dist/runtime-state.js +32 -46
- package/dist/service/attachment-domain-state.d.ts +2 -0
- package/dist/service/attachment-domain-state.js +2 -0
- package/dist/service/conversation-history-service.js +55 -24
- package/dist/service/conversation-segment-service.d.ts +20 -0
- package/dist/service/conversation-segment-service.js +156 -0
- package/dist/service/external-session-resume-service.js +9 -0
- package/dist/service/fake-managed-run-service.d.ts +0 -1
- package/dist/service/fake-managed-run-service.js +0 -2
- package/dist/service/mcp-installation-verifier.js +1 -1
- package/dist/service/native-session-projection-service.js +5 -0
- package/dist/service/native-session-watch-service.d.ts +1 -0
- package/dist/service/native-session-watch-service.js +21 -4
- package/dist/service/node-connection-lifecycle-service.d.ts +0 -2
- package/dist/service/node-connection-lifecycle-service.js +0 -1
- package/dist/service/node-control-channel.js +1 -1
- package/dist/service/node-control-message-service.d.ts +0 -1
- package/dist/service/node-control-message-service.js +9 -6
- package/dist/service/node-request-service.js +2 -1
- package/dist/service/node-workspace-coordinator.d.ts +1 -4
- package/dist/service/node-workspace-coordinator.js +2 -12
- package/dist/service/run-attachment-service.d.ts +3 -2
- package/dist/service/run-attachment-service.js +51 -17
- package/dist/service/run-event-service.d.ts +2 -0
- package/dist/service/run-event-service.js +77 -2
- package/dist/service/run-workbench-service.d.ts +1 -1
- package/dist/service/run-workbench-service.js +1 -5
- package/dist/service/runner-interaction-service.d.ts +1 -2
- package/dist/service/runner-interaction-service.js +1 -4
- package/dist/service/session-catalog-service.js +4 -4
- package/dist/service/session-context-service.d.ts +1 -0
- package/dist/service/session-context-service.js +14 -0
- package/dist/service/session-domain-state.d.ts +1 -0
- package/dist/service/session-domain-state.js +1 -0
- package/dist/service/session-message-service.js +5 -10
- package/dist/service/session-presentation-service.d.ts +1 -0
- package/dist/service/session-presentation-service.js +8 -1
- package/dist/service/session-query-service.d.ts +4 -0
- package/dist/service/session-query-service.js +6 -1
- package/dist/service/skill-directory-service.d.ts +3 -1
- package/dist/service/skill-directory-service.js +31 -30
- package/dist/service/skill-install-service.js +4 -74
- package/dist/service/skill-node-operation-service.d.ts +1 -1
- package/dist/service/skill-node-operation-service.js +6 -3
- package/dist/service/workbench-event-service.d.ts +1 -13
- package/dist/service/workbench-event-service.js +2 -36
- package/dist/service/workbench-manifest-service.d.ts +0 -1
- package/dist/service/workbench-manifest-service.js +0 -1
- package/dist/service/workspace-domain-state.d.ts +1 -0
- package/dist/service/workspace-git-exclude-service.d.ts +4 -0
- package/dist/service/workspace-git-exclude-service.js +119 -0
- package/dist/service/workspace-queue-workbench-service.d.ts +1 -0
- package/dist/service/workspace-queue-workbench-service.js +4 -2
- package/dist/service/workspace-service.js +2 -0
- package/dist/service/workspace-upload-service.d.ts +2 -0
- package/dist/service/workspace-upload-service.js +28 -6
- package/dist/service/workspace-workbench-service.d.ts +0 -3
- package/dist/service/workspace-workbench-service.js +0 -17
- package/dist/supervisor.js +2 -1
- package/dist/terminal.js +1 -1
- package/dist/util/node-operation-parsers.js +2 -2
- package/dist/util/runner-error.d.ts +6 -0
- package/dist/util/runner-error.js +52 -0
- package/dist/util/runner-native-session-parsers.d.ts +2 -3
- package/dist/util/runner-native-session-parsers.js +48 -20
- package/dist/util/safe-error.d.ts +2 -0
- package/dist/util/safe-error.js +5 -0
- package/package.json +2 -2
|
@@ -9,7 +9,9 @@ const DISCOVERY_READ_BYTES = 32 * 1024;
|
|
|
9
9
|
const TRANSCRIPT_READ_BYTES = 4 * 1024 * 1024;
|
|
10
10
|
const CONTEXT_USAGE_READ_BYTES = 256 * 1024;
|
|
11
11
|
const CLAUDE_CONTEXT_USAGE_READ_BYTES = [CONTEXT_USAGE_READ_BYTES, 1024 * 1024, 4 * 1024 * 1024];
|
|
12
|
+
const TRANSCRIPT_INDEX_TTL_MS = 60 * 60_000;
|
|
12
13
|
const transcriptIndex = new Map();
|
|
14
|
+
const transcriptIndexTimers = new Map();
|
|
13
15
|
const discoveryReads = new Map();
|
|
14
16
|
const DEFAULT_CLAUDE_CONTEXT_WINDOW_TOKENS = 200_000;
|
|
15
17
|
const CLAUDE_CONTEXT_WINDOW_ENV = 'MAR_CLAUDE_CONTEXT_WINDOW_TOKENS';
|
|
@@ -53,7 +55,7 @@ async function performNativeSessionDiscovery(runner) {
|
|
|
53
55
|
if (parsed === undefined)
|
|
54
56
|
continue;
|
|
55
57
|
const cwd = canonical(parsed.cwd);
|
|
56
|
-
|
|
58
|
+
setTranscriptIndex(indexKey(runner, cwd, parsed.externalSessionId), files[index]);
|
|
57
59
|
found.set(`${cwd}\u0000${parsed.externalSessionId}`, parsed);
|
|
58
60
|
}
|
|
59
61
|
nodeLog('native.session.discovery.completed', {
|
|
@@ -83,14 +85,14 @@ async function readDiscoveryHeaders(files, runner) {
|
|
|
83
85
|
/** Reads one already-discovered external session again to follow appended JSONL records. */
|
|
84
86
|
export async function readNativeSession(runner, workspacePath, externalSessionId) {
|
|
85
87
|
const wanted = canonical(workspacePath);
|
|
86
|
-
const path =
|
|
88
|
+
const path = getTranscriptIndex(indexKey(runner, wanted, externalSessionId));
|
|
87
89
|
if (path === undefined)
|
|
88
90
|
return undefined;
|
|
89
91
|
const parsed = await readTranscript(path, runner, TRANSCRIPT_READ_BYTES);
|
|
90
92
|
if (parsed === undefined ||
|
|
91
93
|
parsed.externalSessionId !== externalSessionId ||
|
|
92
94
|
canonical(parsed.cwd) !== wanted) {
|
|
93
|
-
|
|
95
|
+
deleteTranscriptIndex(indexKey(runner, wanted, externalSessionId));
|
|
94
96
|
return undefined;
|
|
95
97
|
}
|
|
96
98
|
return parsed;
|
|
@@ -103,10 +105,10 @@ export async function readNativeSession(runner, workspacePath, externalSessionId
|
|
|
103
105
|
*/
|
|
104
106
|
export async function readCodexNativeContextUsage(workspacePath, externalSessionId) {
|
|
105
107
|
const wanted = canonical(workspacePath);
|
|
106
|
-
let path =
|
|
108
|
+
let path = getTranscriptIndex(indexKey('codex', wanted, externalSessionId));
|
|
107
109
|
if (path === undefined) {
|
|
108
110
|
await discoverNativeSessions('codex', workspacePath);
|
|
109
|
-
path =
|
|
111
|
+
path = getTranscriptIndex(indexKey('codex', wanted, externalSessionId));
|
|
110
112
|
}
|
|
111
113
|
if (path === undefined)
|
|
112
114
|
return undefined;
|
|
@@ -124,11 +126,11 @@ export async function readCodexNativeContextUsage(workspacePath, externalSession
|
|
|
124
126
|
/** Reads the latest actual Claude prompt occupancy without starting a CLI/SDK control stream. */
|
|
125
127
|
export async function readClaudeNativeContextUsage(workspacePath, externalSessionId, options = {}) {
|
|
126
128
|
const wanted = canonical(workspacePath);
|
|
127
|
-
let path =
|
|
129
|
+
let path = getTranscriptIndex(indexKey('claude-code', wanted, externalSessionId));
|
|
128
130
|
path ??= await locateClaudeTranscript(wanted, externalSessionId);
|
|
129
131
|
if (path === undefined) {
|
|
130
132
|
await discoverNativeSessions('claude-code', workspacePath);
|
|
131
|
-
path =
|
|
133
|
+
path = getTranscriptIndex(indexKey('claude-code', wanted, externalSessionId));
|
|
132
134
|
}
|
|
133
135
|
if (path === undefined)
|
|
134
136
|
return undefined;
|
|
@@ -178,7 +180,7 @@ async function locateClaudeTranscript(wantedCwd, externalSessionId) {
|
|
|
178
180
|
const match = parsed.find(({ history }) => history?.externalSessionId === externalSessionId && canonical(history.cwd) === wantedCwd);
|
|
179
181
|
if (match === undefined)
|
|
180
182
|
return undefined;
|
|
181
|
-
|
|
183
|
+
setTranscriptIndex(indexKey('claude-code', wantedCwd, externalSessionId), match.path);
|
|
182
184
|
return match.path;
|
|
183
185
|
}
|
|
184
186
|
export async function claudeContextWindowTokens(options = {}) {
|
|
@@ -207,10 +209,10 @@ export async function claudeContextWindowTokens(options = {}) {
|
|
|
207
209
|
*/
|
|
208
210
|
export async function removeNativeSession(runner, workspacePath, externalSessionId) {
|
|
209
211
|
const wanted = canonical(workspacePath);
|
|
210
|
-
let path =
|
|
212
|
+
let path = getTranscriptIndex(indexKey(runner, wanted, externalSessionId));
|
|
211
213
|
if (path === undefined) {
|
|
212
214
|
await discoverNativeSessions(runner, workspacePath);
|
|
213
|
-
path =
|
|
215
|
+
path = getTranscriptIndex(indexKey(runner, wanted, externalSessionId));
|
|
214
216
|
}
|
|
215
217
|
if (path === undefined)
|
|
216
218
|
throw new Error('NATIVE_TRANSCRIPT_UNAVAILABLE');
|
|
@@ -218,7 +220,7 @@ export async function removeNativeSession(runner, workspacePath, externalSession
|
|
|
218
220
|
if (parsed === undefined ||
|
|
219
221
|
parsed.externalSessionId !== externalSessionId ||
|
|
220
222
|
canonical(parsed.cwd) !== wanted) {
|
|
221
|
-
|
|
223
|
+
deleteTranscriptIndex(indexKey(runner, wanted, externalSessionId));
|
|
222
224
|
throw new Error('NATIVE_TRANSCRIPT_UNAVAILABLE');
|
|
223
225
|
}
|
|
224
226
|
try {
|
|
@@ -229,7 +231,7 @@ export async function removeNativeSession(runner, workspacePath, externalSession
|
|
|
229
231
|
throw new Error('NATIVE_TRANSCRIPT_UNAVAILABLE');
|
|
230
232
|
throw error;
|
|
231
233
|
}
|
|
232
|
-
|
|
234
|
+
deleteTranscriptIndex(indexKey(runner, wanted, externalSessionId));
|
|
233
235
|
}
|
|
234
236
|
function transcriptRoot(runner) {
|
|
235
237
|
return runner === 'codex'
|
|
@@ -286,7 +288,7 @@ async function readTranscript(path, runner, byteLimit) {
|
|
|
286
288
|
items.push({
|
|
287
289
|
kind: 'tool_call',
|
|
288
290
|
toolUseId: result.toolUseId,
|
|
289
|
-
toolName: '
|
|
291
|
+
toolName: 'Tool',
|
|
290
292
|
input: null,
|
|
291
293
|
inputSummary: null,
|
|
292
294
|
inputTruncated: false,
|
|
@@ -301,7 +303,7 @@ async function readTranscript(path, runner, byteLimit) {
|
|
|
301
303
|
if (cwd === undefined)
|
|
302
304
|
return undefined;
|
|
303
305
|
const title = items.find((item) => item.kind === 'message' && item.role === 'USER')?.text;
|
|
304
|
-
//
|
|
306
|
+
// Tagged Plan Mode instruction labels do not form a session title.
|
|
305
307
|
const strippedTitle = title === undefined ? undefined : stripClaudePlanTag(title);
|
|
306
308
|
return {
|
|
307
309
|
runner,
|
|
@@ -591,7 +593,7 @@ function codexGeneratedImageEvent(record) {
|
|
|
591
593
|
input: null,
|
|
592
594
|
inputSummary: null,
|
|
593
595
|
inputTruncated: false,
|
|
594
|
-
outputSummary: payload['status'] === 'completed' ? '
|
|
596
|
+
outputSummary: payload['status'] === 'completed' ? 'Image generation completed' : 'Image generation failed',
|
|
595
597
|
outputTruncated: false,
|
|
596
598
|
imageAttachments: [{ name: basename(localPath), mime: imageMime(localPath), localPath }],
|
|
597
599
|
failed: payload['status'] !== 'completed',
|
|
@@ -620,7 +622,7 @@ function codexVisibleToolText(value) {
|
|
|
620
622
|
const start = value.indexOf(marker, cursor);
|
|
621
623
|
if (start < 0)
|
|
622
624
|
return visible + value.slice(cursor);
|
|
623
|
-
visible += `${value.slice(cursor, start)}[
|
|
625
|
+
visible += `${value.slice(cursor, start)}[Image content filtered]`;
|
|
624
626
|
const doubleQuote = value.indexOf('"', start);
|
|
625
627
|
const singleQuote = value.indexOf("'", start);
|
|
626
628
|
const end = doubleQuote < 0
|
|
@@ -636,14 +638,20 @@ function codexVisibleToolText(value) {
|
|
|
636
638
|
}
|
|
637
639
|
/** Extract only image placeholder metadata from native Codex output. */
|
|
638
640
|
function codexImagePlaceholders(value) {
|
|
639
|
-
const
|
|
641
|
+
const attachments = [];
|
|
640
642
|
let visited = 0;
|
|
641
643
|
const visit = (current, depth) => {
|
|
642
|
-
if (
|
|
644
|
+
if (attachments.length >= 5 || visited >= 128 || depth > 5 || current == null)
|
|
643
645
|
return;
|
|
644
646
|
visited += 1;
|
|
645
647
|
if (typeof current === 'string') {
|
|
648
|
+
const paths = [];
|
|
646
649
|
collectGeneratedImagePaths(current, paths);
|
|
650
|
+
for (const localPath of paths) {
|
|
651
|
+
if (attachments.some((attachment) => attachment.localPath === localPath))
|
|
652
|
+
continue;
|
|
653
|
+
attachments.push({ name: basename(localPath), mime: imageMime(localPath), localPath });
|
|
654
|
+
}
|
|
647
655
|
return;
|
|
648
656
|
}
|
|
649
657
|
if (Array.isArray(current)) {
|
|
@@ -653,15 +661,28 @@ function codexImagePlaceholders(value) {
|
|
|
653
661
|
}
|
|
654
662
|
if (!isRecord(current))
|
|
655
663
|
return;
|
|
664
|
+
const type = typeof current['type'] === 'string' ? current['type'] : '';
|
|
665
|
+
if (type === 'input_text' && typeof current['text'] === 'string') {
|
|
666
|
+
const mime = /["']image_url["']\s*:\s*["']data:(image\/[^;,"']+)[;,]/.exec(current['text'])?.[1];
|
|
667
|
+
if (mime !== undefined)
|
|
668
|
+
attachments.push({ name: `image-${attachments.length + 1}.${imageExtension(mime)}`, mime });
|
|
669
|
+
}
|
|
670
|
+
const imageUrl = isRecord(current['image_url'])
|
|
671
|
+
? firstString(current['image_url'], ['url'])
|
|
672
|
+
: typeof current['image_url'] === 'string'
|
|
673
|
+
? current['image_url']
|
|
674
|
+
: undefined;
|
|
675
|
+
const data = typeof current['data'] === 'string' ? current['data'] : imageUrl;
|
|
676
|
+
if ((type === 'image' || type === 'input_image' || type === 'output_image') &&
|
|
677
|
+
data?.startsWith('data:image/')) {
|
|
678
|
+
const mime = /^data:([^;,]+)[;,]/.exec(data)?.[1] ?? 'image/png';
|
|
679
|
+
attachments.push({ name: `image-${attachments.length + 1}.${imageExtension(mime)}`, mime });
|
|
680
|
+
}
|
|
656
681
|
for (const child of Object.values(current))
|
|
657
682
|
visit(child, depth + 1);
|
|
658
683
|
};
|
|
659
684
|
visit(value, 0);
|
|
660
|
-
return
|
|
661
|
-
name: basename(localPath),
|
|
662
|
-
mime: imageMime(localPath),
|
|
663
|
-
localPath
|
|
664
|
-
}));
|
|
685
|
+
return attachments;
|
|
665
686
|
}
|
|
666
687
|
function collectGeneratedImagePaths(value, paths) {
|
|
667
688
|
const marker = '/.codex/generated_images/';
|
|
@@ -690,15 +711,54 @@ function imageMime(path) {
|
|
|
690
711
|
return 'image/webp';
|
|
691
712
|
return 'image/png';
|
|
692
713
|
}
|
|
714
|
+
function imageExtension(mime) {
|
|
715
|
+
if (mime === 'image/jpeg')
|
|
716
|
+
return 'jpg';
|
|
717
|
+
if (mime === 'image/webp')
|
|
718
|
+
return 'webp';
|
|
719
|
+
if (mime === 'image/gif')
|
|
720
|
+
return 'gif';
|
|
721
|
+
return 'png';
|
|
722
|
+
}
|
|
693
723
|
function withToolResult(call, result) {
|
|
724
|
+
const viewedImagePath = codexViewedImagePath(call);
|
|
725
|
+
const imageAttachments = result.imageAttachments?.map((attachment) => attachment.localPath !== undefined || viewedImagePath === undefined
|
|
726
|
+
? attachment
|
|
727
|
+
: {
|
|
728
|
+
name: basename(viewedImagePath),
|
|
729
|
+
mime: imageMime(viewedImagePath),
|
|
730
|
+
localPath: viewedImagePath
|
|
731
|
+
});
|
|
694
732
|
return {
|
|
695
733
|
...call,
|
|
696
734
|
outputSummary: result.output,
|
|
697
735
|
outputTruncated: result.truncated,
|
|
698
|
-
...(
|
|
736
|
+
...(imageAttachments === undefined ? {} : { imageAttachments }),
|
|
699
737
|
failed: result.failed
|
|
700
738
|
};
|
|
701
739
|
}
|
|
740
|
+
function codexViewedImagePath(call) {
|
|
741
|
+
const toolName = call.toolName.toLowerCase();
|
|
742
|
+
if (toolName === 'view_image' || toolName === 'imageview') {
|
|
743
|
+
return isRecord(call.input) && typeof call.input['path'] === 'string'
|
|
744
|
+
? call.input['path']
|
|
745
|
+
: undefined;
|
|
746
|
+
}
|
|
747
|
+
if (toolName !== 'exec' || typeof call.input !== 'string')
|
|
748
|
+
return undefined;
|
|
749
|
+
if (!/tools\.view_image\s*\(/.test(call.input))
|
|
750
|
+
return undefined;
|
|
751
|
+
const encodedPath = /["']path["']\s*:\s*("(?:\\.|[^"\\])*")/.exec(call.input)?.[1];
|
|
752
|
+
if (encodedPath === undefined)
|
|
753
|
+
return undefined;
|
|
754
|
+
try {
|
|
755
|
+
const path = JSON.parse(encodedPath);
|
|
756
|
+
return typeof path === 'string' ? path : undefined;
|
|
757
|
+
}
|
|
758
|
+
catch {
|
|
759
|
+
return undefined;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
702
762
|
function isInjectedContextPrompt(text) {
|
|
703
763
|
const normalized = text.replace(/\s+/g, ' ').trim();
|
|
704
764
|
if (normalized.startsWith('<codex_internal_context'))
|
|
@@ -776,7 +836,7 @@ function compactValue(value, limit) {
|
|
|
776
836
|
text = JSON.stringify(value);
|
|
777
837
|
}
|
|
778
838
|
catch {
|
|
779
|
-
return { text: '
|
|
839
|
+
return { text: '(Unable to display)', truncated: false };
|
|
780
840
|
}
|
|
781
841
|
}
|
|
782
842
|
return {
|
|
@@ -812,7 +872,7 @@ function nestedString(value, keys) {
|
|
|
812
872
|
function compact(value) {
|
|
813
873
|
return value.replace(/\s+/g, ' ').trim().slice(0, 16_000);
|
|
814
874
|
}
|
|
815
|
-
/**
|
|
875
|
+
/** Conversation content can be Markdown, so its internal whitespace must not be collapsed like a title. */
|
|
816
876
|
function messageText(value) {
|
|
817
877
|
return value.trim().slice(0, 16_000);
|
|
818
878
|
}
|
|
@@ -828,6 +888,25 @@ function canonical(value) {
|
|
|
828
888
|
function indexKey(runner, cwd, externalSessionId) {
|
|
829
889
|
return `${runner}\u0000${cwd}\u0000${externalSessionId}`;
|
|
830
890
|
}
|
|
891
|
+
function setTranscriptIndex(key, path) {
|
|
892
|
+
const previousTimer = transcriptIndexTimers.get(key);
|
|
893
|
+
if (previousTimer !== undefined)
|
|
894
|
+
clearTimeout(previousTimer);
|
|
895
|
+
transcriptIndex.set(key, path);
|
|
896
|
+
const timer = setTimeout(() => deleteTranscriptIndex(key), TRANSCRIPT_INDEX_TTL_MS);
|
|
897
|
+
timer.unref();
|
|
898
|
+
transcriptIndexTimers.set(key, timer);
|
|
899
|
+
}
|
|
900
|
+
function getTranscriptIndex(key) {
|
|
901
|
+
return transcriptIndex.get(key);
|
|
902
|
+
}
|
|
903
|
+
function deleteTranscriptIndex(key) {
|
|
904
|
+
const timer = transcriptIndexTimers.get(key);
|
|
905
|
+
if (timer !== undefined)
|
|
906
|
+
clearTimeout(timer);
|
|
907
|
+
transcriptIndexTimers.delete(key);
|
|
908
|
+
transcriptIndex.delete(key);
|
|
909
|
+
}
|
|
831
910
|
function isRecord(value) {
|
|
832
911
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
833
912
|
}
|
|
@@ -53,7 +53,7 @@ export declare abstract class AbstractRunner<TName extends RegisteredRunnerName
|
|
|
53
53
|
}, managedTurn: (nativeTurnId: string) => NodeConversationTurn | undefined): Promise<RunnerOfficialConversationPage | undefined>;
|
|
54
54
|
readExternalActivity(session: NodeAgentSession): Promise<SessionActivityState | undefined>;
|
|
55
55
|
acceptsTruncatedNativeHistory(): boolean;
|
|
56
|
-
|
|
56
|
+
nativeImageRoots(session: NodeAgentSession): readonly string[];
|
|
57
57
|
managedRunForNativeTurn(nativeTurnId: string): string | undefined;
|
|
58
58
|
abstract stop(): void | Promise<void>;
|
|
59
59
|
bindControl(control: RunnerControl): void;
|
|
@@ -106,9 +106,9 @@ export class AbstractRunner {
|
|
|
106
106
|
acceptsTruncatedNativeHistory() {
|
|
107
107
|
return true;
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
nativeImageRoots(session) {
|
|
110
110
|
void session;
|
|
111
|
-
return
|
|
111
|
+
return [];
|
|
112
112
|
}
|
|
113
113
|
managedRunForNativeTurn(nativeTurnId) {
|
|
114
114
|
void nativeTurnId;
|
|
@@ -26,7 +26,6 @@ export interface ClaudeManagedRunHost<TAttachment extends ClaudeRunnerImageAttac
|
|
|
26
26
|
hasActiveSessionLease(sessionId: string): boolean;
|
|
27
27
|
session(sessionId: string): NodeAgentSession | undefined;
|
|
28
28
|
completeCancelled(runId: string, cwd: string): boolean;
|
|
29
|
-
captureSnapshot(runId: string, cwd: string): Promise<void>;
|
|
30
29
|
requestUserInput(runId: string, input: Record<string, unknown>, toolUseId: string): Promise<ReturnType<typeof denyPermission>>;
|
|
31
30
|
requestApproval(runId: string, toolName: string, input: Record<string, unknown>): Promise<ReturnType<typeof denyPermission>>;
|
|
32
31
|
rememberNative(nativeSessionId: string, sessionId: string): void;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createEnvelope } from '@myagentroam/protocol';
|
|
2
2
|
import { ClaudeChannelGate } from '../../claude-channel.js';
|
|
3
3
|
import { boundedConversationItemId, claudePlanText, compactRunnerText, compactRunnerValue, extractClaudeText, extractClaudeThinkingSummaries, extractClaudeToolResults, extractClaudeToolUses, isClaudeCommandTool } from '../codex/conversation-parser.js';
|
|
4
|
-
import { isTerminalRunStatus } from '../../util/node-operation-parsers.js';
|
|
5
4
|
import { claudeContentBlocks } from '../../util/node-operation-parsers.js';
|
|
6
5
|
import { parseSecretEnvironment } from '../../util/secret-environment.js';
|
|
6
|
+
import { safeErrorCode } from '../../util/safe-error.js';
|
|
7
|
+
import { runnerErrorProjection } from '../../util/runner-error.js';
|
|
7
8
|
export class ClaudeManagedRunController {
|
|
8
9
|
runner;
|
|
9
10
|
host;
|
|
@@ -24,10 +25,10 @@ export class ClaudeManagedRunController {
|
|
|
24
25
|
commandId: 'plan',
|
|
25
26
|
active: true,
|
|
26
27
|
label: 'Plan Mode',
|
|
27
|
-
detail: '
|
|
28
|
+
detail: 'Subsequent messages run in read-only tagged Plan Mode and produce a plan card.',
|
|
28
29
|
closable: true,
|
|
29
30
|
closeInput: '/plan',
|
|
30
|
-
continuation: { label: '
|
|
31
|
+
continuation: { label: 'Implement', prompt: 'Implement the plan above.' }
|
|
31
32
|
});
|
|
32
33
|
return { command: command.id, states: this.host.commandStates(session.id) };
|
|
33
34
|
}
|
|
@@ -83,7 +84,7 @@ export class ClaudeManagedRunController {
|
|
|
83
84
|
secretEnvironment = parseSecretEnvironment(payload.secretEnvironment);
|
|
84
85
|
}
|
|
85
86
|
catch (error) {
|
|
86
|
-
this.host.emit(runId, 'run.rejected', { code: error
|
|
87
|
+
this.host.emit(runId, 'run.rejected', { code: safeErrorCode(error, 'MESSAGE_ATTACHMENTS_INVALID') }, 'FAILED');
|
|
87
88
|
return;
|
|
88
89
|
}
|
|
89
90
|
this.host.adopt({
|
|
@@ -115,16 +116,25 @@ export class ClaudeManagedRunController {
|
|
|
115
116
|
let terminal = false;
|
|
116
117
|
let handle;
|
|
117
118
|
const toolKinds = new Map();
|
|
118
|
-
const finish = (status, eventType, eventPayload) => {
|
|
119
|
+
const finish = (status, eventType, eventPayload, failure, fallbackCode = 'CLAUDE_RUN_FAILED') => {
|
|
119
120
|
if (terminal)
|
|
120
121
|
return;
|
|
121
122
|
terminal = true;
|
|
122
|
-
|
|
123
|
+
const projected = status === 'FAILED'
|
|
124
|
+
? runnerErrorProjection(failure ?? eventPayload, fallbackCode)
|
|
125
|
+
: undefined;
|
|
126
|
+
if (projected !== undefined) {
|
|
127
|
+
this.host.emitItem(runId, {
|
|
128
|
+
itemId: boundedConversationItemId('runner-error', runId),
|
|
129
|
+
kind: 'error',
|
|
130
|
+
status: 'FAILED',
|
|
131
|
+
payload: { ...projected, recoverable: true, retryAfterMs: null }
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
this.host.emit(runId, eventType, projected ?? eventPayload, status);
|
|
123
135
|
this.runner.execution.runs.delete(runId);
|
|
124
136
|
handle?.cancel();
|
|
125
137
|
this.host.active.delete(runId);
|
|
126
|
-
if (isTerminalRunStatus(status))
|
|
127
|
-
void this.host.captureSnapshot(runId, cwd);
|
|
128
138
|
};
|
|
129
139
|
try {
|
|
130
140
|
const gate = new ClaudeChannelGate(sessionId);
|
|
@@ -255,14 +265,23 @@ export class ClaudeManagedRunController {
|
|
|
255
265
|
const kind = toolKinds.get(record.tool_use_id);
|
|
256
266
|
if (kind === 'tool_call') {
|
|
257
267
|
const elapsed = typeof record.elapsed_time_seconds === 'number'
|
|
258
|
-
?
|
|
268
|
+
? ` (${Math.max(0, Math.round(record.elapsed_time_seconds))} seconds)`
|
|
259
269
|
: '';
|
|
260
270
|
this.host.emitItem(runId, {
|
|
261
271
|
itemId: boundedConversationItemId('claude-tool', record.tool_use_id),
|
|
262
272
|
kind,
|
|
263
273
|
status: 'IN_PROGRESS',
|
|
264
274
|
payload: {
|
|
265
|
-
progressLabel: compactRunnerText(`${typeof record.tool_name === 'string' ? record.tool_name : '
|
|
275
|
+
progressLabel: compactRunnerText(`${typeof record.tool_name === 'string' ? record.tool_name : 'Tool'} is running${elapsed}`, 500),
|
|
276
|
+
progressLabelCode: typeof record.elapsed_time_seconds === 'number'
|
|
277
|
+
? 'TOOL_RUNNING_WITH_DURATION'
|
|
278
|
+
: 'TOOL_RUNNING',
|
|
279
|
+
progressLabelParameters: {
|
|
280
|
+
tool: typeof record.tool_name === 'string' ? record.tool_name : 'Tool',
|
|
281
|
+
seconds: typeof record.elapsed_time_seconds === 'number'
|
|
282
|
+
? Math.max(0, Math.round(record.elapsed_time_seconds))
|
|
283
|
+
: 0
|
|
284
|
+
}
|
|
266
285
|
},
|
|
267
286
|
merge: true
|
|
268
287
|
});
|
|
@@ -304,7 +323,7 @@ export class ClaudeManagedRunController {
|
|
|
304
323
|
// result completes this AgentRun even though that iterable can
|
|
305
324
|
// remain open waiting for another user turn; waiting only for
|
|
306
325
|
// stream closure would leave the WorkspaceLease permanently held.
|
|
307
|
-
finish(subtype === 'success' && record.is_error !== true ? 'SUCCEEDED' : 'FAILED', subtype === 'success' && record.is_error !== true ? 'run.completed' : 'run.failed', { subtype });
|
|
326
|
+
finish(subtype === 'success' && record.is_error !== true ? 'SUCCEEDED' : 'FAILED', subtype === 'success' && record.is_error !== true ? 'run.completed' : 'run.failed', { subtype }, record);
|
|
308
327
|
if (completedNativeSessionId !== undefined)
|
|
309
328
|
void this.host.syncTitle(sessionId, completedNativeSessionId, cwd);
|
|
310
329
|
}
|
|
@@ -314,14 +333,10 @@ export class ClaudeManagedRunController {
|
|
|
314
333
|
this.host.setChannelToken(sessionId, gate.token);
|
|
315
334
|
this.host.send('session.channel.ready', { sessionId, token: gate.token });
|
|
316
335
|
this.host.emit(runId, 'run.running', {}, 'RUNNING');
|
|
317
|
-
void handle.completed.then(() => finish('SUCCEEDED', 'run.completed', { subtype: 'stream_closed' }), (error) => finish('FAILED', 'run.failed', {
|
|
318
|
-
code: error instanceof Error ? error.message : 'CLAUDE_RUN_FAILED'
|
|
319
|
-
}));
|
|
336
|
+
void handle.completed.then(() => finish('SUCCEEDED', 'run.completed', { subtype: 'stream_closed' }), (error) => finish('FAILED', 'run.failed', { code: safeErrorCode(error, 'CLAUDE_RUN_FAILED') }, error));
|
|
320
337
|
}
|
|
321
338
|
catch (error) {
|
|
322
|
-
finish('FAILED', 'run.failed', {
|
|
323
|
-
code: error instanceof Error ? error.message : 'CLAUDE_RUN_START_FAILED'
|
|
324
|
-
});
|
|
339
|
+
finish('FAILED', 'run.failed', { code: safeErrorCode(error, 'CLAUDE_RUN_START_FAILED') }, error, 'CLAUDE_RUN_START_FAILED');
|
|
325
340
|
}
|
|
326
341
|
}
|
|
327
342
|
}
|
|
@@ -3,7 +3,7 @@ import { AbstractRunner } from './abstract-runner.js';
|
|
|
3
3
|
import { claudeDefaultModel, declaredRunnerProfiles } from '../runner-profiles.js';
|
|
4
4
|
import { withClaudePlanTag } from '../runner-command-engine.js';
|
|
5
5
|
import { discoverNativeSessions, readNativeSession, readClaudeNativeContextUsage } from '../native-session-history.js';
|
|
6
|
-
import { claudeDiscoveredSession, deduplicateDirectSessions,
|
|
6
|
+
import { claudeDiscoveredSession, deduplicateDirectSessions, isNativeHistory, isWithinWorkspace, latestNativeActivity } from './codex/conversation-parser.js';
|
|
7
7
|
export class ClaudeCodeRunner extends AbstractRunner {
|
|
8
8
|
client;
|
|
9
9
|
environment;
|
|
@@ -102,11 +102,10 @@ export class ClaudeCodeRunner extends AbstractRunner {
|
|
|
102
102
|
context.rememberManagedNative(external.externalSessionId, configured.id);
|
|
103
103
|
return { session: configured, activity: 'IDLE' };
|
|
104
104
|
}
|
|
105
|
-
catch
|
|
105
|
+
catch {
|
|
106
106
|
return {
|
|
107
107
|
failureCode: 'RUNNER_RESUME_FAILED',
|
|
108
|
-
messageFailureCode: 'SESSION_RESUME_REJECTED'
|
|
109
|
-
failureDetail: externalResumeFailureDetail(error)
|
|
108
|
+
messageFailureCode: 'SESSION_RESUME_REJECTED'
|
|
110
109
|
};
|
|
111
110
|
}
|
|
112
111
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { NodeAgentSession, NodeConversationItem, NodeConversationTurn, NodeMessageAttachmentInput } from '../../database.js';
|
|
2
2
|
export type PublicConversationItem = {
|
|
3
3
|
readonly itemId: string;
|
|
4
|
-
readonly kind: 'reasoning_summary' | 'tool_call' | 'command_execution' | 'user_input_request' | 'plan' | 'context_compaction' | 'file_change' | 'unknown';
|
|
4
|
+
readonly kind: 'reasoning_summary' | 'tool_call' | 'command_execution' | 'user_input_request' | 'plan' | 'context_compaction' | 'file_change' | 'error' | 'unknown';
|
|
5
5
|
readonly status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'DECLINED';
|
|
6
6
|
readonly payload: Record<string, unknown>;
|
|
7
7
|
readonly merge?: boolean;
|
|
@@ -32,8 +32,8 @@ export declare function mergeCodexCustomToolItems(invocation: NodeConversationIt
|
|
|
32
32
|
export declare function coalesceImageGenerationItems(items: readonly NodeConversationItem[]): readonly NodeConversationItem[];
|
|
33
33
|
export declare function codexPlanText(value: Record<string, unknown>): string | undefined;
|
|
34
34
|
/**
|
|
35
|
-
* Claude
|
|
36
|
-
*
|
|
35
|
+
* A final Claude tagged Plan Mode plan is fully wrapped in `<proposed_plan>` tags;
|
|
36
|
+
* text with missing or unclosed tags remains a regular assistant message.
|
|
37
37
|
*/
|
|
38
38
|
export declare function codexOfficialItem(session: NodeAgentSession, nativeTurnId: string, value: unknown, turnSequence: number, itemSequence: number, startedAt: number | null, completedAt: number | null): NodeConversationItem | undefined;
|
|
39
39
|
export declare function codexLiveConversationItem(value: Record<string, unknown>, completed: boolean, imageAttachments?: readonly Record<string, unknown>[]): PublicConversationItem | undefined;
|
|
@@ -83,6 +83,7 @@ export function codexOfficialTurn(session, value, sequence, managedTurn) {
|
|
|
83
83
|
const consumedOfficialIds = new Set();
|
|
84
84
|
const officialUser = officialItems.find((item) => item.kind === 'user_message');
|
|
85
85
|
const officialAssistants = officialItems.filter((item) => item.kind === 'assistant_message');
|
|
86
|
+
const officialContextCompactions = officialItems.filter((item) => item.kind === 'context_compaction');
|
|
86
87
|
const officialItemMarker = `:official:${value.id}:`;
|
|
87
88
|
const officialByNativeId = new Map(officialItems.flatMap((item) => {
|
|
88
89
|
const markerIndex = item.id.lastIndexOf(officialItemMarker);
|
|
@@ -95,6 +96,8 @@ export function codexOfficialTurn(session, value, sequence, managedTurn) {
|
|
|
95
96
|
let replacement;
|
|
96
97
|
if (managedItem.kind === 'user_message')
|
|
97
98
|
replacement = officialUser;
|
|
99
|
+
else if (managedItem.kind === 'context_compaction')
|
|
100
|
+
replacement = officialContextCompactions.find((item) => !consumedOfficialIds.has(item.id));
|
|
98
101
|
else {
|
|
99
102
|
const nativeId = conversationItemNativeId(managedItem.id);
|
|
100
103
|
if (nativeId !== undefined)
|
|
@@ -201,6 +204,11 @@ export function codexOfficialItems(session, nativeTurnId, values, turnSequence,
|
|
|
201
204
|
const item = codexOfficialItem(session, nativeTurnId, value, turnSequence, itemSequence, startedAt, completedAt);
|
|
202
205
|
if (item === undefined)
|
|
203
206
|
continue;
|
|
207
|
+
// Codex persists one compaction as both `compacted` state and a
|
|
208
|
+
// `context_compacted` event. App Server normalizes both records to
|
|
209
|
+
// consecutive `contextCompaction` items without preserving their source.
|
|
210
|
+
if (item.kind === 'context_compaction' && items.at(-1)?.kind === 'context_compaction')
|
|
211
|
+
continue;
|
|
204
212
|
const key = codexPairedToolCallId(value);
|
|
205
213
|
if (key === undefined) {
|
|
206
214
|
items.push(item);
|
|
@@ -295,8 +303,8 @@ export function codexPlanText(value) {
|
|
|
295
303
|
return plan.length > 0 ? plan : undefined;
|
|
296
304
|
}
|
|
297
305
|
/**
|
|
298
|
-
* Claude
|
|
299
|
-
*
|
|
306
|
+
* A final Claude tagged Plan Mode plan is fully wrapped in `<proposed_plan>` tags;
|
|
307
|
+
* text with missing or unclosed tags remains a regular assistant message.
|
|
300
308
|
*/
|
|
301
309
|
export function codexOfficialItem(session, nativeTurnId, value, turnSequence, itemSequence, startedAt, completedAt) {
|
|
302
310
|
if (!isPlainRecord(value) || typeof value.type !== 'string')
|
|
@@ -361,7 +369,7 @@ export function codexOfficialItem(session, nativeTurnId, value, turnSequence, it
|
|
|
361
369
|
payload: {
|
|
362
370
|
command: typeof value.command === 'string'
|
|
363
371
|
? compactRunnerText(value.command, 10_000)
|
|
364
|
-
: '
|
|
372
|
+
: '(No command provided)',
|
|
365
373
|
cwd: typeof value.cwd === 'string' ? compactRunnerText(value.cwd, 4_096) : null,
|
|
366
374
|
outputPreview: compactRunnerText(output, 10_000),
|
|
367
375
|
outputRef: null,
|
|
@@ -415,7 +423,7 @@ export function codexOfficialItem(session, nativeTurnId, value, turnSequence, it
|
|
|
415
423
|
namespace: 'codex',
|
|
416
424
|
toolName: 'imagegen',
|
|
417
425
|
inputSummary: typeof value.revisedPrompt === 'string' ? value.revisedPrompt : null,
|
|
418
|
-
outputSummary: value.status === 'completed' ? '
|
|
426
|
+
outputSummary: value.status === 'completed' ? 'Image generation completed' : 'Image generation failed',
|
|
419
427
|
progressLabel: null,
|
|
420
428
|
errorCode: value.status === 'failed' ? 'IMAGE_GENERATION_FAILED' : null,
|
|
421
429
|
truncated: false
|
|
@@ -456,7 +464,11 @@ export function codexOfficialItem(session, nativeTurnId, value, turnSequence, it
|
|
|
456
464
|
return {
|
|
457
465
|
...base,
|
|
458
466
|
kind: 'context_compaction',
|
|
459
|
-
payload: {
|
|
467
|
+
payload: {
|
|
468
|
+
phase: 'COMPLETED',
|
|
469
|
+
summary: 'Context compacted',
|
|
470
|
+
summaryCode: 'CONTEXT_COMPACTED'
|
|
471
|
+
}
|
|
460
472
|
};
|
|
461
473
|
return codexUnknownOfficialItem(base, value);
|
|
462
474
|
}
|
|
@@ -501,7 +513,7 @@ export function codexLiveConversationItem(value, completed, imageAttachments = [
|
|
|
501
513
|
payload: {
|
|
502
514
|
command: typeof value.command === 'string'
|
|
503
515
|
? compactRunnerText(value.command, 10_000)
|
|
504
|
-
: '
|
|
516
|
+
: '(No command provided)',
|
|
505
517
|
cwd: typeof value.cwd === 'string' ? compactRunnerText(value.cwd, 4_096) : null,
|
|
506
518
|
outputPreview: compactRunnerText(output, 10_000),
|
|
507
519
|
outputRef: null,
|
|
@@ -550,7 +562,8 @@ export function codexLiveConversationItem(value, completed, imageAttachments = [
|
|
|
550
562
|
title: 'Web Search',
|
|
551
563
|
inputSummary: typeof value.query === 'string' ? compactRunnerText(value.query, 10_000) : null,
|
|
552
564
|
outputSummary: null,
|
|
553
|
-
progressLabel: completed ? null : '
|
|
565
|
+
progressLabel: completed ? null : 'Searching',
|
|
566
|
+
progressLabelCode: completed ? null : 'SEARCHING',
|
|
554
567
|
errorCode: null,
|
|
555
568
|
truncated: false
|
|
556
569
|
}
|
|
@@ -575,8 +588,10 @@ export function codexLiveConversationItem(value, completed, imageAttachments = [
|
|
|
575
588
|
inputSummary: typeof value.revisedPrompt === 'string'
|
|
576
589
|
? compactRunnerText(value.revisedPrompt, 10_000)
|
|
577
590
|
: null,
|
|
578
|
-
outputSummary: completed ? '
|
|
579
|
-
|
|
591
|
+
outputSummary: completed ? 'Image generation completed' : null,
|
|
592
|
+
outputSummaryCode: completed ? 'IMAGE_GENERATION_COMPLETED' : null,
|
|
593
|
+
progressLabel: completed ? null : 'Generating image',
|
|
594
|
+
progressLabelCode: completed ? null : 'GENERATING_IMAGE',
|
|
580
595
|
errorCode: value.status === 'failed' ? 'IMAGE_GENERATION_FAILED' : null,
|
|
581
596
|
truncated: false,
|
|
582
597
|
...(imageAttachments.length === 0 ? {} : { attachments: imageAttachments })
|
|
@@ -704,7 +719,9 @@ export function codexImageAttachments(value) {
|
|
|
704
719
|
totalBytes + Buffer.byteLength(dataBase64, 'base64') <= MAX_COMPOSER_ATTACHMENTS_BYTES) {
|
|
705
720
|
totalBytes += Buffer.byteLength(dataBase64, 'base64');
|
|
706
721
|
found.push({
|
|
707
|
-
name: typeof current.name === 'string'
|
|
722
|
+
name: typeof current.name === 'string'
|
|
723
|
+
? current.name
|
|
724
|
+
: `generated-image-${found.length + 1}.png`,
|
|
708
725
|
mime,
|
|
709
726
|
dataBase64
|
|
710
727
|
});
|
|
@@ -802,10 +819,14 @@ export function codexToolOutput(value) {
|
|
|
802
819
|
return [block.content];
|
|
803
820
|
return [];
|
|
804
821
|
});
|
|
805
|
-
return text.length > 0
|
|
822
|
+
return text.length > 0
|
|
823
|
+
? text.join('')
|
|
824
|
+
: value.some(isCodexImageBlock)
|
|
825
|
+
? 'Image generated'
|
|
826
|
+
: value;
|
|
806
827
|
}
|
|
807
828
|
export function codexVisibleToolText(value) {
|
|
808
|
-
return value.replace(/(["']image_url["']\s*:\s*["'])data:image\/[^"']+(["'])/g, '$1[
|
|
829
|
+
return value.replace(/(["']image_url["']\s*:\s*["'])data:image\/[^"']+(["'])/g, '$1[Image content extracted]$2');
|
|
809
830
|
}
|
|
810
831
|
export function isCodexImageBlock(value) {
|
|
811
832
|
if (!isPlainRecord(value))
|
|
@@ -44,14 +44,13 @@ export interface CodexManagedRunHost<TAttachment> {
|
|
|
44
44
|
}): void;
|
|
45
45
|
emitItem(runId: string, item: {
|
|
46
46
|
readonly itemId: string;
|
|
47
|
-
readonly kind: 'reasoning_summary' | 'tool_call' | 'command_execution' | 'user_input_request' | 'plan' | 'context_compaction' | 'file_change' | 'unknown';
|
|
47
|
+
readonly kind: 'reasoning_summary' | 'tool_call' | 'command_execution' | 'user_input_request' | 'plan' | 'context_compaction' | 'file_change' | 'error' | 'unknown';
|
|
48
48
|
readonly status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'DECLINED';
|
|
49
49
|
readonly payload: Record<string, unknown>;
|
|
50
50
|
readonly merge?: boolean;
|
|
51
51
|
readonly append?: 'sections' | 'outputPreview' | 'outputSummary';
|
|
52
52
|
}): void;
|
|
53
53
|
appendImages(runId: string, images: readonly NodeMessageAttachmentInput[]): readonly Record<string, unknown>[];
|
|
54
|
-
captureSnapshot(runId: string, cwd: string): Promise<void>;
|
|
55
54
|
syncTitle(sessionId: string, nativeSessionId: string, cwd: string): Promise<void>;
|
|
56
55
|
commandState(sessionId: string, commandId: string): RunnerCommandState | undefined;
|
|
57
56
|
setCommandState(sessionId: string, state: RunnerCommandState): void;
|
|
@@ -76,5 +75,6 @@ export declare class CodexManagedRunController<TAttachment> {
|
|
|
76
75
|
private requestUserInput;
|
|
77
76
|
start(envelope: NodeEnvelope): void;
|
|
78
77
|
private run;
|
|
78
|
+
private emitError;
|
|
79
79
|
}
|
|
80
80
|
export {};
|