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.
Files changed (57) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +5 -9
  3. package/artifacts/release/THIRD_PARTY_NOTICES.txt +751 -4425
  4. package/dist/app/agent-cli.mjs +14 -2
  5. package/dist/app/agent-config.mjs +26 -86
  6. package/dist/app/binary-entry.mjs +0 -20
  7. package/dist/app/cli.mjs +6 -22
  8. package/dist/app/internal-command.cjs +0 -2
  9. package/dist/app/internal-command.mjs +0 -2
  10. package/dist/app/runtime-model-directory.mjs +2 -16
  11. package/dist/app/runtime-process.mjs +0 -1
  12. package/dist/app/setup.mjs +52 -57
  13. package/dist/dashboard/dashboard-config-controller.mjs +43 -109
  14. package/dist/dashboard/dashboard-view-model.mjs +4 -7
  15. package/dist/dashboard/web/assets/dashboard.css +1 -1
  16. package/dist/dashboard/web/assets/dashboard.js +15 -15
  17. package/dist/feishu/host-shell.cjs +1 -2
  18. package/dist/feishu/host-shell.mjs +1 -2
  19. package/dist/platform/config.cjs +168 -133
  20. package/dist/platform/config.mjs +168 -133
  21. package/dist/runtime/pi-artifact-provenance.mjs +3 -3
  22. package/dist/runtime/pi-bash-timeout-extension.mjs +4 -5
  23. package/dist/runtime/pi-compaction-recovery.cjs +9 -11
  24. package/dist/runtime/pi-compaction-recovery.mjs +8 -10
  25. package/dist/runtime/pi-extension-api.mjs +1 -0
  26. package/dist/runtime/pi-model-catalog.cjs +7 -8
  27. package/dist/runtime/pi-model-catalog.mjs +7 -8
  28. package/dist/runtime/pi-subagent-injection.mjs +17 -4
  29. package/dist/runtime/runtime-adapters.mjs +26 -43
  30. package/dist/runtime/runtime-host.cjs +21 -43
  31. package/dist/runtime/runtime-host.mjs +22 -44
  32. package/dist/runtime/runtime-model-catalog.cjs +1 -1
  33. package/dist/runtime/runtime-model-catalog.mjs +1 -1
  34. package/dist/runtime/runtime-readiness.cjs +42 -99
  35. package/dist/runtime/runtime-readiness.mjs +40 -98
  36. package/dist/runtime/user-runtime.cjs +7 -24
  37. package/dist/runtime/user-runtime.mjs +7 -23
  38. package/dist/setup/bot-register.mjs +15 -123
  39. package/dist/setup/setup-agent-choice.mjs +48 -74
  40. package/dist/setup/setup-bind.mjs +51 -151
  41. package/dist/setup/setup-binding.mjs +6 -9
  42. package/package.json +3 -2
  43. package/dist/app/pi-auth-cli.mjs +0 -277
  44. package/dist/platform/process-boundary-trace.cjs +0 -108
  45. package/dist/runtime/builtin-pi-assets.cjs +0 -117
  46. package/dist/runtime/builtin-pi-assets.mjs +0 -105
  47. package/dist/runtime/pi-artifact-provenance.cjs +0 -147
  48. package/dist/runtime/pi-distribution-label.cjs +0 -6
  49. package/dist/runtime/pi-distribution-label.mjs +0 -3
  50. package/dist/runtime/pi-inline-extensions.mjs +0 -78
  51. package/dist/runtime/pi-official-auth.cjs +0 -594
  52. package/dist/runtime/pi-official-auth.mjs +0 -544
  53. package/dist/runtime/pi-profile-migration.cjs +0 -764
  54. package/dist/runtime/pi-profile-migration.mjs +0 -719
  55. package/dist/runtime/pi-provider-config.cjs +0 -354
  56. package/dist/runtime/pi-provider-config.mjs +0 -334
  57. 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
