larkin 0.4.29 → 0.5.0
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 +11 -0
- package/README.md +5 -9
- package/artifacts/release/THIRD_PARTY_NOTICES.txt +751 -4425
- package/dist/app/agent-cli.mjs +14 -2
- package/dist/app/agent-config.mjs +26 -86
- package/dist/app/binary-entry.mjs +0 -20
- package/dist/app/cli.mjs +6 -22
- package/dist/app/internal-command.cjs +0 -2
- package/dist/app/internal-command.mjs +0 -2
- package/dist/app/runtime-model-directory.mjs +2 -16
- package/dist/app/runtime-process.mjs +0 -1
- package/dist/app/setup.mjs +52 -57
- package/dist/dashboard/dashboard-config-controller.mjs +43 -109
- package/dist/dashboard/dashboard-view-model.mjs +4 -7
- package/dist/dashboard/web/assets/dashboard.css +1 -1
- package/dist/dashboard/web/assets/dashboard.js +15 -15
- package/dist/feishu/host-shell.cjs +1 -2
- package/dist/feishu/host-shell.mjs +1 -2
- package/dist/platform/config.cjs +168 -133
- package/dist/platform/config.mjs +168 -133
- package/dist/runtime/pi-artifact-provenance.mjs +3 -3
- package/dist/runtime/pi-bash-timeout-extension.mjs +4 -5
- package/dist/runtime/pi-compaction-recovery.cjs +9 -11
- package/dist/runtime/pi-compaction-recovery.mjs +8 -10
- package/dist/runtime/pi-extension-api.mjs +1 -0
- package/dist/runtime/pi-model-catalog.cjs +7 -8
- package/dist/runtime/pi-model-catalog.mjs +7 -8
- package/dist/runtime/pi-subagent-injection.mjs +17 -4
- package/dist/runtime/runtime-adapters.mjs +26 -43
- package/dist/runtime/runtime-host.cjs +21 -43
- package/dist/runtime/runtime-host.mjs +22 -44
- package/dist/runtime/runtime-model-catalog.cjs +1 -1
- package/dist/runtime/runtime-model-catalog.mjs +1 -1
- package/dist/runtime/runtime-readiness.cjs +42 -99
- package/dist/runtime/runtime-readiness.mjs +40 -98
- package/dist/runtime/user-runtime.cjs +7 -24
- package/dist/runtime/user-runtime.mjs +7 -23
- package/dist/setup/bot-register.mjs +15 -123
- package/dist/setup/setup-agent-choice.mjs +48 -74
- package/dist/setup/setup-bind.mjs +51 -151
- package/dist/setup/setup-binding.mjs +6 -9
- package/package.json +3 -2
- package/dist/app/pi-auth-cli.mjs +0 -277
- package/dist/platform/process-boundary-trace.cjs +0 -108
- package/dist/runtime/builtin-pi-assets.cjs +0 -117
- package/dist/runtime/builtin-pi-assets.mjs +0 -105
- package/dist/runtime/pi-artifact-provenance.cjs +0 -147
- package/dist/runtime/pi-distribution-label.cjs +0 -6
- package/dist/runtime/pi-distribution-label.mjs +0 -3
- package/dist/runtime/pi-inline-extensions.mjs +0 -78
- package/dist/runtime/pi-official-auth.cjs +0 -594
- package/dist/runtime/pi-official-auth.mjs +0 -544
- package/dist/runtime/pi-profile-migration.cjs +0 -764
- package/dist/runtime/pi-profile-migration.mjs +0 -719
- package/dist/runtime/pi-provider-config.cjs +0 -354
- package/dist/runtime/pi-provider-config.mjs +0 -334
- package/dist/runtime/pi-provider-login.mjs +0 -240
|
@@ -38,25 +38,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.RuntimePrerequisiteError = void 0;
|
|
40
40
|
exports.safeProviderId = safeProviderId;
|
|
41
|
-
exports.isBuiltinPiDistribution = isBuiltinPiDistribution;
|
|
42
41
|
exports.configuredProviderId = configuredProviderId;
|
|
43
42
|
exports.parsePersistedAuthFailure = parsePersistedAuthFailure;
|
|
44
43
|
exports.authFailureAppliesTo = authFailureAppliesTo;
|
|
45
44
|
exports.readinessForPersistedAuthFailure = readinessForPersistedAuthFailure;
|
|
46
45
|
exports.classifyPiMissingCredentialRejection = classifyPiMissingCredentialRejection;
|
|
46
|
+
exports.runtimeInstallNextAction = runtimeInstallNextAction;
|
|
47
|
+
exports.runtimeLoginNextAction = runtimeLoginNextAction;
|
|
47
48
|
exports.providerAuthenticationFailureReadiness = providerAuthenticationFailureReadiness;
|
|
48
49
|
exports.missingProviderCredentialReadiness = missingProviderCredentialReadiness;
|
|
49
50
|
exports.resolveRuntimeExecutable = resolveRuntimeExecutable;
|
|
50
51
|
exports.classifyRuntimePrerequisite = classifyRuntimePrerequisite;
|
|
51
52
|
exports.probeNativeRuntimeReadiness = probeNativeRuntimeReadiness;
|
|
52
53
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
53
|
-
const node_os_1 = __importDefault(require("node:os"));
|
|
54
54
|
const node_path_1 = __importDefault(require("node:path"));
|
|
55
55
|
const node_child_process_1 = require("node:child_process");
|
|
56
|
-
const root_layout_js_1 = require("../platform/root-layout.cjs");
|
|
57
|
-
const builtin_pi_assets_js_1 = require("./builtin-pi-assets.cjs");
|
|
58
|
-
const pi_provider_config_js_1 = require("./pi-provider-config.cjs");
|
|
59
|
-
const process_boundary_trace_js_1 = require("../platform/process-boundary-trace.cjs");
|
|
60
56
|
function safeProviderId(value) {
|
|
61
57
|
const provider = typeof value === "string" ? value.trim() : "";
|
|
62
58
|
return /^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$/.test(provider) ? provider : null;
|
|
@@ -64,9 +60,6 @@ function safeProviderId(value) {
|
|
|
64
60
|
function safeProviderLabel(value) {
|
|
65
61
|
return safeProviderId(value);
|
|
66
62
|
}
|
|
67
|
-
function isBuiltinPiDistribution(value) {
|
|
68
|
-
return value === "builtin";
|
|
69
|
-
}
|
|
70
63
|
/** Model ids are `provider/model`; only the provider prefix is used for scope. */
|
|
71
64
|
function configuredProviderId(model) {
|
|
72
65
|
const value = typeof model === "string" ? model.trim() : "";
|
|
@@ -89,53 +82,20 @@ function parsePersistedAuthFailure(state) {
|
|
|
89
82
|
const provider = safeProviderId(failure.provider);
|
|
90
83
|
if (kind === "missing-provider" && !provider)
|
|
91
84
|
return null;
|
|
92
|
-
|
|
93
|
-
? failure.piDistribution : undefined;
|
|
94
|
-
return {
|
|
95
|
-
kind,
|
|
96
|
-
runtime,
|
|
97
|
-
...(piDistribution ? { piDistribution } : {}),
|
|
98
|
-
provider,
|
|
99
|
-
};
|
|
85
|
+
return { kind, runtime, provider };
|
|
100
86
|
}
|
|
101
87
|
const legacy = safeProviderId(record.authFailureProvider);
|
|
102
|
-
return legacy
|
|
103
|
-
? { kind: "missing-provider", runtime: "pi", piDistribution: "builtin", provider: legacy }
|
|
104
|
-
: null;
|
|
88
|
+
return legacy ? { kind: "missing-provider", runtime: "pi", provider: legacy } : null;
|
|
105
89
|
}
|
|
106
90
|
function currentAdapterId(current) {
|
|
107
|
-
return current.adapterId ??
|
|
91
|
+
return current.adapterId ?? current.runtime;
|
|
108
92
|
}
|
|
109
|
-
function currentIsBuiltinPi(current) {
|
|
110
|
-
return currentAdapterId(current) === "pi"
|
|
111
|
-
&& (isBuiltinPiDistribution(current.piDistribution) || current.runtime === "builtin-pi");
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Missing-provider and known-provider generic markers apply only to that provider.
|
|
115
|
-
* Generic without a provider is conservative fallback: it still binds runtime /
|
|
116
|
-
* builtin distribution, but cannot reject an A→B model switch because the
|
|
117
|
-
* upstream provider was genuinely unavailable.
|
|
118
|
-
*/
|
|
119
93
|
function authFailureAppliesTo(current, failure) {
|
|
120
|
-
if (failure.kind === "missing-provider") {
|
|
121
|
-
return currentIsBuiltinPi(current)
|
|
122
|
-
&& failure.runtime === "pi"
|
|
123
|
-
&& failure.piDistribution === "builtin"
|
|
124
|
-
&& Boolean(failure.provider)
|
|
125
|
-
&& configuredProviderId(current.model) === failure.provider;
|
|
126
|
-
}
|
|
127
94
|
if (failure.runtime !== currentAdapterId(current))
|
|
128
95
|
return false;
|
|
129
|
-
if (failure.runtime === "pi") {
|
|
130
|
-
const persistedBuiltin = failure.piDistribution === "builtin";
|
|
131
|
-
if (currentIsBuiltinPi(current) !== persistedBuiltin)
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
96
|
if (!failure.provider)
|
|
135
97
|
return true;
|
|
136
98
|
const currentProvider = configuredProviderId(current.model);
|
|
137
|
-
if (currentIsBuiltinPi(current))
|
|
138
|
-
return currentProvider === failure.provider;
|
|
139
99
|
return currentProvider ? currentProvider === failure.provider : true;
|
|
140
100
|
}
|
|
141
101
|
function readinessForPersistedAuthFailure(failure) {
|
|
@@ -154,6 +114,20 @@ function classifyPiMissingCredentialRejection(message) {
|
|
|
154
114
|
const provider = match ? safeProviderLabel(match[2]) : null;
|
|
155
115
|
return provider && match ? { provider, diagnostic: `${match[1]} ${provider}` } : null;
|
|
156
116
|
}
|
|
117
|
+
function runtimeInstallNextAction(runtime) {
|
|
118
|
+
if (runtime === "pi")
|
|
119
|
+
return "Install Pi and ensure `pi` is on PATH, or set LARKIN_PI_COMMAND.";
|
|
120
|
+
if (runtime === "codex")
|
|
121
|
+
return "Install Codex and ensure `codex` is on PATH, or set LARKIN_CODEX_COMMAND.";
|
|
122
|
+
return "Install Claude Code and ensure `claude` is on PATH, or set LARKIN_CLAUDE_COMMAND.";
|
|
123
|
+
}
|
|
124
|
+
function runtimeLoginNextAction(runtime) {
|
|
125
|
+
if (runtime === "pi")
|
|
126
|
+
return "Log in with the external `pi` CLI, then retry.";
|
|
127
|
+
if (runtime === "codex")
|
|
128
|
+
return "Run `codex login`, then retry.";
|
|
129
|
+
return "Run `claude login`, then retry.";
|
|
130
|
+
}
|
|
157
131
|
function providerAuthenticationFailureReadiness(runtime, provider) {
|
|
158
132
|
const label = safeProviderLabel(provider);
|
|
159
133
|
return {
|
|
@@ -162,23 +136,20 @@ function providerAuthenticationFailureReadiness(runtime, provider) {
|
|
|
162
136
|
reason: label
|
|
163
137
|
? `Provider ${label} API-key authentication failed during a Runtime turn.`
|
|
164
138
|
: "Configured provider API-key authentication failed during a Runtime turn.",
|
|
165
|
-
nextAction:
|
|
139
|
+
nextAction: runtimeLoginNextAction(runtime),
|
|
166
140
|
};
|
|
167
141
|
}
|
|
168
|
-
/** P0 分类;Pi nextAction 共用 UX preset 恢复文案,不写官方 provider ID。 */
|
|
169
142
|
function missingProviderCredentialReadiness(runtime, provider) {
|
|
170
143
|
const label = safeProviderLabel(provider);
|
|
171
144
|
return {
|
|
172
145
|
runtime,
|
|
173
146
|
state: "unauthenticated",
|
|
174
147
|
reason: label
|
|
175
|
-
? `Provider ${label} is
|
|
176
|
-
: "The configured provider is
|
|
177
|
-
nextAction: runtime === "pi"
|
|
178
|
-
?
|
|
179
|
-
:
|
|
180
|
-
? `Add the missing ${label} credential to this Agent's official store, then retry the Agent turn.`
|
|
181
|
-
: "Add the missing provider credential to this Agent's official store, then retry the Agent turn.",
|
|
148
|
+
? `Provider ${label} is not authenticated for this runtime.`
|
|
149
|
+
: "The configured provider is not authenticated for this runtime.",
|
|
150
|
+
nextAction: runtime === "pi" && label
|
|
151
|
+
? `Log in with the external \`pi\` CLI for provider ${label}, then retry.`
|
|
152
|
+
: runtimeLoginNextAction(runtime),
|
|
182
153
|
};
|
|
183
154
|
}
|
|
184
155
|
class RuntimePrerequisiteError extends Error {
|
|
@@ -211,27 +182,29 @@ function classifyRuntimePrerequisite(runtime, error, executable) {
|
|
|
211
182
|
const reason = (error instanceof Error ? error.message : String(error)).replace(/[\r\n]+/g, " ").slice(0, 500);
|
|
212
183
|
if (/ENOENT|not found|no such file|spawn .* failed/i.test(reason))
|
|
213
184
|
return {
|
|
214
|
-
runtime, state: "missing", ...(executable ? { executable } : {}),
|
|
215
|
-
|
|
185
|
+
runtime, state: "missing", ...(executable ? { executable } : {}),
|
|
186
|
+
reason: `${runtime} is not installed`,
|
|
187
|
+
nextAction: runtimeInstallNextAction(runtime),
|
|
216
188
|
};
|
|
217
189
|
if (/no authenticated available models|login|credential|unauthenticated|unauthorized|oauth/i.test(reason))
|
|
218
190
|
return {
|
|
219
191
|
runtime, state: "unauthenticated", ...(executable ? { executable } : {}), reason,
|
|
220
|
-
|
|
221
|
-
nextAction: runtime === "pi"
|
|
222
|
-
? "Run the official `pi` login flow, then retry."
|
|
223
|
-
: `Authenticate ${runtime}, then retry.`,
|
|
192
|
+
nextAction: runtimeLoginNextAction(runtime),
|
|
224
193
|
};
|
|
225
|
-
if (/protocol (?:version )?(?:mismatch|unsupported|incompatible)|unsupported (?:rpc|protocol|schema)|schema (?:mismatch|incompatible)|requires (?:a )?newer version/i.test(reason))
|
|
194
|
+
if (/protocol (?:version )?(?:mismatch|unsupported|incompatible)|unsupported (?:rpc|protocol|schema)|schema (?:mismatch|incompatible)|requires (?:a )?newer version/i.test(reason)) {
|
|
226
195
|
return {
|
|
227
196
|
runtime, state: "incompatible", ...(executable ? { executable } : {}), reason,
|
|
228
|
-
nextAction: runtime === "pi"
|
|
197
|
+
nextAction: runtime === "pi"
|
|
198
|
+
? "Upgrade local Pi to a version that supports the documented RPC protocol."
|
|
199
|
+
: `Upgrade ${runtime}, then retry.`,
|
|
229
200
|
};
|
|
230
|
-
|
|
201
|
+
}
|
|
202
|
+
if (/timeout|timed out|unexpected EOF|\bEOF\b|TLS|ECONNRESET|socket hang up|network|temporar(?:y|ily)|unavailable/i.test(reason)) {
|
|
231
203
|
return {
|
|
232
204
|
runtime, state: "unavailable", ...(executable ? { executable } : {}), reason,
|
|
233
205
|
nextAction: `Retry ${runtime}; Larkin will use its bounded Runtime recreate/backoff policy.`,
|
|
234
206
|
};
|
|
207
|
+
}
|
|
235
208
|
return {
|
|
236
209
|
runtime, state: "unavailable", ...(executable ? { executable } : {}), reason,
|
|
237
210
|
nextAction: `Retry ${runtime}; the failure is not proven to be a protocol incompatibility.`,
|
|
@@ -254,44 +227,15 @@ function executableVersion(executable, env, commandArgs = []) {
|
|
|
254
227
|
}
|
|
255
228
|
/** Resolve and handshake through each runtime's structured native control protocol. */
|
|
256
229
|
async function probeNativeRuntimeReadiness(options) {
|
|
257
|
-
|
|
258
|
-
const piDistribution = options.runtime === "pi" ? (0, builtin_pi_assets_js_1.piChildDistributionFromOverrides)(options.env) : "external";
|
|
259
|
-
if (options.runtime === "pi" && piDistribution !== "builtin") {
|
|
260
|
-
if (env.LARKIN_PI_DISTRIBUTION === "builtin")
|
|
261
|
-
delete env.LARKIN_PI_DISTRIBUTION;
|
|
262
|
-
env = (0, builtin_pi_assets_js_1.applyPiPackageDirForChild)(env, { distribution: "external" });
|
|
263
|
-
}
|
|
264
|
-
if (options.runtime === "pi" && piDistribution === "builtin") {
|
|
265
|
-
try {
|
|
266
|
-
if (!options.agentId || !env.LARKIN_CONFIG_DIR)
|
|
267
|
-
throw new Error("内置 Pi readiness 缺少 Agent/config identity");
|
|
268
|
-
(0, pi_provider_config_js_1.assertBuiltinPiAgentDirectory)((0, pi_provider_config_js_1.piAgentDirectory)(env.LARKIN_CONFIG_DIR, options.agentId));
|
|
269
|
-
return { runtime: "pi", state: "ready", executable: process.execPath, version: `official-pi ${pi_provider_config_js_1.BUNDLED_PI_VERSION} (bundled)` };
|
|
270
|
-
}
|
|
271
|
-
catch (error) {
|
|
272
|
-
(0, process_boundary_trace_js_1.traceProcessBoundary)(env, "readiness:builtin-pi-failure", { configDir: env.LARKIN_CONFIG_DIR, agentId: options.agentId, targetDir: options.agentId && env.LARKIN_CONFIG_DIR ? (0, pi_provider_config_js_1.piAgentDirectory)(env.LARKIN_CONFIG_DIR, options.agentId) : undefined, error });
|
|
273
|
-
return { runtime: "pi", state: "unauthenticated", reason: error instanceof Error ? error.message : String(error),
|
|
274
|
-
nextAction: (0, pi_provider_config_js_1.builtinPiProviderRecoveryNextAction)({ agentId: options.agentId }) };
|
|
275
|
-
}
|
|
276
|
-
}
|
|
230
|
+
const env = { ...process.env, ...options.env };
|
|
277
231
|
const command = selectedCommand(options);
|
|
278
232
|
const executable = resolveRuntimeExecutable(command, env);
|
|
279
|
-
if (!executable)
|
|
280
|
-
return {
|
|
281
|
-
runtime: options.runtime, state: "missing",
|
|
282
|
-
reason: `${command} executable was not found`,
|
|
283
|
-
nextAction: options.runtime === "pi"
|
|
284
|
-
? "Install Pi and ensure `pi` is on PATH, or set LARKIN_PI_COMMAND."
|
|
285
|
-
: `Install ${options.runtime} and ensure it is on PATH.`,
|
|
286
|
-
};
|
|
287
|
-
const piAgentId = options.agentId;
|
|
288
|
-
if (options.runtime === "pi" && !piAgentId) {
|
|
233
|
+
if (!executable) {
|
|
289
234
|
return {
|
|
290
|
-
runtime:
|
|
291
|
-
state: "
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
nextAction: "Retry setup or start so Larkin can probe the Agent-owned Pi provider directory.",
|
|
235
|
+
runtime: options.runtime,
|
|
236
|
+
state: "missing",
|
|
237
|
+
reason: `${options.runtime} is not installed`,
|
|
238
|
+
nextAction: runtimeInstallNextAction(options.runtime),
|
|
295
239
|
};
|
|
296
240
|
}
|
|
297
241
|
const version = executableVersion(executable, env, options.commandArgs);
|
|
@@ -303,7 +247,6 @@ async function probeNativeRuntimeReadiness(options) {
|
|
|
303
247
|
command: executable,
|
|
304
248
|
commandArgs: options.commandArgs,
|
|
305
249
|
env,
|
|
306
|
-
agentDir: (0, pi_provider_config_js_1.ownedPiCatalogAgentDir)((0, root_layout_js_1.resolveConfigDir)(env, node_os_1.default.homedir()), piAgentId),
|
|
307
250
|
});
|
|
308
251
|
}
|
|
309
252
|
else if (options.runtime === "codex") {
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import os from "node:os";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { spawnSync } from "node:child_process";
|
|
5
|
-
import { resolveConfigDir as resolveRootConfigDir } from "../platform/root-layout.mjs";
|
|
6
|
-
import { applyPiPackageDirForChild, piChildDistributionFromOverrides } from "./builtin-pi-assets.mjs";
|
|
7
|
-
import { assertBuiltinPiAgentDirectory, BUNDLED_PI_VERSION, builtinPiProviderRecoveryNextAction, ownedPiCatalogAgentDir, piAgentDirectory } from "./pi-provider-config.mjs";
|
|
8
|
-
import { traceProcessBoundary } from "../platform/process-boundary-trace.mjs";
|
|
9
4
|
export function safeProviderId(value) {
|
|
10
5
|
const provider = typeof value === "string" ? value.trim() : "";
|
|
11
6
|
return /^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$/.test(provider) ? provider : null;
|
|
@@ -13,9 +8,6 @@ export function safeProviderId(value) {
|
|
|
13
8
|
function safeProviderLabel(value) {
|
|
14
9
|
return safeProviderId(value);
|
|
15
10
|
}
|
|
16
|
-
export function isBuiltinPiDistribution(value) {
|
|
17
|
-
return value === "builtin";
|
|
18
|
-
}
|
|
19
11
|
/** Model ids are `provider/model`; only the provider prefix is used for scope. */
|
|
20
12
|
export function configuredProviderId(model) {
|
|
21
13
|
const value = typeof model === "string" ? model.trim() : "";
|
|
@@ -38,53 +30,20 @@ export function parsePersistedAuthFailure(state) {
|
|
|
38
30
|
const provider = safeProviderId(failure.provider);
|
|
39
31
|
if (kind === "missing-provider" && !provider)
|
|
40
32
|
return null;
|
|
41
|
-
|
|
42
|
-
? failure.piDistribution : undefined;
|
|
43
|
-
return {
|
|
44
|
-
kind,
|
|
45
|
-
runtime,
|
|
46
|
-
...(piDistribution ? { piDistribution } : {}),
|
|
47
|
-
provider,
|
|
48
|
-
};
|
|
33
|
+
return { kind, runtime, provider };
|
|
49
34
|
}
|
|
50
35
|
const legacy = safeProviderId(record.authFailureProvider);
|
|
51
|
-
return legacy
|
|
52
|
-
? { kind: "missing-provider", runtime: "pi", piDistribution: "builtin", provider: legacy }
|
|
53
|
-
: null;
|
|
36
|
+
return legacy ? { kind: "missing-provider", runtime: "pi", provider: legacy } : null;
|
|
54
37
|
}
|
|
55
38
|
function currentAdapterId(current) {
|
|
56
|
-
return current.adapterId ??
|
|
39
|
+
return current.adapterId ?? current.runtime;
|
|
57
40
|
}
|
|
58
|
-
function currentIsBuiltinPi(current) {
|
|
59
|
-
return currentAdapterId(current) === "pi"
|
|
60
|
-
&& (isBuiltinPiDistribution(current.piDistribution) || current.runtime === "builtin-pi");
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Missing-provider and known-provider generic markers apply only to that provider.
|
|
64
|
-
* Generic without a provider is conservative fallback: it still binds runtime /
|
|
65
|
-
* builtin distribution, but cannot reject an A→B model switch because the
|
|
66
|
-
* upstream provider was genuinely unavailable.
|
|
67
|
-
*/
|
|
68
41
|
export function authFailureAppliesTo(current, failure) {
|
|
69
|
-
if (failure.kind === "missing-provider") {
|
|
70
|
-
return currentIsBuiltinPi(current)
|
|
71
|
-
&& failure.runtime === "pi"
|
|
72
|
-
&& failure.piDistribution === "builtin"
|
|
73
|
-
&& Boolean(failure.provider)
|
|
74
|
-
&& configuredProviderId(current.model) === failure.provider;
|
|
75
|
-
}
|
|
76
42
|
if (failure.runtime !== currentAdapterId(current))
|
|
77
43
|
return false;
|
|
78
|
-
if (failure.runtime === "pi") {
|
|
79
|
-
const persistedBuiltin = failure.piDistribution === "builtin";
|
|
80
|
-
if (currentIsBuiltinPi(current) !== persistedBuiltin)
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
44
|
if (!failure.provider)
|
|
84
45
|
return true;
|
|
85
46
|
const currentProvider = configuredProviderId(current.model);
|
|
86
|
-
if (currentIsBuiltinPi(current))
|
|
87
|
-
return currentProvider === failure.provider;
|
|
88
47
|
return currentProvider ? currentProvider === failure.provider : true;
|
|
89
48
|
}
|
|
90
49
|
export function readinessForPersistedAuthFailure(failure) {
|
|
@@ -103,6 +62,20 @@ export function classifyPiMissingCredentialRejection(message) {
|
|
|
103
62
|
const provider = match ? safeProviderLabel(match[2]) : null;
|
|
104
63
|
return provider && match ? { provider, diagnostic: `${match[1]} ${provider}` } : null;
|
|
105
64
|
}
|
|
65
|
+
export function runtimeInstallNextAction(runtime) {
|
|
66
|
+
if (runtime === "pi")
|
|
67
|
+
return "Install Pi and ensure `pi` is on PATH, or set LARKIN_PI_COMMAND.";
|
|
68
|
+
if (runtime === "codex")
|
|
69
|
+
return "Install Codex and ensure `codex` is on PATH, or set LARKIN_CODEX_COMMAND.";
|
|
70
|
+
return "Install Claude Code and ensure `claude` is on PATH, or set LARKIN_CLAUDE_COMMAND.";
|
|
71
|
+
}
|
|
72
|
+
export function runtimeLoginNextAction(runtime) {
|
|
73
|
+
if (runtime === "pi")
|
|
74
|
+
return "Log in with the external `pi` CLI, then retry.";
|
|
75
|
+
if (runtime === "codex")
|
|
76
|
+
return "Run `codex login`, then retry.";
|
|
77
|
+
return "Run `claude login`, then retry.";
|
|
78
|
+
}
|
|
106
79
|
export function providerAuthenticationFailureReadiness(runtime, provider) {
|
|
107
80
|
const label = safeProviderLabel(provider);
|
|
108
81
|
return {
|
|
@@ -111,23 +84,20 @@ export function providerAuthenticationFailureReadiness(runtime, provider) {
|
|
|
111
84
|
reason: label
|
|
112
85
|
? `Provider ${label} API-key authentication failed during a Runtime turn.`
|
|
113
86
|
: "Configured provider API-key authentication failed during a Runtime turn.",
|
|
114
|
-
nextAction:
|
|
87
|
+
nextAction: runtimeLoginNextAction(runtime),
|
|
115
88
|
};
|
|
116
89
|
}
|
|
117
|
-
/** P0 分类;Pi nextAction 共用 UX preset 恢复文案,不写官方 provider ID。 */
|
|
118
90
|
export function missingProviderCredentialReadiness(runtime, provider) {
|
|
119
91
|
const label = safeProviderLabel(provider);
|
|
120
92
|
return {
|
|
121
93
|
runtime,
|
|
122
94
|
state: "unauthenticated",
|
|
123
95
|
reason: label
|
|
124
|
-
? `Provider ${label} is
|
|
125
|
-
: "The configured provider is
|
|
126
|
-
nextAction: runtime === "pi"
|
|
127
|
-
?
|
|
128
|
-
:
|
|
129
|
-
? `Add the missing ${label} credential to this Agent's official store, then retry the Agent turn.`
|
|
130
|
-
: "Add the missing provider credential to this Agent's official store, then retry the Agent turn.",
|
|
96
|
+
? `Provider ${label} is not authenticated for this runtime.`
|
|
97
|
+
: "The configured provider is not authenticated for this runtime.",
|
|
98
|
+
nextAction: runtime === "pi" && label
|
|
99
|
+
? `Log in with the external \`pi\` CLI for provider ${label}, then retry.`
|
|
100
|
+
: runtimeLoginNextAction(runtime),
|
|
131
101
|
};
|
|
132
102
|
}
|
|
133
103
|
export class RuntimePrerequisiteError extends Error {
|
|
@@ -159,27 +129,29 @@ export function classifyRuntimePrerequisite(runtime, error, executable) {
|
|
|
159
129
|
const reason = (error instanceof Error ? error.message : String(error)).replace(/[\r\n]+/g, " ").slice(0, 500);
|
|
160
130
|
if (/ENOENT|not found|no such file|spawn .* failed/i.test(reason))
|
|
161
131
|
return {
|
|
162
|
-
runtime, state: "missing", ...(executable ? { executable } : {}),
|
|
163
|
-
|
|
132
|
+
runtime, state: "missing", ...(executable ? { executable } : {}),
|
|
133
|
+
reason: `${runtime} is not installed`,
|
|
134
|
+
nextAction: runtimeInstallNextAction(runtime),
|
|
164
135
|
};
|
|
165
136
|
if (/no authenticated available models|login|credential|unauthenticated|unauthorized|oauth/i.test(reason))
|
|
166
137
|
return {
|
|
167
138
|
runtime, state: "unauthenticated", ...(executable ? { executable } : {}), reason,
|
|
168
|
-
|
|
169
|
-
nextAction: runtime === "pi"
|
|
170
|
-
? "Run the official `pi` login flow, then retry."
|
|
171
|
-
: `Authenticate ${runtime}, then retry.`,
|
|
139
|
+
nextAction: runtimeLoginNextAction(runtime),
|
|
172
140
|
};
|
|
173
|
-
if (/protocol (?:version )?(?:mismatch|unsupported|incompatible)|unsupported (?:rpc|protocol|schema)|schema (?:mismatch|incompatible)|requires (?:a )?newer version/i.test(reason))
|
|
141
|
+
if (/protocol (?:version )?(?:mismatch|unsupported|incompatible)|unsupported (?:rpc|protocol|schema)|schema (?:mismatch|incompatible)|requires (?:a )?newer version/i.test(reason)) {
|
|
174
142
|
return {
|
|
175
143
|
runtime, state: "incompatible", ...(executable ? { executable } : {}), reason,
|
|
176
|
-
nextAction: runtime === "pi"
|
|
144
|
+
nextAction: runtime === "pi"
|
|
145
|
+
? "Upgrade local Pi to a version that supports the documented RPC protocol."
|
|
146
|
+
: `Upgrade ${runtime}, then retry.`,
|
|
177
147
|
};
|
|
178
|
-
|
|
148
|
+
}
|
|
149
|
+
if (/timeout|timed out|unexpected EOF|\bEOF\b|TLS|ECONNRESET|socket hang up|network|temporar(?:y|ily)|unavailable/i.test(reason)) {
|
|
179
150
|
return {
|
|
180
151
|
runtime, state: "unavailable", ...(executable ? { executable } : {}), reason,
|
|
181
152
|
nextAction: `Retry ${runtime}; Larkin will use its bounded Runtime recreate/backoff policy.`,
|
|
182
153
|
};
|
|
154
|
+
}
|
|
183
155
|
return {
|
|
184
156
|
runtime, state: "unavailable", ...(executable ? { executable } : {}), reason,
|
|
185
157
|
nextAction: `Retry ${runtime}; the failure is not proven to be a protocol incompatibility.`,
|
|
@@ -202,44 +174,15 @@ function executableVersion(executable, env, commandArgs = []) {
|
|
|
202
174
|
}
|
|
203
175
|
/** Resolve and handshake through each runtime's structured native control protocol. */
|
|
204
176
|
export async function probeNativeRuntimeReadiness(options) {
|
|
205
|
-
|
|
206
|
-
const piDistribution = options.runtime === "pi" ? piChildDistributionFromOverrides(options.env) : "external";
|
|
207
|
-
if (options.runtime === "pi" && piDistribution !== "builtin") {
|
|
208
|
-
if (env.LARKIN_PI_DISTRIBUTION === "builtin")
|
|
209
|
-
delete env.LARKIN_PI_DISTRIBUTION;
|
|
210
|
-
env = applyPiPackageDirForChild(env, { distribution: "external" });
|
|
211
|
-
}
|
|
212
|
-
if (options.runtime === "pi" && piDistribution === "builtin") {
|
|
213
|
-
try {
|
|
214
|
-
if (!options.agentId || !env.LARKIN_CONFIG_DIR)
|
|
215
|
-
throw new Error("内置 Pi readiness 缺少 Agent/config identity");
|
|
216
|
-
assertBuiltinPiAgentDirectory(piAgentDirectory(env.LARKIN_CONFIG_DIR, options.agentId));
|
|
217
|
-
return { runtime: "pi", state: "ready", executable: process.execPath, version: `official-pi ${BUNDLED_PI_VERSION} (bundled)` };
|
|
218
|
-
}
|
|
219
|
-
catch (error) {
|
|
220
|
-
traceProcessBoundary(env, "readiness:builtin-pi-failure", { configDir: env.LARKIN_CONFIG_DIR, agentId: options.agentId, targetDir: options.agentId && env.LARKIN_CONFIG_DIR ? piAgentDirectory(env.LARKIN_CONFIG_DIR, options.agentId) : undefined, error });
|
|
221
|
-
return { runtime: "pi", state: "unauthenticated", reason: error instanceof Error ? error.message : String(error),
|
|
222
|
-
nextAction: builtinPiProviderRecoveryNextAction({ agentId: options.agentId }) };
|
|
223
|
-
}
|
|
224
|
-
}
|
|
177
|
+
const env = { ...process.env, ...options.env };
|
|
225
178
|
const command = selectedCommand(options);
|
|
226
179
|
const executable = resolveRuntimeExecutable(command, env);
|
|
227
|
-
if (!executable)
|
|
228
|
-
return {
|
|
229
|
-
runtime: options.runtime, state: "missing",
|
|
230
|
-
reason: `${command} executable was not found`,
|
|
231
|
-
nextAction: options.runtime === "pi"
|
|
232
|
-
? "Install Pi and ensure `pi` is on PATH, or set LARKIN_PI_COMMAND."
|
|
233
|
-
: `Install ${options.runtime} and ensure it is on PATH.`,
|
|
234
|
-
};
|
|
235
|
-
const piAgentId = options.agentId;
|
|
236
|
-
if (options.runtime === "pi" && !piAgentId) {
|
|
180
|
+
if (!executable) {
|
|
237
181
|
return {
|
|
238
|
-
runtime:
|
|
239
|
-
state: "
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
nextAction: "Retry setup or start so Larkin can probe the Agent-owned Pi provider directory.",
|
|
182
|
+
runtime: options.runtime,
|
|
183
|
+
state: "missing",
|
|
184
|
+
reason: `${options.runtime} is not installed`,
|
|
185
|
+
nextAction: runtimeInstallNextAction(options.runtime),
|
|
243
186
|
};
|
|
244
187
|
}
|
|
245
188
|
const version = executableVersion(executable, env, options.commandArgs);
|
|
@@ -251,7 +194,6 @@ export async function probeNativeRuntimeReadiness(options) {
|
|
|
251
194
|
command: executable,
|
|
252
195
|
commandArgs: options.commandArgs,
|
|
253
196
|
env,
|
|
254
|
-
agentDir: ownedPiCatalogAgentDir(resolveRootConfigDir(env, os.homedir()), piAgentId),
|
|
255
197
|
});
|
|
256
198
|
}
|
|
257
199
|
else if (options.runtime === "codex") {
|
|
@@ -7,45 +7,28 @@ exports.runtimeOptionOf = runtimeOptionOf;
|
|
|
7
7
|
exports.toUserRuntime = toUserRuntime;
|
|
8
8
|
exports.runtimeOptionTarget = runtimeOptionTarget;
|
|
9
9
|
exports.fromUserRuntime = fromUserRuntime;
|
|
10
|
-
exports.
|
|
11
|
-
exports.RUNTIME_OPTIONS = ["codex", "claude", "pi", "builtin-pi"];
|
|
10
|
+
exports.RUNTIME_OPTIONS = ["codex", "claude", "pi"];
|
|
12
11
|
exports.USER_RUNTIMES = exports.RUNTIME_OPTIONS;
|
|
13
12
|
exports.ADAPTER_RUNTIMES = ["pi", "codex", "claude"];
|
|
14
13
|
function isUserRuntime(value) {
|
|
15
|
-
return value === "pi" || value === "
|
|
14
|
+
return value === "pi" || value === "codex" || value === "claude";
|
|
16
15
|
}
|
|
17
16
|
function isAdapterRuntime(value) {
|
|
18
17
|
return value === "pi" || value === "codex" || value === "claude";
|
|
19
18
|
}
|
|
20
|
-
/**
|
|
19
|
+
/** Identity mapping with validation. */
|
|
21
20
|
function runtimeOptionOf(input) {
|
|
22
|
-
|
|
23
|
-
if (runtime === "codex" || runtime === "claude" || runtime === "builtin-pi")
|
|
24
|
-
return runtime;
|
|
25
|
-
if (runtime === "pi")
|
|
26
|
-
return piDistribution === "builtin" ? "builtin-pi" : "pi";
|
|
27
|
-
return runtime;
|
|
21
|
+
return input.runtime;
|
|
28
22
|
}
|
|
29
|
-
function toUserRuntime(runtime
|
|
30
|
-
return runtimeOptionOf({ runtime
|
|
23
|
+
function toUserRuntime(runtime) {
|
|
24
|
+
return runtimeOptionOf({ runtime });
|
|
31
25
|
}
|
|
32
|
-
/** Persist a user-facing
|
|
26
|
+
/** Persist a user-facing runtime as the stored adapter id. */
|
|
33
27
|
function runtimeOptionTarget(option) {
|
|
34
28
|
if (!isUserRuntime(option))
|
|
35
29
|
throw new Error(`未知 runtime:${option}`);
|
|
36
|
-
if (option === "builtin-pi")
|
|
37
|
-
return { runtime: "pi", piDistribution: "builtin" };
|
|
38
|
-
if (option === "pi")
|
|
39
|
-
return { runtime: "pi", piDistribution: "external" };
|
|
40
30
|
return { runtime: option };
|
|
41
31
|
}
|
|
42
32
|
function fromUserRuntime(userRuntime) {
|
|
43
33
|
return runtimeOptionTarget(userRuntime);
|
|
44
34
|
}
|
|
45
|
-
function piCatalogDistributionForUserRuntime(userRuntime) {
|
|
46
|
-
if (userRuntime === "builtin-pi")
|
|
47
|
-
return "builtin";
|
|
48
|
-
if (userRuntime === "pi")
|
|
49
|
-
return "external";
|
|
50
|
-
throw new Error(`非 Pi sibling runtime:${userRuntime}`);
|
|
51
|
-
}
|
|
@@ -1,41 +1,25 @@
|
|
|
1
|
-
export const RUNTIME_OPTIONS = ["codex", "claude", "pi"
|
|
1
|
+
export const RUNTIME_OPTIONS = ["codex", "claude", "pi"];
|
|
2
2
|
export const USER_RUNTIMES = RUNTIME_OPTIONS;
|
|
3
3
|
export const ADAPTER_RUNTIMES = ["pi", "codex", "claude"];
|
|
4
4
|
export function isUserRuntime(value) {
|
|
5
|
-
return value === "pi" || value === "
|
|
5
|
+
return value === "pi" || value === "codex" || value === "claude";
|
|
6
6
|
}
|
|
7
7
|
export function isAdapterRuntime(value) {
|
|
8
8
|
return value === "pi" || value === "codex" || value === "claude";
|
|
9
9
|
}
|
|
10
|
-
/**
|
|
10
|
+
/** Identity mapping with validation. */
|
|
11
11
|
export function runtimeOptionOf(input) {
|
|
12
|
-
|
|
13
|
-
if (runtime === "codex" || runtime === "claude" || runtime === "builtin-pi")
|
|
14
|
-
return runtime;
|
|
15
|
-
if (runtime === "pi")
|
|
16
|
-
return piDistribution === "builtin" ? "builtin-pi" : "pi";
|
|
17
|
-
return runtime;
|
|
12
|
+
return input.runtime;
|
|
18
13
|
}
|
|
19
|
-
export function toUserRuntime(runtime
|
|
20
|
-
return runtimeOptionOf({ runtime
|
|
14
|
+
export function toUserRuntime(runtime) {
|
|
15
|
+
return runtimeOptionOf({ runtime });
|
|
21
16
|
}
|
|
22
|
-
/** Persist a user-facing
|
|
17
|
+
/** Persist a user-facing runtime as the stored adapter id. */
|
|
23
18
|
export function runtimeOptionTarget(option) {
|
|
24
19
|
if (!isUserRuntime(option))
|
|
25
20
|
throw new Error(`未知 runtime:${option}`);
|
|
26
|
-
if (option === "builtin-pi")
|
|
27
|
-
return { runtime: "pi", piDistribution: "builtin" };
|
|
28
|
-
if (option === "pi")
|
|
29
|
-
return { runtime: "pi", piDistribution: "external" };
|
|
30
21
|
return { runtime: option };
|
|
31
22
|
}
|
|
32
23
|
export function fromUserRuntime(userRuntime) {
|
|
33
24
|
return runtimeOptionTarget(userRuntime);
|
|
34
25
|
}
|
|
35
|
-
export function piCatalogDistributionForUserRuntime(userRuntime) {
|
|
36
|
-
if (userRuntime === "builtin-pi")
|
|
37
|
-
return "builtin";
|
|
38
|
-
if (userRuntime === "pi")
|
|
39
|
-
return "external";
|
|
40
|
-
throw new Error(`非 Pi sibling runtime:${userRuntime}`);
|
|
41
|
-
}
|