@cjhyy/code-shell-capability-coding 0.9.29 → 0.9.30
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/external-runtimes/claude-code/runtime.d.ts +2 -3
- package/dist/external-runtimes/claude-code/runtime.js +27 -27
- package/dist/external-runtimes/codex/runtime.d.ts +1 -1
- package/dist/external-runtimes/codex/runtime.js +3 -3
- package/dist/external-runtimes/session-factory.d.ts +2 -2
- package/dist/external-runtimes/session-factory.js +24 -1
- package/package.json +2 -2
|
@@ -29,12 +29,11 @@ export declare class ClaudeCodeRuntime {
|
|
|
29
29
|
private readonly hooks;
|
|
30
30
|
readonly kind: "claude-code";
|
|
31
31
|
private readonly log;
|
|
32
|
-
private translator;
|
|
33
32
|
private child?;
|
|
34
33
|
private claudeSessionId?;
|
|
35
34
|
private closed;
|
|
36
35
|
private firstTurn;
|
|
37
|
-
private
|
|
36
|
+
private turnCount;
|
|
38
37
|
constructor(options: ClaudeRuntimeOptions, hooks?: ClaudeRuntimeHooks);
|
|
39
38
|
/** Claude session id, once the first turn has reported it. Resume key only. */
|
|
40
39
|
get runtimeSessionId(): string | undefined;
|
|
@@ -46,7 +45,7 @@ export declare class ClaudeCodeRuntime {
|
|
|
46
45
|
* positional prompt after it is swallowed as another config value (measured),
|
|
47
46
|
* and a prompt on the command line would also be visible in `ps`.
|
|
48
47
|
*/
|
|
49
|
-
send(input: ExternalRuntimeTurnInput): Promise<ClaudeTurnHandle>;
|
|
48
|
+
send(input: ExternalRuntimeTurnInput, onEvent?: (event: StreamEvent) => void): Promise<ClaudeTurnHandle>;
|
|
50
49
|
private onLine;
|
|
51
50
|
private emit;
|
|
52
51
|
/**
|
|
@@ -25,20 +25,15 @@ export class ClaudeCodeRuntime {
|
|
|
25
25
|
hooks;
|
|
26
26
|
kind = "claude-code";
|
|
27
27
|
log;
|
|
28
|
-
translator;
|
|
29
28
|
child;
|
|
30
29
|
claudeSessionId;
|
|
31
30
|
closed = false;
|
|
32
31
|
firstTurn = true;
|
|
33
|
-
|
|
32
|
+
turnCount = 0;
|
|
34
33
|
constructor(options, hooks = {}) {
|
|
35
34
|
this.options = options;
|
|
36
35
|
this.hooks = hooks;
|
|
37
36
|
this.log = options.log ?? (() => { });
|
|
38
|
-
this.translator = new ClaudeEventTranslator({
|
|
39
|
-
sessionId: options.businessSessionId,
|
|
40
|
-
codeshellServerName: options.serverName ?? CLAUDE_MCP_SERVER_NAME,
|
|
41
|
-
});
|
|
42
37
|
this.claudeSessionId = options.resumeRuntimeSessionId;
|
|
43
38
|
}
|
|
44
39
|
/** Claude session id, once the first turn has reported it. Resume key only. */
|
|
@@ -53,13 +48,18 @@ export class ClaudeCodeRuntime {
|
|
|
53
48
|
* positional prompt after it is swallowed as another config value (measured),
|
|
54
49
|
* and a prompt on the command line would also be visible in `ps`.
|
|
55
50
|
*/
|
|
56
|
-
async send(input) {
|
|
51
|
+
async send(input, onEvent) {
|
|
57
52
|
if (this.closed)
|
|
58
53
|
throw new Error("ClaudeCodeRuntime is closed");
|
|
59
54
|
if (this.child)
|
|
60
55
|
throw new Error("a turn is already running");
|
|
61
|
-
|
|
62
|
-
this.
|
|
56
|
+
let terminalSeen = false;
|
|
57
|
+
const turnNumber = ++this.turnCount;
|
|
58
|
+
const translator = new ClaudeEventTranslator({
|
|
59
|
+
sessionId: this.options.businessSessionId,
|
|
60
|
+
codeshellServerName: this.options.serverName ?? CLAUDE_MCP_SERVER_NAME,
|
|
61
|
+
});
|
|
62
|
+
translator.beginTurn();
|
|
63
63
|
const wiring = claudeBridgeArgs({
|
|
64
64
|
bridge: this.options.bridge,
|
|
65
65
|
exposedToolNames: this.options.exposedToolNames,
|
|
@@ -93,7 +93,13 @@ export class ClaudeCodeRuntime {
|
|
|
93
93
|
this.child = child;
|
|
94
94
|
child.stdout.setEncoding("utf8");
|
|
95
95
|
const lines = createInterface({ input: child.stdout, crlfDelay: Infinity });
|
|
96
|
-
lines.on("line", (line) =>
|
|
96
|
+
lines.on("line", (line) => {
|
|
97
|
+
this.onLine(line, translator, (event) => {
|
|
98
|
+
if (event.type === "turn_complete")
|
|
99
|
+
terminalSeen = true;
|
|
100
|
+
this.emit(event.type === "stream_request_start" ? { ...event, turnNumber } : event, onEvent);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
97
103
|
child.stderr.setEncoding("utf8");
|
|
98
104
|
child.stderr.on("data", (chunk) => {
|
|
99
105
|
const trimmed = chunk.trim();
|
|
@@ -116,11 +122,11 @@ export class ClaudeCodeRuntime {
|
|
|
116
122
|
// Clean up the config file that carried the bearer token.
|
|
117
123
|
wiring.cleanup();
|
|
118
124
|
this.child = undefined;
|
|
119
|
-
if (!
|
|
125
|
+
if (!terminalSeen) {
|
|
120
126
|
const detail = error?.message ??
|
|
121
127
|
`Claude Code exited without a terminal result (code ${code ?? "unknown"})`;
|
|
122
|
-
this.emit({ type: "error", error: detail });
|
|
123
|
-
this.emit({ type: "turn_complete", reason: "model_error" });
|
|
128
|
+
this.emit({ type: "error", error: detail }, onEvent);
|
|
129
|
+
this.emit({ type: "turn_complete", reason: "model_error" }, onEvent);
|
|
124
130
|
}
|
|
125
131
|
resolve();
|
|
126
132
|
};
|
|
@@ -132,7 +138,7 @@ export class ClaudeCodeRuntime {
|
|
|
132
138
|
});
|
|
133
139
|
return { done };
|
|
134
140
|
}
|
|
135
|
-
onLine(line) {
|
|
141
|
+
onLine(line, translator, emit) {
|
|
136
142
|
if (!line.trim())
|
|
137
143
|
return;
|
|
138
144
|
let parsed;
|
|
@@ -144,22 +150,19 @@ export class ClaudeCodeRuntime {
|
|
|
144
150
|
this.log("claude.unparsable_line", { bytes: line.length });
|
|
145
151
|
return;
|
|
146
152
|
}
|
|
147
|
-
for (const event of
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
this.
|
|
151
|
-
}
|
|
152
|
-
if (!this.claudeSessionId && this.translator.runtimeSessionId) {
|
|
153
|
-
this.claudeSessionId = this.translator.runtimeSessionId;
|
|
153
|
+
for (const event of translator.translate(parsed))
|
|
154
|
+
emit(event);
|
|
155
|
+
if (!this.claudeSessionId && translator.runtimeSessionId) {
|
|
156
|
+
this.claudeSessionId = translator.runtimeSessionId;
|
|
154
157
|
this.log("claude.session_started", {
|
|
155
158
|
businessSessionId: this.options.businessSessionId,
|
|
156
159
|
runtimeSessionIdPrefix: this.claudeSessionId.slice(0, 8),
|
|
157
160
|
});
|
|
158
161
|
}
|
|
159
162
|
}
|
|
160
|
-
emit(event) {
|
|
163
|
+
emit(event, onEvent) {
|
|
161
164
|
try {
|
|
162
|
-
this.hooks.onEvent?.(event);
|
|
165
|
+
(onEvent ?? this.hooks.onEvent)?.(event);
|
|
163
166
|
}
|
|
164
167
|
catch (error) {
|
|
165
168
|
this.log("claude.event_handler_failed", {
|
|
@@ -186,9 +189,6 @@ export class ClaudeCodeRuntime {
|
|
|
186
189
|
/** Start a fresh conversation on the next `send()`, discarding resume state. */
|
|
187
190
|
resetConversation() {
|
|
188
191
|
this.claudeSessionId = undefined;
|
|
189
|
-
this.
|
|
190
|
-
sessionId: this.options.businessSessionId,
|
|
191
|
-
codeshellServerName: this.options.serverName ?? CLAUDE_MCP_SERVER_NAME,
|
|
192
|
-
});
|
|
192
|
+
this.turnCount = 0;
|
|
193
193
|
}
|
|
194
194
|
}
|
|
@@ -101,7 +101,7 @@ export declare class CodexRuntime {
|
|
|
101
101
|
* tombstones are what keep a late `turn/started` from reactivating a session
|
|
102
102
|
* that already reported terminal.
|
|
103
103
|
*/
|
|
104
|
-
send(input: ExternalRuntimeTurnInput): Promise<CodexTurnHandle>;
|
|
104
|
+
send(input: ExternalRuntimeTurnInput, onEvent?: (event: StreamEvent) => void): Promise<CodexTurnHandle>;
|
|
105
105
|
/**
|
|
106
106
|
* Interrupt the active turn.
|
|
107
107
|
*
|
|
@@ -122,12 +122,12 @@ export class CodexRuntime {
|
|
|
122
122
|
* tombstones are what keep a late `turn/started` from reactivating a session
|
|
123
123
|
* that already reported terminal.
|
|
124
124
|
*/
|
|
125
|
-
async send(input) {
|
|
125
|
+
async send(input, onEvent) {
|
|
126
126
|
if (!this.threadId)
|
|
127
127
|
throw new Error("CodexRuntime.send() before start()");
|
|
128
128
|
let resolveDone;
|
|
129
129
|
const done = new Promise((resolve) => (resolveDone = resolve));
|
|
130
|
-
this.activeTurn = { resolve: resolveDone };
|
|
130
|
+
this.activeTurn = { resolve: resolveDone, onEvent };
|
|
131
131
|
let text = textWithAttachmentReferences(input);
|
|
132
132
|
if (this.firstTurn && !this.resumed && this.options.initialContext) {
|
|
133
133
|
text = `${this.options.initialContext}\n\n<current_user_request>\n${text}\n</current_user_request>`;
|
|
@@ -201,7 +201,7 @@ export class CodexRuntime {
|
|
|
201
201
|
}
|
|
202
202
|
emitEvent(event) {
|
|
203
203
|
try {
|
|
204
|
-
this.hooks.onEvent?.(event);
|
|
204
|
+
(this.activeTurn?.onEvent ?? this.hooks.onEvent)?.(event);
|
|
205
205
|
}
|
|
206
206
|
catch (error) {
|
|
207
207
|
this.log("runtime.event_handler_failed", {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* Teardown reverses it, and unregisters before disposing the host so a late
|
|
20
20
|
* request finds nothing rather than a disposed host (§13.4).
|
|
21
21
|
*/
|
|
22
|
-
import type { PermissionRule, ToolDefinition } from "@cjhyy/code-shell-core/extension";
|
|
22
|
+
import type { PermissionRule, StreamEvent, ToolDefinition } from "@cjhyy/code-shell-core/extension";
|
|
23
23
|
import { createSessionToolHost, type ExternalToolExposurePolicy, type ToolVisibilityInputs } from "@cjhyy/code-shell-core/extension";
|
|
24
24
|
import { type CodexRuntimeHooks, type CodexRuntimeOptions } from "./codex/runtime.js";
|
|
25
25
|
import { type ClaudeRuntimeHooks } from "./claude-code/runtime.js";
|
|
@@ -83,7 +83,7 @@ export interface ExternalRuntimeSession {
|
|
|
83
83
|
readonly runtimeSessionId: string | undefined;
|
|
84
84
|
/** Tools actually exposed, after the allowlist and visibility guards. */
|
|
85
85
|
listTools(): readonly ToolDefinition[];
|
|
86
|
-
send(input: ExternalRuntimeTurnInput): Promise<{
|
|
86
|
+
send(input: ExternalRuntimeTurnInput, onEvent?: (event: StreamEvent) => void): Promise<{
|
|
87
87
|
done: Promise<void>;
|
|
88
88
|
}>;
|
|
89
89
|
interrupt(): Promise<void>;
|
|
@@ -28,6 +28,7 @@ export async function startExternalRuntimeSession(options) {
|
|
|
28
28
|
let host;
|
|
29
29
|
let runtime;
|
|
30
30
|
let closed = false;
|
|
31
|
+
let turnSink;
|
|
31
32
|
const close = async () => {
|
|
32
33
|
if (closed)
|
|
33
34
|
return;
|
|
@@ -53,6 +54,9 @@ export async function startExternalRuntimeSession(options) {
|
|
|
53
54
|
visibility: options.visibility,
|
|
54
55
|
...(options.approvalBackend ? { approvalBackend: options.approvalBackend } : {}),
|
|
55
56
|
...(options.contextOverrides ? { contextOverrides: options.contextOverrides } : {}),
|
|
57
|
+
// Outside a concrete provider call there is no run output owner. Never
|
|
58
|
+
// capture the lifetime callback and let it borrow a later active turn.
|
|
59
|
+
getStreamCallback: () => turnSink,
|
|
56
60
|
...(options.settingsScope ? { settingsScope: options.settingsScope } : {}),
|
|
57
61
|
});
|
|
58
62
|
// 3. Register before the runtime starts, so a tool call on the very first
|
|
@@ -116,7 +120,26 @@ export async function startExternalRuntimeSession(options) {
|
|
|
116
120
|
return activeRuntime.runtimeSessionId;
|
|
117
121
|
},
|
|
118
122
|
listTools: () => activeHost.listTools(),
|
|
119
|
-
send: (input) =>
|
|
123
|
+
send: async (input, onEvent) => {
|
|
124
|
+
if (turnSink)
|
|
125
|
+
throw new Error("An external runtime turn is already running");
|
|
126
|
+
const sink = onEvent ?? options.hooks?.onEvent;
|
|
127
|
+
turnSink = sink;
|
|
128
|
+
try {
|
|
129
|
+
const turn = await activeRuntime.send(input, sink);
|
|
130
|
+
return {
|
|
131
|
+
done: turn.done.finally(() => {
|
|
132
|
+
if (turnSink === sink)
|
|
133
|
+
turnSink = undefined;
|
|
134
|
+
}),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
if (turnSink === sink)
|
|
139
|
+
turnSink = undefined;
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
},
|
|
120
143
|
interrupt: () => activeRuntime.interrupt(),
|
|
121
144
|
close,
|
|
122
145
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cjhyy/code-shell-capability-coding",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.30",
|
|
4
4
|
"description": "Coding capability pack for the generic code-shell agent core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@cjhyy/code-shell-core": "0.9.
|
|
42
|
+
"@cjhyy/code-shell-core": "0.9.30"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=20.10"
|