@cjhyy/code-shell-capability-coding 0.9.6 → 0.9.7
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/codex/app-server-client.d.ts +1 -1
- package/dist/external-runtimes/codex/app-server-client.js +19 -5
- package/dist/external-runtimes/codex/model-discovery.d.ts +14 -0
- package/dist/external-runtimes/codex/model-discovery.js +76 -0
- package/dist/external-runtimes/index.d.ts +2 -0
- package/dist/external-runtimes/index.js +1 -0
- package/package.json +2 -2
|
@@ -61,6 +61,6 @@ export declare class CodexAppServerClient {
|
|
|
61
61
|
private write;
|
|
62
62
|
private failAll;
|
|
63
63
|
get isClosed(): boolean;
|
|
64
|
-
/**
|
|
64
|
+
/** Stop via stdin EOF, then SIGTERM and SIGKILL if the server does not exit. */
|
|
65
65
|
close(): Promise<void>;
|
|
66
66
|
}
|
|
@@ -219,12 +219,14 @@ export class CodexAppServerClient {
|
|
|
219
219
|
get isClosed() {
|
|
220
220
|
return this.closed;
|
|
221
221
|
}
|
|
222
|
-
/**
|
|
222
|
+
/** Stop via stdin EOF, then SIGTERM and SIGKILL if the server does not exit. */
|
|
223
223
|
async close() {
|
|
224
224
|
const child = this.child;
|
|
225
225
|
this.failAll("app-server client closed");
|
|
226
226
|
this.lines?.close();
|
|
227
|
-
|
|
227
|
+
// Failed spawns have no pid and never emit `exit`. A process already killed
|
|
228
|
+
// by a signal likewise has no numeric exitCode and will not emit it again.
|
|
229
|
+
if (!child || !child.pid || child.exitCode !== null || child.signalCode !== null)
|
|
228
230
|
return;
|
|
229
231
|
try {
|
|
230
232
|
child.stdin.end();
|
|
@@ -237,8 +239,20 @@ export class CodexAppServerClient {
|
|
|
237
239
|
return resolve();
|
|
238
240
|
child.once("exit", () => resolve());
|
|
239
241
|
});
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
let killTimer;
|
|
243
|
+
const terminateTimer = setTimeout(() => {
|
|
244
|
+
child.kill("SIGTERM");
|
|
245
|
+
// Cleanup must finish even when an unresponsive server ignores SIGTERM.
|
|
246
|
+
// Keep awaiting its actual exit so callers never leave an orphan behind.
|
|
247
|
+
killTimer = setTimeout(() => child.kill("SIGKILL"), 500);
|
|
248
|
+
}, 2_000);
|
|
249
|
+
try {
|
|
250
|
+
await exited;
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
clearTimeout(terminateTimer);
|
|
254
|
+
if (killTimer)
|
|
255
|
+
clearTimeout(killTimer);
|
|
256
|
+
}
|
|
243
257
|
}
|
|
244
258
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type AppServerClientOptions } from "./app-server-client.js";
|
|
2
|
+
export interface CodexDiscoveredModel {
|
|
3
|
+
model: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
isDefault: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Read the installed Codex CLI's available models without starting a thread or
|
|
9
|
+
* turn. The deadline covers initialization and every page together. Callers own
|
|
10
|
+
* caching and fallback policy; a valid empty catalog is distinct from failure.
|
|
11
|
+
*/
|
|
12
|
+
export declare function discoverCodexModels(options?: AppServerClientOptions & {
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
}): Promise<CodexDiscoveredModel[]>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { CodexAppServerClient } from "./app-server-client.js";
|
|
2
|
+
import { buildRuntimeSpawnEnv } from "../shared/spawn-env.js";
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 8_000;
|
|
4
|
+
const MAX_PAGES = 100;
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
function nonemptyString(value) {
|
|
9
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Read the installed Codex CLI's available models without starting a thread or
|
|
13
|
+
* turn. The deadline covers initialization and every page together. Callers own
|
|
14
|
+
* caching and fallback policy; a valid empty catalog is distinct from failure.
|
|
15
|
+
*/
|
|
16
|
+
export async function discoverCodexModels(options = {}) {
|
|
17
|
+
const { timeoutMs = DEFAULT_TIMEOUT_MS, ...clientOptions } = options;
|
|
18
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
19
|
+
throw new Error("Codex model discovery requires a positive timeout");
|
|
20
|
+
}
|
|
21
|
+
const deadline = performance.now() + timeoutMs;
|
|
22
|
+
const remainingMs = () => {
|
|
23
|
+
const remaining = deadline - performance.now();
|
|
24
|
+
if (remaining <= 0)
|
|
25
|
+
throw new Error("Codex model discovery timed out");
|
|
26
|
+
return Math.ceil(remaining);
|
|
27
|
+
};
|
|
28
|
+
const client = new CodexAppServerClient({
|
|
29
|
+
...clientOptions,
|
|
30
|
+
env: buildRuntimeSpawnEnv({ base: options.env }),
|
|
31
|
+
});
|
|
32
|
+
client.onNotification(() => { });
|
|
33
|
+
client.onServerRequest(() => undefined);
|
|
34
|
+
try {
|
|
35
|
+
client.start();
|
|
36
|
+
await client.request("initialize", { clientInfo: { name: "codeshell", title: "CodeShell", version: "1" } }, remainingMs());
|
|
37
|
+
client.notify("initialized");
|
|
38
|
+
const models = new Map();
|
|
39
|
+
const cursors = new Set();
|
|
40
|
+
let cursor;
|
|
41
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
42
|
+
const result = await client.request("model/list", { includeHidden: false, limit: 100, ...(cursor ? { cursor } : {}) }, remainingMs());
|
|
43
|
+
if (!isRecord(result) || !Array.isArray(result.data)) {
|
|
44
|
+
throw new Error("Invalid Codex model/list response");
|
|
45
|
+
}
|
|
46
|
+
for (const entry of result.data) {
|
|
47
|
+
if (!isRecord(entry) ||
|
|
48
|
+
!nonemptyString(entry.model) ||
|
|
49
|
+
!nonemptyString(entry.displayName) ||
|
|
50
|
+
(entry.isDefault !== undefined && typeof entry.isDefault !== "boolean") ||
|
|
51
|
+
(entry.hidden !== undefined && typeof entry.hidden !== "boolean")) {
|
|
52
|
+
throw new Error("Invalid Codex model/list entry");
|
|
53
|
+
}
|
|
54
|
+
if (entry.hidden === true || models.has(entry.model))
|
|
55
|
+
continue;
|
|
56
|
+
models.set(entry.model, {
|
|
57
|
+
model: entry.model,
|
|
58
|
+
displayName: entry.displayName,
|
|
59
|
+
isDefault: entry.isDefault === true,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (result.nextCursor === null || result.nextCursor === undefined) {
|
|
63
|
+
return [...models.values()];
|
|
64
|
+
}
|
|
65
|
+
if (!nonemptyString(result.nextCursor) || cursors.has(result.nextCursor)) {
|
|
66
|
+
throw new Error("Invalid Codex model/list pagination cursor");
|
|
67
|
+
}
|
|
68
|
+
cursor = result.nextCursor;
|
|
69
|
+
cursors.add(cursor);
|
|
70
|
+
}
|
|
71
|
+
throw new Error("Codex model/list exceeded the pagination limit");
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
await client.close();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -25,6 +25,8 @@ export type { ExternalRuntimeAttachment, ExternalRuntimeTurnInput } from "./turn
|
|
|
25
25
|
export { CodexEventTranslator } from "./codex/event-translator.js";
|
|
26
26
|
export { CodexAppServerClient } from "./codex/app-server-client.js";
|
|
27
27
|
export type { AppServerClientOptions } from "./codex/app-server-client.js";
|
|
28
|
+
export { discoverCodexModels } from "./codex/model-discovery.js";
|
|
29
|
+
export type { CodexDiscoveredModel } from "./codex/model-discovery.js";
|
|
28
30
|
export { CodexRuntime } from "./codex/runtime.js";
|
|
29
31
|
export type { CodexRuntimeOptions, CodexRuntimeHooks, CodexTurnHandle, NativeApprovalDecision, } from "./codex/runtime.js";
|
|
30
32
|
export { buildClaudeMcpConfig, claudeAllowedToolNames, claudeBridgeArgs, CLAUDE_MCP_SERVER_NAME, } from "./claude-code/mcp-config.js";
|
|
@@ -20,6 +20,7 @@ export { buildRuntimeSpawnEnv } from "./shared/spawn-env.js";
|
|
|
20
20
|
export { textWithAttachmentReferences } from "./turn-input.js";
|
|
21
21
|
export { CodexEventTranslator } from "./codex/event-translator.js";
|
|
22
22
|
export { CodexAppServerClient } from "./codex/app-server-client.js";
|
|
23
|
+
export { discoverCodexModels } from "./codex/model-discovery.js";
|
|
23
24
|
export { CodexRuntime } from "./codex/runtime.js";
|
|
24
25
|
export { buildClaudeMcpConfig, claudeAllowedToolNames, claudeBridgeArgs, CLAUDE_MCP_SERVER_NAME, } from "./claude-code/mcp-config.js";
|
|
25
26
|
export { writeClaudeMcpConfigFile } from "./claude-code/mcp-config.js";
|
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.7",
|
|
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.7"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=20.10"
|