@love-moon/ai-sdk 0.2.42 → 0.3.2
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/CHANGELOG.md +26 -0
- package/dist/built-in-backends.d.ts +51 -0
- package/dist/built-in-backends.js +78 -0
- package/dist/external-provider-registry.js +15 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/providers/claude-agent-sdk-session.js +1 -1
- package/dist/providers/codex-app-server-session.js +6 -5
- package/dist/providers/codex-exec-session.js +1 -1
- package/dist/providers/copilot-sdk-session.d.ts +8 -0
- package/dist/providers/copilot-sdk-session.js +49 -1
- package/dist/providers/kimi-cli-session.js +1 -1
- package/dist/providers/kimi-print-session.js +1 -1
- package/dist/providers/opencode-sdk-session.js +1 -1
- package/dist/resume/claude.d.ts +14 -0
- package/dist/resume/claude.js +138 -0
- package/dist/resume/codex.d.ts +14 -0
- package/dist/resume/codex.js +81 -0
- package/dist/resume/copilot.d.ts +14 -0
- package/dist/resume/copilot.js +375 -0
- package/dist/resume/index.d.ts +26 -0
- package/dist/resume/index.js +132 -0
- package/dist/resume/kimi.d.ts +14 -0
- package/dist/resume/kimi.js +89 -0
- package/dist/resume/opencode.d.ts +13 -0
- package/dist/resume/opencode.js +63 -0
- package/dist/resume/shared.d.ts +26 -0
- package/dist/resume/shared.js +115 -0
- package/dist/session-factory.d.ts +2 -1
- package/dist/session-factory.js +40 -62
- package/package.json +10 -4
- package/dist/resume.d.ts +0 -26
- package/dist/resume.js +0 -380
- package/dist/tui-session.d.ts +0 -153
- package/dist/tui-session.js +0 -941
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @love-moon/ai-sdk
|
|
2
|
+
|
|
3
|
+
## 0.3.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8e1d4a8: Prefer the bundled Copilot platform executable before the JS entrypoint so Node
|
|
8
|
+
20 installs do not fail with `ERR_UNKNOWN_BUILTIN_MODULE: node:sqlite`.
|
|
9
|
+
|
|
10
|
+
## 0.3.1
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 4e8d4e5: Include `CHANGELOG.md` in published npm tarballs.
|
|
15
|
+
|
|
16
|
+
The `files` array in each package's `package.json` previously only
|
|
17
|
+
listed the build output (`bin`/`src` for the CLI, `dist` for the
|
|
18
|
+
modules). npm's `files` whitelist replaces the default include set,
|
|
19
|
+
and CHANGELOG is not one of the auto-included files (only
|
|
20
|
+
`package.json`, `README*`, `LICENSE*`, and `main` are unconditional).
|
|
21
|
+
|
|
22
|
+
As a result, every release through 0.3.0 published tarballs with no
|
|
23
|
+
CHANGELOG, so a consumer running `npm install` or unpacking the brew
|
|
24
|
+
artifact had no way to see what changed in the version they just
|
|
25
|
+
installed. The repo `cli/CHANGELOG.md` and the GitHub Release body
|
|
26
|
+
remain the canonical source until 0.3.1 ships with this fix.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export function listBuiltInBackends(): string[];
|
|
2
|
+
export function normalizeBuiltInBackend(backend: any): any;
|
|
3
|
+
export function isBuiltInBackend(backend: any): boolean;
|
|
4
|
+
export function getBuiltInBackendEntry(backend: any): BuiltInBackendEntry | null;
|
|
5
|
+
/**
|
|
6
|
+
* Canonical registry of built-in AI SDK backends.
|
|
7
|
+
*
|
|
8
|
+
* This is the single source of truth for:
|
|
9
|
+
* - backend canonical name (e.g. "codex", "claude")
|
|
10
|
+
* - accepted aliases (e.g. "code" → "codex", "kimi-cli" → "kimi")
|
|
11
|
+
* - session variants (default + structured-output variant, if any)
|
|
12
|
+
*
|
|
13
|
+
* Provider surfaces that need to know about built-in backends (session
|
|
14
|
+
* factory, resume dispatcher, etc.) import from here so that adding a new
|
|
15
|
+
* built-in backend is a one-line change in this file, plus the provider's own
|
|
16
|
+
* implementation module.
|
|
17
|
+
*/
|
|
18
|
+
export const CODEX_APP_SERVER_VARIANT: "codex-app-server";
|
|
19
|
+
export const CODEX_EXEC_VARIANT: "codex-exec";
|
|
20
|
+
export const CLAUDE_AGENT_SDK_VARIANT: "claude-agent-sdk";
|
|
21
|
+
export const COPILOT_SDK_VARIANT: "copilot-sdk";
|
|
22
|
+
export const KIMI_CLI_WIRE_VARIANT: "kimi-cli-wire";
|
|
23
|
+
export const KIMI_CLI_PRINT_VARIANT: "kimi-cli-print";
|
|
24
|
+
export const OPENCODE_SDK_VARIANT: "opencode-sdk";
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {Object} BuiltInBackendEntry
|
|
27
|
+
* @property {string} backend Canonical backend name.
|
|
28
|
+
* @property {string[]} aliases All accepted aliases (INCLUDING the canonical name).
|
|
29
|
+
* @property {string} defaultVariant Variant used when no structured-output preference is set.
|
|
30
|
+
* @property {string=} structuredVariant Optional variant used when structured output is requested.
|
|
31
|
+
*/
|
|
32
|
+
/** @type {BuiltInBackendEntry[]} */
|
|
33
|
+
export const BUILT_IN_BACKENDS: BuiltInBackendEntry[];
|
|
34
|
+
export type BuiltInBackendEntry = {
|
|
35
|
+
/**
|
|
36
|
+
* Canonical backend name.
|
|
37
|
+
*/
|
|
38
|
+
backend: string;
|
|
39
|
+
/**
|
|
40
|
+
* All accepted aliases (INCLUDING the canonical name).
|
|
41
|
+
*/
|
|
42
|
+
aliases: string[];
|
|
43
|
+
/**
|
|
44
|
+
* Variant used when no structured-output preference is set.
|
|
45
|
+
*/
|
|
46
|
+
defaultVariant: string;
|
|
47
|
+
/**
|
|
48
|
+
* Optional variant used when structured output is requested.
|
|
49
|
+
*/
|
|
50
|
+
structuredVariant?: string | undefined;
|
|
51
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical registry of built-in AI SDK backends.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth for:
|
|
5
|
+
* - backend canonical name (e.g. "codex", "claude")
|
|
6
|
+
* - accepted aliases (e.g. "code" → "codex", "kimi-cli" → "kimi")
|
|
7
|
+
* - session variants (default + structured-output variant, if any)
|
|
8
|
+
*
|
|
9
|
+
* Provider surfaces that need to know about built-in backends (session
|
|
10
|
+
* factory, resume dispatcher, etc.) import from here so that adding a new
|
|
11
|
+
* built-in backend is a one-line change in this file, plus the provider's own
|
|
12
|
+
* implementation module.
|
|
13
|
+
*/
|
|
14
|
+
export const CODEX_APP_SERVER_VARIANT = "codex-app-server";
|
|
15
|
+
export const CODEX_EXEC_VARIANT = "codex-exec";
|
|
16
|
+
export const CLAUDE_AGENT_SDK_VARIANT = "claude-agent-sdk";
|
|
17
|
+
export const COPILOT_SDK_VARIANT = "copilot-sdk";
|
|
18
|
+
export const KIMI_CLI_WIRE_VARIANT = "kimi-cli-wire";
|
|
19
|
+
export const KIMI_CLI_PRINT_VARIANT = "kimi-cli-print";
|
|
20
|
+
export const OPENCODE_SDK_VARIANT = "opencode-sdk";
|
|
21
|
+
/**
|
|
22
|
+
* @typedef {Object} BuiltInBackendEntry
|
|
23
|
+
* @property {string} backend Canonical backend name.
|
|
24
|
+
* @property {string[]} aliases All accepted aliases (INCLUDING the canonical name).
|
|
25
|
+
* @property {string} defaultVariant Variant used when no structured-output preference is set.
|
|
26
|
+
* @property {string=} structuredVariant Optional variant used when structured output is requested.
|
|
27
|
+
*/
|
|
28
|
+
/** @type {BuiltInBackendEntry[]} */
|
|
29
|
+
export const BUILT_IN_BACKENDS = [
|
|
30
|
+
{
|
|
31
|
+
backend: "codex",
|
|
32
|
+
aliases: ["codex", "code"],
|
|
33
|
+
defaultVariant: CODEX_APP_SERVER_VARIANT,
|
|
34
|
+
structuredVariant: CODEX_EXEC_VARIANT,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
backend: "claude",
|
|
38
|
+
aliases: ["claude", "claude-code"],
|
|
39
|
+
defaultVariant: CLAUDE_AGENT_SDK_VARIANT,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
backend: "copilot",
|
|
43
|
+
aliases: ["copilot"],
|
|
44
|
+
defaultVariant: COPILOT_SDK_VARIANT,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
backend: "kimi",
|
|
48
|
+
aliases: ["kimi", "kimi-cli", "kimi-code"],
|
|
49
|
+
defaultVariant: KIMI_CLI_WIRE_VARIANT,
|
|
50
|
+
structuredVariant: KIMI_CLI_PRINT_VARIANT,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
backend: "opencode",
|
|
54
|
+
aliases: ["opencode", "open-code", "open_code"],
|
|
55
|
+
defaultVariant: OPENCODE_SDK_VARIANT,
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
const ALIAS_TO_BACKEND = new Map();
|
|
59
|
+
for (const entry of BUILT_IN_BACKENDS) {
|
|
60
|
+
for (const alias of entry.aliases) {
|
|
61
|
+
ALIAS_TO_BACKEND.set(alias, entry.backend);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const BACKEND_SET = new Set(BUILT_IN_BACKENDS.map((entry) => entry.backend));
|
|
65
|
+
export function listBuiltInBackends() {
|
|
66
|
+
return BUILT_IN_BACKENDS.map((entry) => entry.backend);
|
|
67
|
+
}
|
|
68
|
+
export function normalizeBuiltInBackend(backend) {
|
|
69
|
+
const normalized = String(backend || "").trim().toLowerCase();
|
|
70
|
+
return ALIAS_TO_BACKEND.get(normalized) || normalized;
|
|
71
|
+
}
|
|
72
|
+
export function isBuiltInBackend(backend) {
|
|
73
|
+
return BACKEND_SET.has(normalizeBuiltInBackend(backend));
|
|
74
|
+
}
|
|
75
|
+
export function getBuiltInBackendEntry(backend) {
|
|
76
|
+
const canonical = normalizeBuiltInBackend(backend);
|
|
77
|
+
return BUILT_IN_BACKENDS.find((entry) => entry.backend === canonical) || null;
|
|
78
|
+
}
|
|
@@ -113,12 +113,26 @@ function validateDescriptor(descriptor, sourcePath) {
|
|
|
113
113
|
throw new Error(`External AI SDK provider "${backend}" from ${sourcePath} is missing provider.createSession().`);
|
|
114
114
|
}
|
|
115
115
|
const aliases = Array.isArray(descriptor.aliases) ? descriptor.aliases.map((item) => normalizeName(item)).filter(Boolean) : [];
|
|
116
|
+
const optionalFn = (fieldName) => {
|
|
117
|
+
const value = descriptor[fieldName];
|
|
118
|
+
if (value === undefined || value === null) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
if (typeof value !== "function") {
|
|
122
|
+
throw new Error(`External AI SDK provider "${backend}" from ${sourcePath} has provider.${fieldName} `
|
|
123
|
+
+ `but it is not a function (got ${typeof value}).`);
|
|
124
|
+
}
|
|
125
|
+
return value;
|
|
126
|
+
};
|
|
116
127
|
return {
|
|
117
128
|
backend,
|
|
118
129
|
variant,
|
|
119
130
|
aliases,
|
|
120
131
|
createSession: descriptor.createSession,
|
|
121
|
-
isSupported:
|
|
132
|
+
isSupported: optionalFn("isSupported"),
|
|
133
|
+
resolveResumeContext: optionalFn("resolveResumeContext"),
|
|
134
|
+
buildResumeArgs: optionalFn("buildResumeArgs"),
|
|
135
|
+
findSessionPath: optionalFn("findSessionPath"),
|
|
122
136
|
sourcePath,
|
|
123
137
|
};
|
|
124
138
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
+
export { BUILT_IN_BACKENDS } from "./built-in-backends.js";
|
|
1
2
|
export { createAiSession, RemoteAiSession } from "./client.js";
|
|
3
|
+
export { resolveResumeContext, buildResumeArgsForBackend, resumeProviderForBackend, findSessionPath, resolveSessionRunDirectory, inspectResumeTarget } from "./resume/index.js";
|
package/dist/index.js
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
1
|
export { createAiSession, RemoteAiSession } from "./client.js";
|
|
2
|
+
export { BUILT_IN_BACKENDS } from "./built-in-backends.js";
|
|
3
|
+
export { resolveResumeContext, buildResumeArgsForBackend, resumeProviderForBackend, findSessionPath, resolveSessionRunDirectory, inspectResumeTarget, } from "./resume/index.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
|
+
import { CLAUDE_AGENT_SDK_VARIANT as CLAUDE_PROVIDER_VARIANT } from "../built-in-backends.js";
|
|
2
3
|
import { emitLog, getBoundedEnvInt, loadEnvConfig, normalizeLogger, proxyToEnv, sanitizeForLog, } from "../shared.js";
|
|
3
4
|
const DEFAULT_TURN_DEADLINE_MS = 12 * 60 * 1000;
|
|
4
5
|
const MIN_TURN_DEADLINE_MS = 30 * 1000;
|
|
5
6
|
const MAX_TURN_DEADLINE_MS = 30 * 60 * 1000;
|
|
6
7
|
const DEFAULT_SETTING_SOURCES = ["user", "project", "local"];
|
|
7
|
-
const CLAUDE_PROVIDER_VARIANT = "claude-agent-sdk";
|
|
8
8
|
function waitForever() {
|
|
9
9
|
return new Promise(() => { });
|
|
10
10
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
|
+
import { CODEX_APP_SERVER_VARIANT } from "../built-in-backends.js";
|
|
2
3
|
import { CodexAppServerTransport } from "../transports/codex-app-server-transport.js";
|
|
3
4
|
import { emitLog, getBoundedEnvInt, loadEnvConfig, normalizeLogger, proxyToEnv, sanitizeForLog, } from "../shared.js";
|
|
4
5
|
const DEFAULT_TURN_DEADLINE_MS = 12 * 60 * 1000;
|
|
@@ -248,7 +249,7 @@ export class CodexAppServerSession extends EventEmitter {
|
|
|
248
249
|
getSnapshot() {
|
|
249
250
|
return {
|
|
250
251
|
backend: this.backend,
|
|
251
|
-
provider:
|
|
252
|
+
provider: CODEX_APP_SERVER_VARIANT,
|
|
252
253
|
cwd: this.cwd,
|
|
253
254
|
sessionId: this.sessionId || undefined,
|
|
254
255
|
sessionInfo: this.getSessionInfo(),
|
|
@@ -324,7 +325,7 @@ export class CodexAppServerSession extends EventEmitter {
|
|
|
324
325
|
}
|
|
325
326
|
markTurnStartedStatus() {
|
|
326
327
|
this.updateCurrentTurnStatus({
|
|
327
|
-
source:
|
|
328
|
+
source: CODEX_APP_SERVER_VARIANT,
|
|
328
329
|
reply_in_progress: true,
|
|
329
330
|
replyTo: this.getCurrentReplyTarget(),
|
|
330
331
|
phase: "turn_started",
|
|
@@ -444,7 +445,7 @@ export class CodexAppServerSession extends EventEmitter {
|
|
|
444
445
|
}
|
|
445
446
|
normalizeWorkingStatusPayload(payload) {
|
|
446
447
|
return {
|
|
447
|
-
source:
|
|
448
|
+
source: CODEX_APP_SERVER_VARIANT,
|
|
448
449
|
reply_in_progress: Boolean(payload?.reply_in_progress),
|
|
449
450
|
replyTo: payload?.replyTo || this.getCurrentReplyTarget(),
|
|
450
451
|
state: payload?.state,
|
|
@@ -469,7 +470,7 @@ export class CodexAppServerSession extends EventEmitter {
|
|
|
469
470
|
const payload = {
|
|
470
471
|
text,
|
|
471
472
|
preserveWhitespace: true,
|
|
472
|
-
source:
|
|
473
|
+
source: CODEX_APP_SERVER_VARIANT,
|
|
473
474
|
replyTo: this.getCurrentReplyTarget(),
|
|
474
475
|
sessionId: this.sessionId || undefined,
|
|
475
476
|
sessionFilePath: this.threadPath || undefined,
|
|
@@ -957,7 +958,7 @@ export class CodexAppServerSession extends EventEmitter {
|
|
|
957
958
|
events: [],
|
|
958
959
|
provider: this.backend,
|
|
959
960
|
metadata: {
|
|
960
|
-
source:
|
|
961
|
+
source: CODEX_APP_SERVER_VARIANT,
|
|
961
962
|
threadId: this.sessionId,
|
|
962
963
|
threadPath: this.threadPath || undefined,
|
|
963
964
|
nativeSessionId: this.nativeSessionId || undefined,
|
|
@@ -5,11 +5,11 @@ import { spawn } from "node:child_process";
|
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
6
6
|
import { EventEmitter } from "node:events";
|
|
7
7
|
import readline from "node:readline";
|
|
8
|
+
import { CODEX_EXEC_VARIANT as CODEX_EXEC_PROVIDER_VARIANT } from "../built-in-backends.js";
|
|
8
9
|
import { emitLog, getBoundedEnvInt, loadEnvConfig, normalizeLogger, parseCommandParts, proxyToEnv, sanitizeForLog, } from "../shared.js";
|
|
9
10
|
const DEFAULT_TURN_DEADLINE_MS = 12 * 60 * 1000;
|
|
10
11
|
const MIN_TURN_DEADLINE_MS = 30 * 1000;
|
|
11
12
|
const MAX_TURN_DEADLINE_MS = 30 * 60 * 1000;
|
|
12
|
-
const CODEX_EXEC_PROVIDER_VARIANT = "codex-exec";
|
|
13
13
|
const DEFAULT_CODEX_EXEC_COMMAND = "codex";
|
|
14
14
|
function createTurnError(message, extras = {}) {
|
|
15
15
|
const error = new Error(message);
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export function resolveBundledCopilotCliPath({ platform, arch, resolvePackage, resolvePackagePaths, existsSyncFn, }?: {
|
|
2
|
+
platform?: NodeJS.Platform | undefined;
|
|
3
|
+
arch?: NodeJS.Architecture | undefined;
|
|
4
|
+
resolvePackage?: ((packageName: any) => string) | undefined;
|
|
5
|
+
resolvePackagePaths?: ((packageName: any) => string[]) | undefined;
|
|
6
|
+
existsSyncFn?: typeof existsSync | undefined;
|
|
7
|
+
}): string | null;
|
|
1
8
|
export class CopilotSdkSession extends EventEmitter<[never]> {
|
|
2
9
|
constructor(backend: any, options?: {});
|
|
3
10
|
backend: string;
|
|
@@ -190,4 +197,5 @@ export class CopilotSdkSession extends EventEmitter<[never]> {
|
|
|
190
197
|
}>;
|
|
191
198
|
close(): Promise<void>;
|
|
192
199
|
}
|
|
200
|
+
import { existsSync } from "node:fs";
|
|
193
201
|
import { EventEmitter } from "node:events";
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
3
4
|
import path from "node:path";
|
|
5
|
+
import { COPILOT_SDK_VARIANT as COPILOT_PROVIDER_VARIANT } from "../built-in-backends.js";
|
|
4
6
|
import { emitLog, getBoundedEnvInt, loadEnvConfig, normalizeLogger, parseCommandParts, proxyToEnv, sanitizeForLog, withoutCopilotGithubTokenEnv, } from "../shared.js";
|
|
5
7
|
const DEFAULT_TURN_DEADLINE_MS = 12 * 60 * 1000;
|
|
6
8
|
const MIN_TURN_DEADLINE_MS = 30 * 1000;
|
|
7
9
|
const MAX_TURN_DEADLINE_MS = 30 * 60 * 1000;
|
|
8
10
|
const DEFAULT_CLOSE_TIMEOUT_MS = 5 * 1000;
|
|
9
11
|
const SDK_SEND_AND_WAIT_TIMEOUT_GRACE_MS = 5 * 1000;
|
|
10
|
-
const COPILOT_PROVIDER_VARIANT = "copilot-sdk";
|
|
11
12
|
const LEGACY_COPILOT_CLI_ARGS = new Set(["--allow-all-paths", "--allow-all-tools"]);
|
|
13
|
+
const moduleRequire = createRequire(import.meta.url);
|
|
12
14
|
function waitForever() {
|
|
13
15
|
return new Promise(() => { });
|
|
14
16
|
}
|
|
@@ -192,6 +194,44 @@ function unwrapEnvironmentCommand(command, args) {
|
|
|
192
194
|
function hasOwnEnumerableKeys(value) {
|
|
193
195
|
return value && typeof value === "object" && Object.keys(value).length > 0;
|
|
194
196
|
}
|
|
197
|
+
function resolveCopilotPlatformPackageName(platform = process.platform, arch = process.arch) {
|
|
198
|
+
if (!["darwin", "linux", "win32"].includes(platform)) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
if (!["arm64", "x64"].includes(arch)) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
return `@github/copilot-${platform}-${arch}`;
|
|
205
|
+
}
|
|
206
|
+
function resolvePackageFileFromSearchPaths(packageName, relativePath, resolvePackagePaths, existsSyncFn) {
|
|
207
|
+
const searchPaths = resolvePackagePaths(packageName) || [];
|
|
208
|
+
const packageParts = packageName.split("/");
|
|
209
|
+
for (const basePath of searchPaths) {
|
|
210
|
+
const candidate = path.join(basePath, ...packageParts, relativePath);
|
|
211
|
+
if (existsSyncFn(candidate)) {
|
|
212
|
+
return candidate;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
export function resolveBundledCopilotCliPath({ platform = process.platform, arch = process.arch, resolvePackage = (packageName) => moduleRequire.resolve(packageName), resolvePackagePaths = (packageName) => moduleRequire.resolve.paths(packageName) || [], existsSyncFn = existsSync, } = {}) {
|
|
218
|
+
const platformPackageName = resolveCopilotPlatformPackageName(platform, arch);
|
|
219
|
+
if (platformPackageName) {
|
|
220
|
+
try {
|
|
221
|
+
const platformExecutablePath = resolvePackage(platformPackageName);
|
|
222
|
+
if (platformExecutablePath && existsSyncFn(platformExecutablePath)) {
|
|
223
|
+
return platformExecutablePath;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
// Optional platform packages may be absent when optional dependencies are disabled.
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return resolvePackageFileFromSearchPaths("@github/copilot", "npm-loader.js", resolvePackagePaths, existsSyncFn);
|
|
231
|
+
}
|
|
232
|
+
function hasExplicitCopilotCliPathEnv(env) {
|
|
233
|
+
return typeof env?.COPILOT_CLI_PATH === "string" && env.COPILOT_CLI_PATH.trim();
|
|
234
|
+
}
|
|
195
235
|
function resolveCopilotCliLaunch(commandLine, env = process.env) {
|
|
196
236
|
const normalized = typeof commandLine === "string" ? commandLine.trim() : "";
|
|
197
237
|
if (!normalized) {
|
|
@@ -395,6 +435,14 @@ function buildCopilotClientOptions(options, cwd, env) {
|
|
|
395
435
|
clientOptions.env = hasExplicitGithubToken
|
|
396
436
|
? resolvedEnv
|
|
397
437
|
: withoutCopilotGithubTokenEnv(resolvedEnv);
|
|
438
|
+
if (clientOptions.cliPath === undefined &&
|
|
439
|
+
clientOptions.cliUrl === undefined &&
|
|
440
|
+
!hasExplicitCopilotCliPathEnv(clientOptions.env)) {
|
|
441
|
+
const bundledCliPath = resolveBundledCopilotCliPath();
|
|
442
|
+
if (bundledCliPath) {
|
|
443
|
+
clientOptions.cliPath = bundledCliPath;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
398
446
|
if (!hasExplicitGithubToken && clientOptions.useLoggedInUser === undefined) {
|
|
399
447
|
clientOptions.useLoggedInUser = true;
|
|
400
448
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
|
+
import { KIMI_CLI_WIRE_VARIANT as KIMI_PROVIDER_VARIANT } from "../built-in-backends.js";
|
|
3
4
|
import { KimiWireTransport } from "../transports/kimi-wire-transport.js";
|
|
4
5
|
import { emitLog, getBoundedEnvInt, loadEnvConfig, normalizeLogger, proxyToEnv, sanitizeForLog, } from "../shared.js";
|
|
5
6
|
const DEFAULT_TURN_DEADLINE_MS = 12 * 60 * 1000;
|
|
6
7
|
const MIN_TURN_DEADLINE_MS = 30 * 1000;
|
|
7
8
|
const MAX_TURN_DEADLINE_MS = 30 * 60 * 1000;
|
|
8
|
-
const KIMI_PROVIDER_VARIANT = "kimi-cli-wire";
|
|
9
9
|
const DEFAULT_STATUS_DEDUPE_MS = 120;
|
|
10
10
|
const DEFAULT_STATUS_THROTTLE_MS = 450;
|
|
11
11
|
const DEFAULT_REASONING_STATUS_THROTTLE_MS = 2500;
|
|
@@ -4,11 +4,11 @@ import { spawn } from "node:child_process";
|
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { EventEmitter } from "node:events";
|
|
6
6
|
import readline from "node:readline";
|
|
7
|
+
import { KIMI_CLI_PRINT_VARIANT as KIMI_PRINT_PROVIDER_VARIANT } from "../built-in-backends.js";
|
|
7
8
|
import { emitLog, getBoundedEnvInt, loadEnvConfig, normalizeLogger, parseCommandParts, proxyToEnv, sanitizeForLog, } from "../shared.js";
|
|
8
9
|
const DEFAULT_TURN_DEADLINE_MS = 12 * 60 * 1000;
|
|
9
10
|
const MIN_TURN_DEADLINE_MS = 30 * 1000;
|
|
10
11
|
const MAX_TURN_DEADLINE_MS = 30 * 60 * 1000;
|
|
11
|
-
const KIMI_PRINT_PROVIDER_VARIANT = "kimi-cli-print";
|
|
12
12
|
const DEFAULT_KIMI_COMMAND = "kimi";
|
|
13
13
|
function createTurnError(message, extras = {}) {
|
|
14
14
|
const error = new Error(message);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
|
+
import { OPENCODE_SDK_VARIANT as OPENCODE_PROVIDER_VARIANT } from "../built-in-backends.js";
|
|
2
3
|
import { OpencodeServerTransport } from "../transports/opencode-server-transport.js";
|
|
3
4
|
import { emitLog, getBoundedEnvInt, loadEnvConfig, normalizeLogger, proxyToEnv, sanitizeForLog, } from "../shared.js";
|
|
4
5
|
const DEFAULT_TURN_DEADLINE_MS = 12 * 60 * 1000;
|
|
5
6
|
const MIN_TURN_DEADLINE_MS = 30 * 1000;
|
|
6
7
|
const MAX_TURN_DEADLINE_MS = 30 * 60 * 1000;
|
|
7
|
-
const OPENCODE_PROVIDER_VARIANT = "opencode-sdk";
|
|
8
8
|
function waitForever() {
|
|
9
9
|
return new Promise(() => { });
|
|
10
10
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function buildCliArgs(sessionId: any): string[];
|
|
2
|
+
export function findSessionPath(sessionId: any, options?: {}): Promise<any>;
|
|
3
|
+
export function extractResumeCwd(sessionPath: any, sessionId: any): Promise<string | null>;
|
|
4
|
+
export function resolveResumeContext(sessionId: any, options?: {}): Promise<{
|
|
5
|
+
provider: any;
|
|
6
|
+
sessionId: any;
|
|
7
|
+
sessionPath: null;
|
|
8
|
+
cwd: any;
|
|
9
|
+
debugMetadata: {
|
|
10
|
+
cwdSource: any;
|
|
11
|
+
sessionPath: null;
|
|
12
|
+
};
|
|
13
|
+
}>;
|
|
14
|
+
export const BACKEND: "claude";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { promises as fsp } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import readline from "node:readline";
|
|
5
|
+
import { buildResumeContext, isExistingDirectory, normalizeSessionId, pathExists, resolveHomeDir, resolveSessionRunDirectory, } from "./shared.js";
|
|
6
|
+
export const BACKEND = "claude";
|
|
7
|
+
export function buildCliArgs(sessionId) {
|
|
8
|
+
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
9
|
+
if (!normalizedSessionId) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
return ["--resume", normalizedSessionId];
|
|
13
|
+
}
|
|
14
|
+
export async function findSessionPath(sessionId, options = {}) {
|
|
15
|
+
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
16
|
+
if (!normalizedSessionId) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const homeDir = resolveHomeDir(options);
|
|
20
|
+
const projectsDir = options.claudeProjectsDir || path.join(homeDir, ".claude", "projects");
|
|
21
|
+
const sessionEntries = await findClaudeSessionEntries(projectsDir, normalizedSessionId);
|
|
22
|
+
if (sessionEntries.length > 0) {
|
|
23
|
+
return sessionEntries[0]?.source || null;
|
|
24
|
+
}
|
|
25
|
+
const tasksDir = options.claudeTasksDir || path.join(homeDir, ".claude", "tasks");
|
|
26
|
+
const directTaskDir = path.join(tasksDir, normalizedSessionId);
|
|
27
|
+
if (await pathExists(directTaskDir, "directory")) {
|
|
28
|
+
return directTaskDir;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
export async function extractResumeCwd(sessionPath, sessionId) {
|
|
33
|
+
if (!sessionPath || !sessionPath.endsWith(".jsonl")) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const rl = readline.createInterface({
|
|
37
|
+
input: fs.createReadStream(sessionPath),
|
|
38
|
+
crlfDelay: Infinity,
|
|
39
|
+
});
|
|
40
|
+
for await (const line of rl) {
|
|
41
|
+
const trimmed = line.trim();
|
|
42
|
+
if (!trimmed) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
let entry;
|
|
46
|
+
try {
|
|
47
|
+
entry = JSON.parse(trimmed);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const idMatches = String(entry?.sessionId || "").trim() === sessionId;
|
|
53
|
+
const maybeCwd = entry?.cwd;
|
|
54
|
+
if (idMatches && typeof maybeCwd === "string" && maybeCwd.trim()) {
|
|
55
|
+
return maybeCwd.trim();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
export async function resolveResumeContext(sessionId, options = {}) {
|
|
61
|
+
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
62
|
+
if (!normalizedSessionId) {
|
|
63
|
+
throw new Error("--resume requires a session id");
|
|
64
|
+
}
|
|
65
|
+
const sessionPath = await findSessionPath(normalizedSessionId, options);
|
|
66
|
+
if (!sessionPath) {
|
|
67
|
+
throw new Error(`Invalid --resume session id for claude: ${normalizedSessionId}`);
|
|
68
|
+
}
|
|
69
|
+
const cwdFromSession = await extractResumeCwd(sessionPath, normalizedSessionId);
|
|
70
|
+
const fallbackCwd = await resolveSessionRunDirectory(sessionPath);
|
|
71
|
+
const cwd = cwdFromSession || fallbackCwd;
|
|
72
|
+
if (!cwd) {
|
|
73
|
+
throw new Error(`Could not resolve workspace for claude session ${normalizedSessionId}`);
|
|
74
|
+
}
|
|
75
|
+
if (!(await isExistingDirectory(cwd))) {
|
|
76
|
+
throw new Error(`Resume workspace path does not exist: ${cwd}`);
|
|
77
|
+
}
|
|
78
|
+
return buildResumeContext({
|
|
79
|
+
provider: "claude",
|
|
80
|
+
sessionId: normalizedSessionId,
|
|
81
|
+
sessionPath,
|
|
82
|
+
cwd,
|
|
83
|
+
cwdSource: cwdFromSession ? "session" : "session_path",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
async function findClaudeSessionEntries(projectsDir, sessionId) {
|
|
87
|
+
const entries = [];
|
|
88
|
+
let projectDirs = [];
|
|
89
|
+
try {
|
|
90
|
+
projectDirs = await fsp.readdir(projectsDir, { withFileTypes: true });
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return entries;
|
|
94
|
+
}
|
|
95
|
+
for (const projectDir of projectDirs) {
|
|
96
|
+
if (!projectDir.isDirectory()) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const projectPath = path.join(projectsDir, projectDir.name);
|
|
100
|
+
let files = [];
|
|
101
|
+
try {
|
|
102
|
+
files = await fsp.readdir(projectPath, { withFileTypes: true });
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
for (const file of files) {
|
|
108
|
+
if (!file.isFile()) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (!file.name.endsWith(".jsonl") || file.name.startsWith("agent-")) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const filePath = path.join(projectPath, file.name);
|
|
115
|
+
const rl = readline.createInterface({
|
|
116
|
+
input: fs.createReadStream(filePath),
|
|
117
|
+
crlfDelay: Infinity,
|
|
118
|
+
});
|
|
119
|
+
for await (const line of rl) {
|
|
120
|
+
const trimmed = line.trim();
|
|
121
|
+
if (!trimmed) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
let entry;
|
|
125
|
+
try {
|
|
126
|
+
entry = JSON.parse(trimmed);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (entry.sessionId === sessionId) {
|
|
132
|
+
entries.push({ ...entry, source: filePath });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return entries;
|
|
138
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function buildCliArgs(sessionId: any): string[];
|
|
2
|
+
export function findSessionPath(sessionId: any, options?: {}): Promise<string | null>;
|
|
3
|
+
export function extractResumeCwd(sessionPath: any): Promise<string | null>;
|
|
4
|
+
export function resolveResumeContext(sessionId: any, options?: {}): Promise<{
|
|
5
|
+
provider: any;
|
|
6
|
+
sessionId: any;
|
|
7
|
+
sessionPath: null;
|
|
8
|
+
cwd: any;
|
|
9
|
+
debugMetadata: {
|
|
10
|
+
cwdSource: any;
|
|
11
|
+
sessionPath: null;
|
|
12
|
+
};
|
|
13
|
+
}>;
|
|
14
|
+
export const BACKEND: "codex";
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { promises as fsp } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { buildResumeContext, isExistingDirectory, iterateJsonlEntries, normalizeSessionId, resolveHomeDir, resolveSessionRunDirectory, } from "./shared.js";
|
|
4
|
+
export const BACKEND = "codex";
|
|
5
|
+
export function buildCliArgs(sessionId) {
|
|
6
|
+
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
7
|
+
if (!normalizedSessionId) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
return ["resume", normalizedSessionId];
|
|
11
|
+
}
|
|
12
|
+
export async function findSessionPath(sessionId, options = {}) {
|
|
13
|
+
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
14
|
+
if (!normalizedSessionId) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const homeDir = resolveHomeDir(options);
|
|
18
|
+
const sessionsDir = options.codexSessionsDir || path.join(homeDir, ".codex", "sessions");
|
|
19
|
+
return findCodexSessionFile(sessionsDir, normalizedSessionId);
|
|
20
|
+
}
|
|
21
|
+
export async function extractResumeCwd(sessionPath) {
|
|
22
|
+
if (!sessionPath || !sessionPath.endsWith(".jsonl")) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
for await (const entry of iterateJsonlEntries(sessionPath)) {
|
|
26
|
+
const maybeCwd = entry?.type === "session_meta" ? entry?.payload?.cwd : null;
|
|
27
|
+
if (typeof maybeCwd === "string" && maybeCwd.trim()) {
|
|
28
|
+
return maybeCwd.trim();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
export async function resolveResumeContext(sessionId, options = {}) {
|
|
34
|
+
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
35
|
+
if (!normalizedSessionId) {
|
|
36
|
+
throw new Error("--resume requires a session id");
|
|
37
|
+
}
|
|
38
|
+
const sessionPath = await findSessionPath(normalizedSessionId, options);
|
|
39
|
+
if (!sessionPath) {
|
|
40
|
+
throw new Error(`Invalid --resume session id for codex: ${normalizedSessionId}`);
|
|
41
|
+
}
|
|
42
|
+
const cwdFromSession = await extractResumeCwd(sessionPath);
|
|
43
|
+
const fallbackCwd = await resolveSessionRunDirectory(sessionPath);
|
|
44
|
+
const cwd = cwdFromSession || fallbackCwd;
|
|
45
|
+
if (!cwd) {
|
|
46
|
+
throw new Error(`Could not resolve workspace for codex session ${normalizedSessionId}`);
|
|
47
|
+
}
|
|
48
|
+
if (!(await isExistingDirectory(cwd))) {
|
|
49
|
+
throw new Error(`Resume workspace path does not exist: ${cwd}`);
|
|
50
|
+
}
|
|
51
|
+
return buildResumeContext({
|
|
52
|
+
provider: "codex",
|
|
53
|
+
sessionId: normalizedSessionId,
|
|
54
|
+
sessionPath,
|
|
55
|
+
cwd,
|
|
56
|
+
cwdSource: cwdFromSession ? "session" : "session_path",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async function findCodexSessionFile(rootDir, sessionId) {
|
|
60
|
+
const queue = [rootDir];
|
|
61
|
+
while (queue.length) {
|
|
62
|
+
const current = queue.pop();
|
|
63
|
+
let entries = [];
|
|
64
|
+
try {
|
|
65
|
+
entries = await fsp.readdir(current, { withFileTypes: true });
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
for (const entry of entries) {
|
|
71
|
+
const fullPath = path.join(current, entry.name);
|
|
72
|
+
if (entry.isDirectory()) {
|
|
73
|
+
queue.push(fullPath);
|
|
74
|
+
}
|
|
75
|
+
else if (entry.isFile() && entry.name.includes(sessionId) && entry.name.endsWith(".jsonl")) {
|
|
76
|
+
return fullPath;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|