@myagentroam/node 0.9.62 → 0.9.65
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/LICENSE +202 -0
- package/NOTICE +4 -0
- package/dist/capabilities.js +110 -2
- package/dist/claude-agent-sdk.js +330 -2
- package/dist/claude-channel.js +44 -2
- package/dist/codex-app-server.js +510 -2
- package/dist/config.js +106 -2
- package/dist/connector/node-connector-options.js +1 -2
- package/dist/connector/node-operation-router.js +22 -2
- package/dist/connector.js +1736 -2
- package/dist/control-outbound-scheduler.js +153 -2
- package/dist/database.js +639 -2
- package/dist/fake-runner.js +129 -2
- package/dist/git-askpass.js +12 -0
- package/dist/git-execution-helper.js +266 -0
- package/dist/health.js +3 -2
- package/dist/main.js +57 -2
- package/dist/mcp-installation-model.js +1 -2
- package/dist/migrations/v004.js +55 -3
- package/dist/migrations/v005.js +13 -3
- package/dist/migrations/v006.js +90 -3
- package/dist/migrations/v007.js +22 -3
- package/dist/migrations/v008.js +18 -3
- package/dist/migrations/v009.js +70 -4
- package/dist/migrations/v010.js +43 -3
- package/dist/migrations/v011.js +20 -3
- package/dist/migrations/v012.js +8 -0
- package/dist/native-jsonl-reader.js +186 -2
- package/dist/native-session-history.js +1143 -2
- package/dist/opencode-runtime.js +80 -2
- package/dist/opencode-server.js +259 -2
- package/dist/operational.js +122 -2
- package/dist/process-tree.js +18 -2
- package/dist/ripgrep-binary.js +31 -2
- package/dist/rotating-log.js +67 -2
- package/dist/runner/abstract-runner.js +260 -2
- package/dist/runner/claude/managed-run-controller.js +355 -2
- package/dist/runner/claude/tool-normalizer.js +120 -2
- package/dist/runner/claude-code-runner.js +303 -2
- package/dist/runner/codex/composer-image-markers.js +8 -2
- package/dist/runner/codex/conversation-parser.js +913 -2
- package/dist/runner/codex/managed-run-controller.js +494 -2
- package/dist/runner/codex/tool-normalizer.js +214 -2
- package/dist/runner/codex-runner.js +585 -2
- package/dist/runner/fake-test-runner.js +47 -2
- package/dist/runner/mar-agent/conversation-normalizer.js +644 -2
- package/dist/runner/mar-agent/executor-stdio-client-transport.js +139 -2
- package/dist/runner/mar-agent/generated-images.js +41 -2
- package/dist/runner/mar-agent/history-projection.js +106 -2
- package/dist/runner/mar-agent/hosted-conversation-runtime.js +446 -2
- package/dist/runner/mar-agent/managed-run-controller.js +785 -2
- package/dist/runner/mar-agent/mcp-client-pool.js +233 -2
- package/dist/runner/mar-agent/runtime-model-factory.js +326 -2
- package/dist/runner/mar-agent-runner.js +458 -2
- package/dist/runner/opencode/conversation-parser.js +221 -2
- package/dist/runner/opencode/managed-run-controller.js +588 -2
- package/dist/runner/opencode/tool-normalizer.js +80 -2
- package/dist/runner/opencode-runner.js +426 -2
- package/dist/runner/runner-registry.js +87 -2
- package/dist/runner-command-engine.js +71 -2
- package/dist/runner-profiles.js +323 -2
- package/dist/runner-usage.js +190 -2
- package/dist/runtime-command-detector.js +73 -2
- package/dist/runtime-model.js +1 -2
- package/dist/runtime-state.js +1509 -2
- package/dist/service/attachment-domain-state.js +7 -2
- package/dist/service/bubblewrap-sandbox-executor.js +543 -2
- package/dist/service/continuous-run-coordinator.js +425 -2
- package/dist/service/conversation-history-service.js +552 -2
- package/dist/service/conversation-hosting-capability-service.js +61 -2
- package/dist/service/conversation-hosting-enablement-service.js +91 -2
- package/dist/service/conversation-hosting-maintenance-service.js +174 -2
- package/dist/service/conversation-segment-service.js +162 -2
- package/dist/service/conversation-template-node-service.js +992 -2
- package/dist/service/external-session-resume-service.js +152 -2
- package/dist/service/fake-managed-run-service.js +60 -2
- package/dist/service/git-execution-service.js +418 -0
- package/dist/service/git-operation-service.js +57 -0
- package/dist/service/hosted-conversation-node-service.js +1982 -2
- package/dist/service/hosted-conversation-store.js +1405 -2
- package/dist/service/managed-runner-session-service.js +35 -2
- package/dist/service/mar-agent-model-transport-test-service.js +88 -2
- package/dist/service/mcp-installation-verifier.js +87 -2
- package/dist/service/mcp-node-operation-service.js +90 -2
- package/dist/service/mission-mcp-server.js +124 -2
- package/dist/service/mission-mcp-stdio.js +40 -2
- package/dist/service/mission-runtime.js +142 -2
- package/dist/service/native-session-projection-service.js +274 -2
- package/dist/service/native-session-watch-service.js +683 -2
- package/dist/service/node-connection-lifecycle-service.js +88 -2
- package/dist/service/node-control-channel.js +85 -2
- package/dist/service/node-control-message-service.js +109 -2
- package/dist/service/node-request-service.js +62 -2
- package/dist/service/node-run-event-bridge.js +88 -2
- package/dist/service/node-terminal-channel.js +202 -2
- package/dist/service/node-upgrade-coordinator.js +137 -2
- package/dist/service/node-workspace-coordinator.js +97 -2
- package/dist/service/recent-run-projection-service.js +99 -2
- package/dist/service/run-attachment-service.js +321 -2
- package/dist/service/run-domain-state.js +4 -2
- package/dist/service/run-event-service.js +246 -2
- package/dist/service/run-ownership-policy.js +22 -2
- package/dist/service/run-workbench-service.js +120 -2
- package/dist/service/runner-channel-message-service.js +20 -2
- package/dist/service/runner-interaction-service.js +243 -2
- package/dist/service/runner-service.js +69 -2
- package/dist/service/runtime-credential-control-service.js +95 -2
- package/dist/service/session-catalog-service.js +404 -2
- package/dist/service/session-command-service.js +125 -2
- package/dist/service/session-context-service.js +128 -2
- package/dist/service/session-domain-state.js +9 -2
- package/dist/service/session-identity-service.js +86 -2
- package/dist/service/session-lifecycle-service.js +248 -2
- package/dist/service/session-message-service.js +270 -2
- package/dist/service/session-presentation-service.js +43 -2
- package/dist/service/session-query-service.js +82 -2
- package/dist/service/session-watch-slot-coordinator.js +21 -2
- package/dist/service/skill-directory-service.js +238 -2
- package/dist/service/skill-install-service.js +434 -2
- package/dist/service/skill-node-operation-service.js +206 -2
- package/dist/service/terminal-relay-state.js +3 -2
- package/dist/service/terminal-service.js +90 -2
- package/dist/service/web-search-error.js +40 -2
- package/dist/service/workbench-event-service.js +21 -2
- package/dist/service/workbench-manifest-service.js +69 -2
- package/dist/service/workspace-change-service.js +290 -2
- package/dist/service/workspace-content-search-service.js +457 -2
- package/dist/service/workspace-domain-state.js +41 -2
- package/dist/service/workspace-file-service.js +150 -2
- package/dist/service/workspace-git-exclude-service.js +119 -2
- package/dist/service/workspace-queue-workbench-service.js +176 -2
- package/dist/service/workspace-service.js +92 -2
- package/dist/service/workspace-session-service.js +154 -2
- package/dist/service/workspace-upload-service.js +262 -2
- package/dist/service/workspace-watch-controller.js +68 -2
- package/dist/service/workspace-watch-service.js +170 -2
- package/dist/service/workspace-watch-snapshot-service.js +218 -2
- package/dist/service/workspace-workbench-service.js +239 -2
- package/dist/service.js +91 -2
- package/dist/storage.js +32 -2
- package/dist/supervisor.js +136 -2
- package/dist/terminal.js +496 -2
- package/dist/util/git-credential-client.js +32 -0
- package/dist/util/node-operation-data.js +9 -2
- package/dist/util/node-operation-parsers.js +382 -2
- package/dist/util/personal-instructions.js +34 -2
- package/dist/util/runner-error.js +70 -2
- package/dist/util/runner-native-session-parsers.js +510 -2
- package/dist/util/safe-error.js +8 -2
- package/dist/util/secret-environment.js +25 -2
- package/dist/workspace.js +1793 -2
- package/package.json +11 -8
- package/vendor/ripgrep/darwin-arm64/rg +0 -0
- package/vendor/ripgrep/darwin-x64/rg +0 -0
- package/vendor/ripgrep/manifest.json +12 -0
- package/README.md +0 -42
- package/dist/event-buffer.js +0 -2
- package/dist/migrations/v001.js +0 -107
- package/dist/migrations/v002.js +0 -2
- package/dist/migrations/v003.js +0 -2
- package/dist/service/mcp-package-installer.js +0 -2
|
@@ -1,2 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export function assertRunOwner(run, requestUserId) {
|
|
2
|
+
if (Number.isSafeInteger(requestUserId) && run.initiatedByUserId !== requestUserId)
|
|
3
|
+
throw new Error('RUN_OWNED_BY_ANOTHER_USER');
|
|
4
|
+
}
|
|
5
|
+
export function assertQueueItemOwner(item, requestUserId) {
|
|
6
|
+
if (Number.isSafeInteger(requestUserId) && item.initiatedByUserId !== requestUserId)
|
|
7
|
+
throw new Error('RUN_OWNED_BY_ANOTHER_USER');
|
|
8
|
+
}
|
|
9
|
+
export function assertSessionControlOwner(runtime, sessionId, requestUserId) {
|
|
10
|
+
if (!Number.isSafeInteger(requestUserId))
|
|
11
|
+
return;
|
|
12
|
+
const active = runtime.activeSessionRun(sessionId);
|
|
13
|
+
if (active !== undefined) {
|
|
14
|
+
assertRunOwner(active, requestUserId);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
for (const itemId of runtime.sessionQueue(sessionId).itemIds) {
|
|
18
|
+
const item = runtime.getQueueItem(itemId);
|
|
19
|
+
if (item !== undefined)
|
|
20
|
+
assertQueueItemOwner(item, requestUserId);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,2 +1,120 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { isTerminalRunStatus } from '../util/node-operation-parsers.js';
|
|
2
|
+
import { isPlainRecord } from '../runner/codex/conversation-parser.js';
|
|
3
|
+
import { isHostedConversationImageRunId } from '../runner/mar-agent/generated-images.js';
|
|
4
|
+
import { assertRunOwner } from './run-ownership-policy.js';
|
|
5
|
+
export class RunWorkbenchService {
|
|
6
|
+
options;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
operations() {
|
|
11
|
+
return {
|
|
12
|
+
'run.get': (data) => this.get(record(data)),
|
|
13
|
+
'run.image.read': (data) => this.image(record(data)),
|
|
14
|
+
'run.user-input.respond': (data) => this.respond(record(data)),
|
|
15
|
+
'session.interrupt': (data) => this.interruptSession(record(data)),
|
|
16
|
+
'run.cancel': (data) => this.cancelOrInterrupt('run.cancel', record(data)),
|
|
17
|
+
'run.interrupt': (data) => this.cancelOrInterrupt('run.interrupt', record(data)),
|
|
18
|
+
'run.approval.decide': (data) => this.decideApproval(record(data))
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
get(input) {
|
|
22
|
+
return { run: this.requireRun(input.runId) };
|
|
23
|
+
}
|
|
24
|
+
async image(input) {
|
|
25
|
+
if (typeof input.runId !== 'string' ||
|
|
26
|
+
typeof input.imageIndex !== 'number' ||
|
|
27
|
+
!Number.isInteger(input.imageIndex) ||
|
|
28
|
+
input.imageIndex < 0)
|
|
29
|
+
throw new Error('RUN_IMAGE_INVALID');
|
|
30
|
+
if (isHostedConversationImageRunId(input.runId))
|
|
31
|
+
throw new Error('RUN_IMAGE_INVALID');
|
|
32
|
+
const image = await this.options.readImage(input.runId, input.imageIndex);
|
|
33
|
+
if (image === undefined)
|
|
34
|
+
throw new Error('RUN_IMAGE_NOT_FOUND');
|
|
35
|
+
return { image };
|
|
36
|
+
}
|
|
37
|
+
respond(input) {
|
|
38
|
+
if (typeof input.runId !== 'string' ||
|
|
39
|
+
typeof input.requestId !== 'string' ||
|
|
40
|
+
!isPlainRecord(input.answers))
|
|
41
|
+
throw new Error('USER_INPUT_INVALID');
|
|
42
|
+
const run = this.requireOwnedRun(input.runId, input.__requestUserId);
|
|
43
|
+
// Direct control-envelope runs use the public Run ID as their Runner
|
|
44
|
+
// handle. Continuous Workbench runs resolve to their current Execution.
|
|
45
|
+
const executionId = this.options.runtime.currentExecutionId(run.id) ?? run.id;
|
|
46
|
+
this.options.respondUserInput(executionId, input.requestId, input.answers);
|
|
47
|
+
return { accepted: true };
|
|
48
|
+
}
|
|
49
|
+
interruptSession(input) {
|
|
50
|
+
if (typeof input.sessionId !== 'string')
|
|
51
|
+
throw new Error('SESSION_NOT_FOUND');
|
|
52
|
+
const session = this.options.runtime.getAgentSession(input.sessionId);
|
|
53
|
+
if (session === undefined)
|
|
54
|
+
throw new Error('SESSION_NOT_FOUND');
|
|
55
|
+
const run = this.options.runtime.activeSessionRun(session.id);
|
|
56
|
+
if (run === undefined || isTerminalRunStatus(run.status))
|
|
57
|
+
throw new Error('RUN_NOT_FOUND');
|
|
58
|
+
return this.cancelOrInterrupt('run.interrupt', {
|
|
59
|
+
runId: run.id,
|
|
60
|
+
__requestUserId: input.__requestUserId
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
cancelOrInterrupt(operation, input) {
|
|
64
|
+
const run = this.requireOwnedRun(input.runId, input.__requestUserId);
|
|
65
|
+
const next = this.options.runtime.transitionRun(run.id, 'CANCELLING');
|
|
66
|
+
const executionId = this.options.runtime.currentExecutionId(run.id);
|
|
67
|
+
const turn = this.options.runtime.conversationTurnForRun(run.id);
|
|
68
|
+
const controlRunId = executionId ?? (turn === undefined || turn.userItemId === null ? run.id : undefined);
|
|
69
|
+
this.options.pauseQueue(run.sessionId);
|
|
70
|
+
if (controlRunId === undefined) {
|
|
71
|
+
this.options.markInterrupted(run.id);
|
|
72
|
+
this.options.emitRun(run.id, 'run.interrupted', { code: 'USER_INTERRUPTED' }, 'INTERRUPTED');
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
this.options.markInterrupted(controlRunId);
|
|
76
|
+
this.options.control(operation, { runId: controlRunId });
|
|
77
|
+
}
|
|
78
|
+
return { run: next };
|
|
79
|
+
}
|
|
80
|
+
decideApproval(input) {
|
|
81
|
+
if (typeof input.runId !== 'string' ||
|
|
82
|
+
typeof input.approvalId !== 'string' ||
|
|
83
|
+
(input.decision !== 'APPROVED' && input.decision !== 'REJECTED'))
|
|
84
|
+
throw new Error('APPROVAL_DECISION_INVALID');
|
|
85
|
+
const current = this.options.runtime.getApproval(input.approvalId);
|
|
86
|
+
if (current === undefined || this.options.runtime.canonicalRunId(current.runId) !== input.runId)
|
|
87
|
+
throw new Error('APPROVAL_NOT_FOUND');
|
|
88
|
+
this.assertRunOwner(current.runId, input.__requestUserId);
|
|
89
|
+
const approval = this.options.runtime.decideApproval(input.approvalId, input.decision);
|
|
90
|
+
this.options.emitRun(approval.runId, 'approval.decided', {
|
|
91
|
+
approvalId: approval.id,
|
|
92
|
+
decision: input.decision
|
|
93
|
+
});
|
|
94
|
+
this.options.control('run.approval.decision', {
|
|
95
|
+
runId: approval.runId,
|
|
96
|
+
approvalId: approval.id,
|
|
97
|
+
decision: input.decision
|
|
98
|
+
});
|
|
99
|
+
return { approval };
|
|
100
|
+
}
|
|
101
|
+
requireRun(runId) {
|
|
102
|
+
if (typeof runId !== 'string')
|
|
103
|
+
throw new Error('RUN_NOT_FOUND');
|
|
104
|
+
const run = this.options.runtime.getRun(runId);
|
|
105
|
+
if (run === undefined)
|
|
106
|
+
throw new Error('RUN_NOT_FOUND');
|
|
107
|
+
return run;
|
|
108
|
+
}
|
|
109
|
+
requireOwnedRun(runId, requestUserId) {
|
|
110
|
+
const run = this.requireRun(runId);
|
|
111
|
+
assertRunOwner(run, requestUserId);
|
|
112
|
+
return run;
|
|
113
|
+
}
|
|
114
|
+
assertRunOwner(runId, requestUserId) {
|
|
115
|
+
assertRunOwner(this.requireRun(runId), requestUserId);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function record(value) {
|
|
119
|
+
return isPlainRecord(value) ? value : {};
|
|
120
|
+
}
|
|
@@ -1,2 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/** Validates shared-control channel messages before delivery to a Runner. */
|
|
2
|
+
export class RunnerChannelMessageService {
|
|
3
|
+
options;
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options;
|
|
6
|
+
}
|
|
7
|
+
handle(envelope) {
|
|
8
|
+
const payload = envelope.payload;
|
|
9
|
+
if (typeof payload.sessionId !== 'string' ||
|
|
10
|
+
typeof payload.id !== 'string' ||
|
|
11
|
+
typeof payload.senderId !== 'string' ||
|
|
12
|
+
typeof payload.token !== 'string' ||
|
|
13
|
+
typeof payload.content !== 'string') {
|
|
14
|
+
this.options.send('error', { code: 'MESSAGE_INVALID' }, envelope.id);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const delivery = this.options.interactions.deliverChannel('claude-code', payload.sessionId, payload.id, payload.senderId, payload.token, payload.content);
|
|
18
|
+
this.options.send('ack', { type: envelope.type, delivery }, envelope.id);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,2 +1,243 @@
|
|
|
1
|
-
|
|
2
|
-
function _0x5b59(_0x4180fe,_0x4d941e){_0x4180fe=_0x4180fe-(0x8cf*0x3+-0x21e*0x8+-0x2a5*0x3);const _0x4d15a4=_0x4429();let _0x27cf6a=_0x4d15a4[_0x4180fe];if(_0x5b59['maujNQ']===undefined){var _0x6728c1=function(_0x1a6286){const _0x9f99ca='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x3c31a6='',_0x3395ec='';for(let _0xc6ab24=-0x184*-0xb+-0x1651+0x5a5,_0x2d14dd,_0x14cd7f,_0x233731=-0x13c7+-0x4*-0x16f+0xe0b;_0x14cd7f=_0x1a6286['charAt'](_0x233731++);~_0x14cd7f&&(_0x2d14dd=_0xc6ab24%(0x59d*0x6+-0x5c1*-0x3+-0x32ed)?_0x2d14dd*(-0x9*-0x6a+0x2*-0xe20+0x18c6)+_0x14cd7f:_0x14cd7f,_0xc6ab24++%(-0x2056+-0x2505+-0x7*-0x9e9))?_0x3c31a6+=String['fromCharCode'](0x23ed+0x237*0x7+-0x326f&_0x2d14dd>>(-(-0x730+-0xa6+0x7d8)*_0xc6ab24&0x1db9+-0xdf4+-0xfbf)):0xd*-0x21f+0x4*0x8c3+-0x779*0x1){_0x14cd7f=_0x9f99ca['indexOf'](_0x14cd7f);}for(let _0x53a8af=0x101a+-0x11ce+0x1b4,_0x37ed60=_0x3c31a6['length'];_0x53a8af<_0x37ed60;_0x53a8af++){_0x3395ec+='%'+('00'+_0x3c31a6['charCodeAt'](_0x53a8af)['toString'](0x1f*-0x31+-0x243d*0x1+0x2a3c))['slice'](-(0x8bf+0x1*-0x17c3+0x281*0x6));}return decodeURIComponent(_0x3395ec);};_0x5b59['gbxkSI']=_0x6728c1,_0x5b59['dtItYz']={},_0x5b59['maujNQ']=!![];}const _0x4fa471=_0x4d15a4[-0x566*-0x1+-0x1*-0x22e1+-0xd6d*0x3];_0x5b59['OvOubC']!==_0x4fa471&&(_0x5b59['dtItYz']={},_0x5b59['OvOubC']=_0x4fa471);const _0x3cfbb5=_0x5b59['dtItYz'][_0x4180fe];return _0x3cfbb5===undefined?(_0x27cf6a=_0x5b59['gbxkSI'](_0x27cf6a),_0x5b59['dtItYz'][_0x4180fe]=_0x27cf6a):_0x27cf6a=_0x3cfbb5,_0x27cf6a;}const _0x2de83f=_0x5b59;(function(_0x1a1067,_0x3d4ede){const _0x334f3f=_0x5b59,_0x388874=_0x1a1067();while(!![]){try{const _0x4d4f25=-parseInt(_0x334f3f(0x1a1))/(0x11b2*0x2+0x1*-0x19ed+-0x976)*(parseInt(_0x334f3f(0x1f1))/(-0x11f1+0x21bf+-0xfcc))+parseInt(_0x334f3f(0x1b9))/(-0xc*0x22e+-0x1d95+0x37c0)+-parseInt(_0x334f3f(0x1ba))/(-0x352+-0x1aaf+-0x1e05*-0x1)*(-parseInt(_0x334f3f(0x1bf))/(0x14bb+-0x16fc+0x246))+parseInt(_0x334f3f(0x1ae))/(-0x1*0xf09+-0xebe+0x9ef*0x3)*(parseInt(_0x334f3f(0x1e9))/(-0x2a+0xfcc+-0xf9b))+-parseInt(_0x334f3f(0x19c))/(0x1*0x2566+0x9f3*0x2+0x5*-0xb74)*(parseInt(_0x334f3f(0x1f0))/(0x3*-0x2d8+0x2e7+0x5aa))+-parseInt(_0x334f3f(0x1b6))/(0x1998+0x1780+-0x12b*0x2a)+parseInt(_0x334f3f(0x1a0))/(0x151c+-0x16b+-0x13a6);if(_0x4d4f25===_0x3d4ede)break;else _0x388874['push'](_0x388874['shift']());}catch(_0x1b781e){_0x388874['push'](_0x388874['shift']());}}}(_0x4429,0x2e204+-0x121c60+0x198cac));import{denyPermission}from'../claude-agent-sdk.js';function _0x4429(){const _0x3e7d8c=['Aw50zxjYDxb0','y2fUy2vSq2XHDwrLuNvU','Aw5JBhvKzxm','su5urvjsvvburuq','q09ervHFsu5urvjsvvbux0zbsuXfra','vvnfuL9jtLbvvf9jtLzbteLe','mtyYDe1fBu12','CNvUlMzHAwXLza','vvnfuL9jtLbvvf9ot1rFrK9vtKq','zgvJAwrLq2XHDwrLqxbWCM92ywW','uevoreLorW','q0foq0vmteLorW','BxvSDgLtzwXLy3q','CMvSzwfZzuvUDMLYB25Tzw50','mtaYodKYmJbVu3jWD3u','yxbWCM92ywXuAw1LB3v0txm','CNvUlMnVBxbSzxrLza','mJK3nJC2nxjwsvLYva','mZqYmdy0qM1rDhvq','CMvZB2X2zq','y2XHDwrLoG','AxnbCNjHEq','BwvZC2fNzq','mtbQBKDzrvi','Aw50zxjYDxb0uMvXDwvZDgvK','y2XHDwrL','CMvZCg9UzenVzgv4vxnLCKLUChv0','zgvJAwrLq29KzxHbChbYB3zHBa','ywXSB3DpDgHLCG','zw1PDeL0zw0','q0foq0vm','zxHLy3v0Aw9U','y2XHDwrLlwLUChv0','DMfSDwu','C3rHDgu','C29Tzq','C3rYAw5N','ywnJzxb0','CMfUzg9Tvvvjra','z2v0','CNvUDgLTzq','y29TCgXLDgvdyw5JzwXSzwrsDw4','DgLTzxi','Bwf4','y2fUy2vS','yxbWCM92ywWUzxHWAxjLza','DgHLBG','BM93','AgfUzgXL','y2fUy2vSq29KzxHuDxjU','vvnfuL9jtLbvvf9fwfbjuKve','y29KzxG','Aw50zxjYDxb0vhvYBG','yw5ZD2vYCW','CNvUBMvYCW','CNvUCW','q0foq0vmteve','AM9PBG','zgvJBgLUzq','zgvSzxrL','CMvXDwLYzq','qvbquK9wruq','zxHWAxjLqxbWCM92ywW','C2v0','CMvXDwvZDeLK','mJq4mtCXvhnXD0Pm','ywXSB3C','AgfZ','y3jLyxrLqxbWCM92ywW','CMvXDwvZDenSyxvKzvvZzxjjBNb1Da','CxvLC3rPB25Z','ChvIBgLZAefWChjVDMfS','ou56C2vUqG','nZeWCvnIugXz','CMvZCg9UzfvZzxjjBNb1Da','ChjVBxb0','zw1PDfj1BG','qvbquK9wquXFtK9ux0vyueLsruq','q09nueXfveve','CNvUswq','zgvSAxzLCKnOyw5UzwW','BwfW','y2HHBM5LBc5KzwXPDMvYEq','CMvZCg9Uza','y29KzxGTAw5WDxq','CMvQzwn0','DxnLCL9PBNb1Df9Yzxf1zxn0','B3b0Aw9UCW','yxbWCM92ywXZ','qvbquK9wquXFrvHqsvjfra','mtGYmti4uNPOA1vM','C3rHDhvZ','rKfjteve','BgvUz3rO','mtC5ndK0n01OEwzfzW','mtu2nxvXwfPJAa','DxnLCKLUChv0CW','q0Xbvurfx0LovevsuLvqvf9gquLmruq','qvbquK9wquXFu1rpuKvFrKfjteve','ywn0AxzL','z2v0uNvU','CMvXDwvZDenSyxvKzufWChjVDMfS'];_0x4429=function(){return _0x3e7d8c;};return _0x4429();}import{boundedConversationItemId,claudeUserInputQuestions,isTerminalRunStatus}from'../runner/codex/conversation-parser.js';export class RunnerInteractionService{[_0x2de83f(0x199)];constructor(_0xd329b3){const _0x522781=_0x2de83f;this[_0x522781(0x199)]=_0xd329b3;}[_0x2de83f(0x1a7)](_0x1e3b66,_0xe08c82,_0x5a76c9){const _0xdd7c81=_0x2de83f,_0x4fc056=_0xdd7c81(0x1bc)+crypto[_0xdd7c81(0x1ce)]();return new Promise(_0x3ccea1=>{const _0x3dc0be=_0xdd7c81,_0x591c8b=Date[_0x3dc0be(0x1d7)]()+this[_0x3dc0be(0x199)][_0x3dc0be(0x1b7)],_0x424286=_0x4357d1=>_0x3ccea1(_0x4357d1===_0x3dc0be(0x1e5)?{'behavior':_0x3dc0be(0x1ea),'updatedInput':_0x5a76c9}:denyPermission());try{this[_0x3dc0be(0x199)][_0x3dc0be(0x1d0)][_0x3dc0be(0x1ec)]({'runId':_0x1e3b66,'approvalId':_0x4fc056,'payload':{'toolName':_0xe08c82,'input':_0x5a76c9},'expiresAt':_0x591c8b});}catch{_0x3ccea1(denyPermission(_0x3dc0be(0x1a4)));return;}const _0x3d5fe2=()=>{const _0x21eda7=_0x3dc0be,_0x19f52e=this[_0x21eda7(0x199)][_0x21eda7(0x1c1)]()[_0x21eda7(0x1c7)][_0x21eda7(0x19a)],_0x1528e7=_0x19f52e[_0x21eda7(0x1cf)](_0x4fc056);if(_0x1528e7===undefined)return;try{this[_0x21eda7(0x199)][_0x21eda7(0x1d0)][_0x21eda7(0x1e6)](_0x4fc056);}catch(_0x2cd2ea){if(_0x2cd2ea instanceof Error&&_0x2cd2ea[_0x21eda7(0x1be)]===_0x21eda7(0x18f)){const _0xa7a0df=setTimeout(_0x3d5fe2,Math[_0x21eda7(0x1d3)](0xef2+-0x1a82+0xb91,_0x591c8b-Date[_0x21eda7(0x1d7)]()));_0x19f52e[_0x21eda7(0x1e7)](_0x4fc056,{..._0x1528e7,'timer':_0xa7a0df});return;}}_0x19f52e[_0x21eda7(0x1e3)](_0x4fc056),this[_0x21eda7(0x199)][_0x21eda7(0x18e)](_0x1528e7[_0x21eda7(0x191)],_0x21eda7(0x1d5),{'approvalId':_0x4fc056}),_0x3ccea1(denyPermission(_0x21eda7(0x19b)));},_0x61074c=setTimeout(_0x3d5fe2,this[_0x3dc0be(0x199)][_0x3dc0be(0x1b7)]);this[_0x3dc0be(0x199)][_0x3dc0be(0x1c1)]()[_0x3dc0be(0x1c7)][_0x3dc0be(0x19a)][_0x3dc0be(0x1e7)](_0x4fc056,{'runId':_0x1e3b66,'timer':_0x61074c,'resolve':_0x424286}),this[_0x3dc0be(0x199)][_0x3dc0be(0x1ef)]({'runId':_0x1e3b66,'approvalId':_0x4fc056,'payload':{'toolName':_0xe08c82,'input':_0x5a76c9},'expiresAt':_0x591c8b});});}[_0x2de83f(0x1ed)](_0x287208,_0x375da8,_0x50e80f){const _0x5a08a8=_0x2de83f,_0x461425=claudeUserInputQuestions(_0x375da8);if(_0x461425[_0x5a08a8(0x19f)]===-0x4*-0x16f+-0xf8b+0x1f*0x51)return Promise[_0x5a08a8(0x1bb)](denyPermission(_0x5a08a8(0x1ad)));const _0x4b8941=_0x5a08a8(0x1bc)+_0x287208+':'+_0x50e80f;return new Promise(_0x11bc59=>{const _0x36fcf2=_0x5a08a8,_0x2b39ce={..._0x375da8},_0x3a5d31=setTimeout(()=>{const _0x552c43=_0x5b59,_0x12b05b=this[_0x552c43(0x199)][_0x552c43(0x1c1)]()[_0x552c43(0x1c7)][_0x552c43(0x1a2)][_0x552c43(0x1cf)](_0x4b8941);if(_0x12b05b===undefined)return;this[_0x552c43(0x199)][_0x552c43(0x1c1)]()[_0x552c43(0x1c7)][_0x552c43(0x1a2)][_0x552c43(0x1e3)](_0x4b8941),_0x12b05b[_0x552c43(0x197)](_0x552c43(0x1da)),this[_0x552c43(0x199)][_0x552c43(0x1c5)](_0x287208,{'itemId':boundedConversationItemId(_0x552c43(0x1c8),_0x4b8941),'kind':_0x552c43(0x198),'status':_0x552c43(0x19e),'payload':{'requestId':_0x4b8941,'questions':_0x461425},'merge':!![]});},this[_0x36fcf2(0x199)][_0x36fcf2(0x1b7)]);this[_0x36fcf2(0x199)][_0x36fcf2(0x1c1)]()[_0x36fcf2(0x1c7)][_0x36fcf2(0x1a2)][_0x36fcf2(0x1e7)](_0x4b8941,{'runId':_0x287208,'requestId':_0x4b8941,'questions':_0x461425,'input':_0x2b39ce,'resolve':_0x1d492e=>_0x11bc59({'behavior':_0x36fcf2(0x1ea),'updatedInput':{..._0x2b39ce,'answers':_0x1d492e}}),'reject':(_0x3cc7cd=_0x36fcf2(0x1da))=>_0x11bc59(denyPermission(_0x3cc7cd)),'timer':_0x3a5d31}),this[_0x36fcf2(0x199)][_0x36fcf2(0x1c5)](_0x287208,{'itemId':boundedConversationItemId(_0x36fcf2(0x1c8),_0x4b8941),'kind':_0x36fcf2(0x198),'status':_0x36fcf2(0x1b2),'payload':{'requestId':_0x4b8941,'questions':_0x461425}});});}[_0x2de83f(0x192)](_0x323cf0,_0x55d658,_0x4a474e,_0x364731,_0x5a41ac,_0x5bec3e){const _0x2de8f6=_0x2de83f;return this[_0x2de8f6(0x199)][_0x2de8f6(0x1de)][_0x2de8f6(0x1e4)](_0x323cf0)[_0x2de8f6(0x192)](_0x55d658,_0x4a474e,_0x364731,_0x5a41ac,_0x5bec3e,(_0x850c81,_0x3a5772,_0x24d903)=>this[_0x2de8f6(0x199)][_0x2de8f6(0x18e)](_0x850c81,_0x2de8f6(0x194),{'messageId':_0x3a5772,'delivery':_0x24d903}));}[_0x2de83f(0x1c3)](_0x5e5d70,_0x69ec4b){const _0x5abecd=_0x2de83f,_0x4180fe=this[_0x5abecd(0x199)][_0x5abecd(0x1db)](),_0x4d941e=_0x4180fe[_0x5abecd(0x1c7)][_0x5abecd(0x19a)][_0x5abecd(0x1cf)](_0x5e5d70);if(_0x4d941e===undefined)return![];try{_0x4180fe[_0x5abecd(0x195)](_0x4d941e,{'decision':_0x69ec4b===_0x5abecd(0x1e5)?_0x5abecd(0x1cd):_0x5abecd(0x1e2)});}catch{}return _0x4180fe[_0x5abecd(0x1c7)][_0x5abecd(0x19a)][_0x5abecd(0x1e3)](_0x5e5d70),!![];}[_0x2de83f(0x1b1)](_0x4d15a4,_0x27cf6a){const _0x23d396=_0x2de83f,_0x6728c1=this[_0x23d396(0x199)][_0x23d396(0x1c1)]()[_0x23d396(0x1c7)][_0x23d396(0x19a)],_0x4fa471=_0x6728c1[_0x23d396(0x1cf)](_0x4d15a4);if(_0x4fa471===undefined)return![];return clearTimeout(_0x4fa471[_0x23d396(0x1d2)]),_0x6728c1[_0x23d396(0x1e3)](_0x4d15a4),_0x4fa471[_0x23d396(0x1bb)](_0x27cf6a),!![];}[_0x2de83f(0x1a9)](_0x3cfbb5,_0x1a6286){const _0x1916be=_0x2de83f,_0x9f99ca=this[_0x1916be(0x199)][_0x1916be(0x1c1)]()[_0x1916be(0x1c7)][_0x1916be(0x1df)][_0x1916be(0x1cf)](_0x3cfbb5);if(_0x9f99ca===undefined)return![];if(_0x1a6286===_0x1916be(0x1c6))_0x9f99ca[_0x1916be(0x1d8)][_0x1916be(0x1d4)]();else void _0x9f99ca[_0x1916be(0x1d8)][_0x1916be(0x1a8)]()[_0x1916be(0x1d6)](()=>{const _0x2f4fdf=_0x1916be,_0x3c31a6=this[_0x2f4fdf(0x199)][_0x2f4fdf(0x1d0)][_0x2f4fdf(0x1a6)](_0x3cfbb5);if(_0x3c31a6!==undefined&&!isTerminalRunStatus(_0x3c31a6[_0x2f4fdf(0x19d)]))this[_0x2f4fdf(0x199)][_0x2f4fdf(0x18e)](_0x3cfbb5,_0x2f4fdf(0x1b8),{'status':_0x2f4fdf(0x1ab)},_0x2f4fdf(0x1ab));},()=>{const _0x248b2f=_0x1916be,_0x3395ec=this[_0x248b2f(0x199)][_0x248b2f(0x1d0)][_0x248b2f(0x1a6)](_0x3cfbb5);if(_0x3395ec!==undefined&&!isTerminalRunStatus(_0x3395ec[_0x248b2f(0x19d)]))this[_0x248b2f(0x199)][_0x248b2f(0x18e)](_0x3cfbb5,_0x248b2f(0x1af),{'code':_0x248b2f(0x1a3)},_0x248b2f(0x19e));});return!![];}async[_0x2de83f(0x1d9)](_0xc6ab24,_0x2d14dd,_0x14cd7f,_0x233731,_0x53a8af){const _0x15e88d=_0x2de83f,_0x37ed60=this[_0x15e88d(0x199)][_0x15e88d(0x1db)]();try{await _0x37ed60[_0x15e88d(0x1dc)](_0x2d14dd,_0x14cd7f);const _0x23d5fd=this[_0x15e88d(0x199)][_0x15e88d(0x1d0)][_0x15e88d(0x1a6)](_0xc6ab24);if(_0x23d5fd!==undefined&&!isTerminalRunStatus(_0x23d5fd[_0x15e88d(0x19d)]))this[_0x15e88d(0x199)][_0x15e88d(0x18e)](_0xc6ab24,_0x15e88d(0x1b8),{'status':_0x53a8af},_0x53a8af);}catch{const _0x5bf529=this[_0x15e88d(0x199)][_0x15e88d(0x1d0)][_0x15e88d(0x1a6)](_0xc6ab24);if(_0x5bf529!==undefined&&!isTerminalRunStatus(_0x5bf529[_0x15e88d(0x19d)]))this[_0x15e88d(0x199)][_0x15e88d(0x18e)](_0xc6ab24,_0x15e88d(0x1af),{'code':_0x15e88d(0x1ac)},_0x15e88d(0x19e));}finally{_0x37ed60[_0x15e88d(0x1c7)][_0x15e88d(0x1df)][_0x15e88d(0x1e3)](_0xc6ab24),_0x37ed60[_0x15e88d(0x1b5)](_0xc6ab24),this[_0x15e88d(0x199)][_0x15e88d(0x1ca)][_0x15e88d(0x1a5)][_0x15e88d(0x1e3)](_0xc6ab24);}}[_0x2de83f(0x1f2)](_0x4f3651,_0x10f187,_0x4b769c){const _0x52f87e=_0x2de83f;if(this[_0x52f87e(0x199)][_0x52f87e(0x1de)][_0x52f87e(0x1f2)](_0x4f3651,_0x10f187,_0x4b769c))return;if(this[_0x52f87e(0x199)][_0x52f87e(0x1db)]()[_0x52f87e(0x1c7)][_0x52f87e(0x1a2)][_0x52f87e(0x1eb)](_0x10f187)){this[_0x52f87e(0x1c2)](_0x4f3651,_0x10f187,_0x4b769c);return;}const _0x506371=this[_0x52f87e(0x199)][_0x52f87e(0x1c1)]()[_0x52f87e(0x1c7)][_0x52f87e(0x1a2)],_0x5bdae0=_0x506371[_0x52f87e(0x1cf)](_0x10f187);if(_0x5bdae0===undefined||_0x5bdae0[_0x52f87e(0x191)]!==_0x4f3651)throw new Error(_0x52f87e(0x1b0));const _0x11c5d6={};for(const _0x24de52 of _0x5bdae0[_0x52f87e(0x1ee)]){const _0x5bc661=this[_0x52f87e(0x1dd)](_0x4b769c[_0x24de52['id']],_0x24de52[_0x52f87e(0x1c4)],_0x8bc9a4=>_0x24de52[_0x52f87e(0x199)][_0x52f87e(0x1cb)](_0x26e7da=>_0x26e7da[_0x52f87e(0x1c9)]===_0x8bc9a4));if(!_0x24de52[_0x52f87e(0x1b4)]&&_0x5bc661[_0x52f87e(0x19f)]!==-0x6b6*-0x3+0x1c63+-0x1cc*0x1b)throw new Error(_0x52f87e(0x1ad));_0x11c5d6[_0x24de52[_0x52f87e(0x1f3)]]=_0x5bc661[_0x52f87e(0x1e1)](',\x20');}clearTimeout(_0x5bdae0[_0x52f87e(0x1d2)]),_0x506371[_0x52f87e(0x1e3)](_0x10f187),_0x5bdae0[_0x52f87e(0x1bb)](_0x11c5d6),this[_0x52f87e(0x199)][_0x52f87e(0x1c5)](_0x4f3651,{'itemId':boundedConversationItemId(_0x52f87e(0x1c8),_0x10f187),'kind':_0x52f87e(0x198),'status':_0x52f87e(0x190),'payload':{'requestId':_0x10f187,'questions':_0x5bdae0[_0x52f87e(0x1ee)]},'merge':!![]});}[_0x2de83f(0x1d1)](_0x439e07){const _0x3c5c55=_0x2de83f,_0x27fda5=this[_0x3c5c55(0x199)][_0x3c5c55(0x1d0)][_0x3c5c55(0x1a6)](_0x439e07);if(_0x27fda5===undefined)return![];if(_0x27fda5[_0x3c5c55(0x19d)]===_0x3c5c55(0x1b3)){const _0x136daa=this[_0x3c5c55(0x199)][_0x3c5c55(0x1ca)][_0x3c5c55(0x1c0)][_0x3c5c55(0x1eb)](_0x439e07)?_0x3c5c55(0x1ab):_0x3c5c55(0x1e0);this[_0x3c5c55(0x199)][_0x3c5c55(0x18e)](_0x439e07,_0x3c5c55(0x1b8),{'status':_0x136daa},_0x136daa);}else{if(!isTerminalRunStatus(_0x27fda5[_0x3c5c55(0x19d)]))return![];}return this[_0x3c5c55(0x199)][_0x3c5c55(0x1db)]()[_0x3c5c55(0x1c7)][_0x3c5c55(0x1df)][_0x3c5c55(0x1e3)](_0x439e07),this[_0x3c5c55(0x199)][_0x3c5c55(0x1ca)][_0x3c5c55(0x1a5)][_0x3c5c55(0x1e3)](_0x439e07),!![];}[_0x2de83f(0x1c2)](_0x26d24c,_0x47f1d3,_0x3ecf95){const _0x1c5578=_0x2de83f,_0x4e4106=this[_0x1c5578(0x199)][_0x1c5578(0x1db)](),_0x33d691=_0x4e4106[_0x1c5578(0x1c7)][_0x1c5578(0x1a2)][_0x1c5578(0x1cf)](_0x47f1d3);if(_0x33d691===undefined||_0x33d691[_0x1c5578(0x191)]!==_0x26d24c||this[_0x1c5578(0x199)][_0x1c5578(0x1d0)][_0x1c5578(0x1a6)](_0x26d24c)===undefined)throw new Error(_0x1c5578(0x1b0));const _0x5e74f5={};for(const _0x51f2e3 of _0x33d691[_0x1c5578(0x1ee)])_0x5e74f5[_0x51f2e3['id']]={'answers':this[_0x1c5578(0x1dd)](_0x3ecf95[_0x51f2e3['id']],_0x51f2e3[_0x1c5578(0x1c4)],_0x4bcdec=>_0x51f2e3[_0x1c5578(0x199)][_0x1c5578(0x1aa)](_0x4bcdec))};_0x4e4106[_0x1c5578(0x195)](_0x33d691[_0x1c5578(0x1e8)],{'answers':_0x5e74f5}),_0x4e4106[_0x1c5578(0x1c7)][_0x1c5578(0x1a2)][_0x1c5578(0x1e3)](_0x47f1d3),this[_0x1c5578(0x199)][_0x1c5578(0x1c5)](_0x26d24c,{'itemId':boundedConversationItemId(_0x1c5578(0x196),_0x47f1d3),'kind':_0x1c5578(0x198),'status':_0x1c5578(0x190),'payload':{'requestId':_0x47f1d3,'questions':[]},'merge':!![]});}[_0x2de83f(0x1dd)](_0x1ef92c,_0x889e55,_0xd76184){const _0x23a9c5=_0x2de83f;if(!Array[_0x23a9c5(0x1bd)](_0x1ef92c)||_0x1ef92c[_0x23a9c5(0x19f)]===0x1*0x15bf+-0xd0f+-0x8b0||_0x1ef92c[_0x23a9c5(0x19f)]>-0x2505+-0x3*0xcc9+0x4c*0xfe)throw new Error(_0x23a9c5(0x1ad));return _0x1ef92c[_0x23a9c5(0x193)](_0x26fec8=>{const _0x46ffd2=_0x23a9c5;if(typeof _0x26fec8!==_0x46ffd2(0x1cc)||_0x26fec8[_0x46ffd2(0x19f)]===-0x18d*0x7+0x1565+-0xa8a||_0x26fec8[_0x46ffd2(0x19f)]>-0x21f9+-0x4*0x2f5+0x2fc1)throw new Error(_0x46ffd2(0x1ad));if(!_0x889e55&&!_0xd76184(_0x26fec8))throw new Error(_0x46ffd2(0x1ad));return _0x26fec8;});}}
|
|
1
|
+
import { denyPermission } from '../claude-agent-sdk.js';
|
|
2
|
+
import { boundedConversationItemId, claudeUserInputQuestions, isTerminalRunStatus } from '../runner/codex/conversation-parser.js';
|
|
3
|
+
export class RunnerInteractionService {
|
|
4
|
+
options;
|
|
5
|
+
constructor(options) {
|
|
6
|
+
this.options = options;
|
|
7
|
+
}
|
|
8
|
+
requestClaudeApproval(runId, toolName, toolInput) {
|
|
9
|
+
const approvalId = `claude:${crypto.randomUUID()}`;
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
const expiresAt = Date.now() + this.options.approvalTimeoutMs;
|
|
12
|
+
const settle = (decision) => resolve(decision === 'APPROVED'
|
|
13
|
+
? { behavior: 'allow', updatedInput: toolInput }
|
|
14
|
+
: denyPermission());
|
|
15
|
+
try {
|
|
16
|
+
this.options.runtime.createApproval({
|
|
17
|
+
runId,
|
|
18
|
+
approvalId,
|
|
19
|
+
payload: { toolName, input: toolInput },
|
|
20
|
+
expiresAt
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
resolve(denyPermission('APPROVAL_STORE_FAILED'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const expire = () => {
|
|
28
|
+
const approvals = this.options.claude().execution.approvals;
|
|
29
|
+
const active = approvals.get(approvalId);
|
|
30
|
+
if (active === undefined)
|
|
31
|
+
return;
|
|
32
|
+
try {
|
|
33
|
+
this.options.runtime.expireApproval(approvalId);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (error instanceof Error && error.message === 'APPROVAL_NOT_EXPIRED') {
|
|
37
|
+
const timer = setTimeout(expire, Math.max(1, expiresAt - Date.now()));
|
|
38
|
+
approvals.set(approvalId, { ...active, timer });
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
approvals.delete(approvalId);
|
|
43
|
+
this.options.emitRun(active.runId, 'approval.expired', { approvalId });
|
|
44
|
+
resolve(denyPermission('APPROVAL_EXPIRED'));
|
|
45
|
+
};
|
|
46
|
+
const timer = setTimeout(expire, this.options.approvalTimeoutMs);
|
|
47
|
+
this.options.claude().execution.approvals.set(approvalId, {
|
|
48
|
+
runId,
|
|
49
|
+
timer,
|
|
50
|
+
resolve: settle
|
|
51
|
+
});
|
|
52
|
+
this.options.publishApproval({
|
|
53
|
+
runId,
|
|
54
|
+
approvalId,
|
|
55
|
+
payload: { toolName, input: toolInput },
|
|
56
|
+
expiresAt
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
requestClaudeUserInput(runId, toolInput, toolUseId) {
|
|
61
|
+
const questions = claudeUserInputQuestions(toolInput);
|
|
62
|
+
if (questions.length === 0)
|
|
63
|
+
return Promise.resolve(denyPermission('USER_INPUT_INVALID'));
|
|
64
|
+
const requestId = `claude:${runId}:${toolUseId}`;
|
|
65
|
+
return new Promise((resolve) => {
|
|
66
|
+
const input = { ...toolInput };
|
|
67
|
+
const timer = setTimeout(() => {
|
|
68
|
+
const pending = this.options.claude().execution.userInputs.get(requestId);
|
|
69
|
+
if (pending === undefined)
|
|
70
|
+
return;
|
|
71
|
+
this.options.claude().execution.userInputs.delete(requestId);
|
|
72
|
+
pending.reject('USER_INPUT_EXPIRED');
|
|
73
|
+
this.options.emitItem(runId, {
|
|
74
|
+
itemId: boundedConversationItemId('claude-input', requestId),
|
|
75
|
+
kind: 'user_input_request',
|
|
76
|
+
status: 'FAILED',
|
|
77
|
+
payload: { requestId, questions },
|
|
78
|
+
merge: true
|
|
79
|
+
});
|
|
80
|
+
}, this.options.approvalTimeoutMs);
|
|
81
|
+
this.options.claude().execution.userInputs.set(requestId, {
|
|
82
|
+
runId,
|
|
83
|
+
requestId,
|
|
84
|
+
questions,
|
|
85
|
+
input,
|
|
86
|
+
resolve: (answers) => resolve({ behavior: 'allow', updatedInput: { ...input, answers } }),
|
|
87
|
+
reject: (message = 'USER_INPUT_EXPIRED') => resolve(denyPermission(message)),
|
|
88
|
+
timer
|
|
89
|
+
});
|
|
90
|
+
this.options.emitItem(runId, {
|
|
91
|
+
itemId: boundedConversationItemId('claude-input', requestId),
|
|
92
|
+
kind: 'user_input_request',
|
|
93
|
+
status: 'PENDING',
|
|
94
|
+
payload: { requestId, questions }
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
deliverChannel(runner, sessionId, messageId, senderId, token, content) {
|
|
99
|
+
return this.options.runners
|
|
100
|
+
.require(runner)
|
|
101
|
+
.deliverChannel(sessionId, messageId, senderId, token, content, (runId, deliveredMessageId, delivery) => this.options.emitRun(runId, 'channel.delivery', {
|
|
102
|
+
messageId: deliveredMessageId,
|
|
103
|
+
delivery
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
decideCodexApproval(approvalId, decision) {
|
|
107
|
+
const codex = this.options.codex();
|
|
108
|
+
const requestId = codex.execution.approvals.get(approvalId);
|
|
109
|
+
if (requestId === undefined)
|
|
110
|
+
return false;
|
|
111
|
+
try {
|
|
112
|
+
codex.respond(requestId, { decision: decision === 'APPROVED' ? 'accept' : 'decline' });
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// A disconnected App Server cannot safely receive a late approval.
|
|
116
|
+
}
|
|
117
|
+
codex.execution.approvals.delete(approvalId);
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
decideClaudeApproval(approvalId, decision) {
|
|
121
|
+
const approvals = this.options.claude().execution.approvals;
|
|
122
|
+
const approval = approvals.get(approvalId);
|
|
123
|
+
if (approval === undefined)
|
|
124
|
+
return false;
|
|
125
|
+
clearTimeout(approval.timer);
|
|
126
|
+
approvals.delete(approvalId);
|
|
127
|
+
approval.resolve(decision);
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
cancelClaudeRun(runId, intent) {
|
|
131
|
+
const claudeRun = this.options.claude().execution.runs.get(runId);
|
|
132
|
+
if (claudeRun === undefined)
|
|
133
|
+
return false;
|
|
134
|
+
if (intent === 'CANCEL')
|
|
135
|
+
claudeRun.handle.cancel();
|
|
136
|
+
else
|
|
137
|
+
void claudeRun.handle.interrupt().then(() => {
|
|
138
|
+
const run = this.options.runtime.getRun(runId);
|
|
139
|
+
if (run !== undefined && !isTerminalRunStatus(run.status))
|
|
140
|
+
this.options.emitRun(runId, 'run.completed', { status: 'INTERRUPTED' }, 'INTERRUPTED');
|
|
141
|
+
}, () => {
|
|
142
|
+
const run = this.options.runtime.getRun(runId);
|
|
143
|
+
if (run !== undefined && !isTerminalRunStatus(run.status))
|
|
144
|
+
this.options.emitRun(runId, 'run.failed', { code: 'CLAUDE_INTERRUPT_FAILED' }, 'FAILED');
|
|
145
|
+
});
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
async cancelCodexTurn(runId, threadId, turnId, cwd, terminalStatus) {
|
|
149
|
+
const codex = this.options.codex();
|
|
150
|
+
try {
|
|
151
|
+
await codex.interruptTurn(threadId, turnId);
|
|
152
|
+
const run = this.options.runtime.getRun(runId);
|
|
153
|
+
if (run !== undefined && !isTerminalRunStatus(run.status))
|
|
154
|
+
this.options.emitRun(runId, 'run.completed', { status: terminalStatus }, terminalStatus);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
const run = this.options.runtime.getRun(runId);
|
|
158
|
+
if (run !== undefined && !isTerminalRunStatus(run.status))
|
|
159
|
+
this.options.emitRun(runId, 'run.failed', { code: 'CODEX_INTERRUPT_FAILED' }, 'FAILED');
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
codex.execution.runs.delete(runId);
|
|
163
|
+
codex.releaseEnvironment(runId);
|
|
164
|
+
this.options.state.active.delete(runId);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
respondUserInput(runId, requestId, rawAnswers) {
|
|
168
|
+
if (this.options.runners.respondUserInput(runId, requestId, rawAnswers))
|
|
169
|
+
return;
|
|
170
|
+
if (this.options.codex().execution.userInputs.has(requestId)) {
|
|
171
|
+
this.respondCodexUserInput(runId, requestId, rawAnswers);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const userInputs = this.options.claude().execution.userInputs;
|
|
175
|
+
const pending = userInputs.get(requestId);
|
|
176
|
+
if (pending === undefined || pending.runId !== runId)
|
|
177
|
+
throw new Error('USER_INPUT_NOT_FOUND');
|
|
178
|
+
const answers = {};
|
|
179
|
+
for (const question of pending.questions) {
|
|
180
|
+
const normalized = this.answers(rawAnswers[question.id], question.allowOther, (value) => question.options.some((option) => option.value === value));
|
|
181
|
+
if (!question.multiSelect && normalized.length !== 1)
|
|
182
|
+
throw new Error('USER_INPUT_INVALID');
|
|
183
|
+
answers[question.prompt] = normalized.join(', ');
|
|
184
|
+
}
|
|
185
|
+
clearTimeout(pending.timer);
|
|
186
|
+
userInputs.delete(requestId);
|
|
187
|
+
pending.resolve(answers);
|
|
188
|
+
this.options.emitItem(runId, {
|
|
189
|
+
itemId: boundedConversationItemId('claude-input', requestId),
|
|
190
|
+
kind: 'user_input_request',
|
|
191
|
+
status: 'COMPLETED',
|
|
192
|
+
payload: { requestId, questions: pending.questions },
|
|
193
|
+
merge: true
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
completeCancelledRun(runId) {
|
|
197
|
+
const run = this.options.runtime.getRun(runId);
|
|
198
|
+
if (run === undefined)
|
|
199
|
+
return false;
|
|
200
|
+
if (run.status === 'CANCELLING') {
|
|
201
|
+
const status = this.options.state.interruptRequested.has(runId) ? 'INTERRUPTED' : 'CANCELLED';
|
|
202
|
+
this.options.emitRun(runId, 'run.completed', { status }, status);
|
|
203
|
+
}
|
|
204
|
+
else if (!isTerminalRunStatus(run.status))
|
|
205
|
+
return false;
|
|
206
|
+
this.options.codex().execution.runs.delete(runId);
|
|
207
|
+
this.options.state.active.delete(runId);
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
respondCodexUserInput(runId, requestId, rawAnswers) {
|
|
211
|
+
const codex = this.options.codex();
|
|
212
|
+
const pending = codex.execution.userInputs.get(requestId);
|
|
213
|
+
if (pending === undefined ||
|
|
214
|
+
pending.runId !== runId ||
|
|
215
|
+
this.options.runtime.getRun(runId) === undefined)
|
|
216
|
+
throw new Error('USER_INPUT_NOT_FOUND');
|
|
217
|
+
const answers = {};
|
|
218
|
+
for (const question of pending.questions)
|
|
219
|
+
answers[question.id] = {
|
|
220
|
+
answers: this.answers(rawAnswers[question.id], question.allowOther, (value) => question.options.includes(value))
|
|
221
|
+
};
|
|
222
|
+
codex.respond(pending.requestId, { answers });
|
|
223
|
+
codex.execution.userInputs.delete(requestId);
|
|
224
|
+
this.options.emitItem(runId, {
|
|
225
|
+
itemId: boundedConversationItemId('codex-input', requestId),
|
|
226
|
+
kind: 'user_input_request',
|
|
227
|
+
status: 'COMPLETED',
|
|
228
|
+
payload: { requestId, questions: [] },
|
|
229
|
+
merge: true
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
answers(raw, allowOther, supported) {
|
|
233
|
+
if (!Array.isArray(raw) || raw.length === 0 || raw.length > 8)
|
|
234
|
+
throw new Error('USER_INPUT_INVALID');
|
|
235
|
+
return raw.map((value) => {
|
|
236
|
+
if (typeof value !== 'string' || value.length === 0 || value.length > 500)
|
|
237
|
+
throw new Error('USER_INPUT_INVALID');
|
|
238
|
+
if (!allowOther && !supported(value))
|
|
239
|
+
throw new Error('USER_INPUT_INVALID');
|
|
240
|
+
return value;
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -1,2 +1,69 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { runnerDefaultConfigurationSchema } from '@myagentroam/protocol';
|
|
2
|
+
import { parseSecretEnvironment } from '../util/secret-environment.js';
|
|
3
|
+
export class RunnerService {
|
|
4
|
+
database;
|
|
5
|
+
capabilities;
|
|
6
|
+
runners;
|
|
7
|
+
usage;
|
|
8
|
+
constructor(database, capabilities, runners, usage) {
|
|
9
|
+
this.database = database;
|
|
10
|
+
this.capabilities = capabilities;
|
|
11
|
+
this.runners = runners;
|
|
12
|
+
this.usage = usage;
|
|
13
|
+
}
|
|
14
|
+
operations() {
|
|
15
|
+
return {
|
|
16
|
+
'runner.usage.status': () => this.usageStatuses(),
|
|
17
|
+
'runner.usage.read': (data) => this.readUsage(data),
|
|
18
|
+
'runner.profiles.list': (data) => this.listProfiles(data),
|
|
19
|
+
'runner.defaults.save': (data) => this.saveDefaults(data)
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
profiles() {
|
|
23
|
+
return this.runners.profiles(this.capabilities());
|
|
24
|
+
}
|
|
25
|
+
refreshProfiles(workspaceId, environment = {}) {
|
|
26
|
+
const workspace = workspaceId === undefined ? undefined : this.database().getWorkspace(workspaceId);
|
|
27
|
+
if (workspaceId !== undefined && workspace === undefined)
|
|
28
|
+
throw new Error('WORKSPACE_NOT_FOUND');
|
|
29
|
+
return this.runners.refreshProfiles(this.capabilities(), workspace, environment);
|
|
30
|
+
}
|
|
31
|
+
async usageStatuses() {
|
|
32
|
+
return {
|
|
33
|
+
statuses: await Promise.all(this.runners
|
|
34
|
+
.advertised()
|
|
35
|
+
.flatMap((runner) => runner.name === 'codex' || runner.name === 'claude-code'
|
|
36
|
+
? [this.usage.status(runner.name)]
|
|
37
|
+
: []))
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async readUsage(data) {
|
|
41
|
+
const input = data;
|
|
42
|
+
const runner = this.runners.product(input.runner);
|
|
43
|
+
if (runner === undefined || (runner.name !== 'codex' && runner.name !== 'claude-code'))
|
|
44
|
+
throw new Error('RUNNER_USAGE_INVALID');
|
|
45
|
+
return { usage: await this.usage.read(runner.name) };
|
|
46
|
+
}
|
|
47
|
+
async listProfiles(data) {
|
|
48
|
+
const input = data;
|
|
49
|
+
const marAgent = this.runners.optional('mar-agent');
|
|
50
|
+
if (marAgent !== undefined &&
|
|
51
|
+
'configureModels' in marAgent &&
|
|
52
|
+
typeof marAgent.configureModels === 'function')
|
|
53
|
+
marAgent.configureModels(input.marAgentModels);
|
|
54
|
+
const workspaceId = typeof input.workspaceId === 'string' && input.workspaceId.length > 0
|
|
55
|
+
? input.workspaceId
|
|
56
|
+
: undefined;
|
|
57
|
+
const environment = parseSecretEnvironment(input.secretEnvironment);
|
|
58
|
+
return {
|
|
59
|
+
profiles: await this.refreshProfiles(workspaceId, environment),
|
|
60
|
+
defaults: this.database().getRunnerDefaults()
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
saveDefaults(data) {
|
|
64
|
+
const parsed = runnerDefaultConfigurationSchema.safeParse(data);
|
|
65
|
+
if (!parsed.success)
|
|
66
|
+
throw new Error('RUNNER_DEFAULT_INVALID');
|
|
67
|
+
return { defaults: this.database().saveRunnerDefaults(parsed.data) };
|
|
68
|
+
}
|
|
69
|
+
}
|