- const piDistribution = failure.piDistribution === "builtin" || failure.piDistribution === "external"
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 ?? (current.runtime === "builtin-pi" ? "pi" : current.runtime);
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: "Check the provider login or API-key resolver command, then retry the Agent turn.",
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 missing from this Agent's official credential store.`
176
- : "The configured provider is missing from this Agent's official credential store.",
177
- nextAction: runtime === "pi"
178
- ? (0, pi_provider_config_js_1.builtinPiProviderRecoveryNextAction)({ providerId: label ?? undefined })
179
- : label
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 } : {}), reason,
215
- nextAction: runtime === "pi" ? "Install Pi and ensure `pi` is on PATH, or set LARKIN_PI_COMMAND." : `Install ${runtime} and ensure it is on PATH.`,
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
- // 此分类没有 distribution:外部 Pi 不能指向 Dashboard / pi-auth login。
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" ? "Upgrade local Pi to a version that supports the documented RPC protocol." : `Upgrade ${runtime}, then retry.`,
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
- if (/timeout|timed out|unexpected EOF|\bEOF\b|TLS|ECONNRESET|socket hang up|network|temporar(?:y|ily)|unavailable/i.test(reason))
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
- let env = { ...process.env, ...options.env };
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: "pi",
291
- state: "unavailable",
292
- executable,
293
- reason: "Pi catalog readiness requires Agent ID",
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
- const piDistribution = failure.piDistribution === "builtin" || failure.piDistribution === "external"
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 ?? (current.runtime === "builtin-pi" ? "pi" : current.runtime);
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: "Check the provider login or API-key resolver command, then retry the Agent turn.",
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 missing from this Agent's official credential store.`
125
- : "The configured provider is missing from this Agent's official credential store.",
126
- nextAction: runtime === "pi"
127
- ? builtinPiProviderRecoveryNextAction({ providerId: label ?? undefined })
128
- : label
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 } : {}), reason,
163
- nextAction: runtime === "pi" ? "Install Pi and ensure `pi` is on PATH, or set LARKIN_PI_COMMAND." : `Install ${runtime} and ensure it is on PATH.`,
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
- // 此分类没有 distribution:外部 Pi 不能指向 Dashboard / pi-auth login。
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" ? "Upgrade local Pi to a version that supports the documented RPC protocol." : `Upgrade ${runtime}, then retry.`,
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
- if (/timeout|timed out|unexpected EOF|\bEOF\b|TLS|ECONNRESET|socket hang up|network|temporar(?:y|ily)|unavailable/i.test(reason))
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
- let env = { ...process.env, ...options.env };
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: "pi",
239
- state: "unavailable",
240
- executable,
241
- reason: "Pi catalog readiness requires Agent ID",
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.piCatalogDistributionForUserRuntime = piCatalogDistributionForUserRuntime;
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 === "builtin-pi" || value === "codex" || value === "claude";
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
- /** Project stored adapter + distribution to the user-facing sibling id. Legacy `runtime=pi` without distribution is `pi`, never builtin. */
19
+ /** Identity mapping with validation. */
21
20
  function runtimeOptionOf(input) {
22
- const { runtime, piDistribution } = input;
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, piDistribution) {
30
- return runtimeOptionOf({ runtime, piDistribution });
23
+ function toUserRuntime(runtime) {
24
+ return runtimeOptionOf({ runtime });
31
25
  }
32
- /** Persist a user-facing sibling as adapter id + distribution. Adapter id stays `pi` for both Pi siblings. */
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", "builtin-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 === "builtin-pi" || value === "codex" || value === "claude";
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
- /** Project stored adapter + distribution to the user-facing sibling id. Legacy `runtime=pi` without distribution is `pi`, never builtin. */
10
+ /** Identity mapping with validation. */
11
11
  export function runtimeOptionOf(input) {
12
- const { runtime, piDistribution } = input;
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, piDistribution) {
20
- return runtimeOptionOf({ runtime, piDistribution });
14
+ export function toUserRuntime(runtime) {
15
+ return runtimeOptionOf({ runtime });
21
16
  }
22
- /** Persist a user-facing sibling as adapter id + distribution. Adapter id stays `pi` for both Pi siblings. */
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
- }