larkin 0.4.29 → 0.5.1

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 +15 -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 +45 -15
  24. package/dist/runtime/pi-compaction-recovery.mjs +43 -14
  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 +62 -98
  35. package/dist/runtime/runtime-readiness.mjs +60 -97
  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
@@ -6,8 +6,7 @@ import { auditReminderDelivery } from "../agent/reminder-delivery-audit.mjs";
6
6
  import { isCanonicalInboxTarget, targetKeyOfInboxEnvelope } from "../agent/inbox-projection.mjs";
7
7
  import { SpanKind } from "@opentelemetry/api";
8
8
  import { buildStrictProviderErrorInput, classifyStrictProviderError } from "./provider-error-classifier.mjs";
9
- import { authFailureAppliesTo, classifyPiMissingCredentialRejection, classifyRuntimePrerequisite, configuredProviderId, isBuiltinPiDistribution, missingProviderCredentialReadiness, parsePersistedAuthFailure, providerAuthenticationFailureReadiness, readinessForPersistedAuthFailure, safeProviderId, RuntimePrerequisiteError, } from "./runtime-readiness.mjs";
10
- import { officialPiHasStoredProvider } from "./pi-official-auth.mjs";
9
+ import { authFailureAppliesTo, classifyPiMissingCredentialRejection, classifyRuntimePrerequisite, configuredProviderId, missingProviderCredentialReadiness, parsePersistedAuthFailure, providerAuthenticationFailureReadiness, readinessForPersistedAuthFailure, safeProviderId, RuntimePrerequisiteError, } from "./runtime-readiness.mjs";
11
10
  import { resolveOfficialLarkCli } from "../app/official-lark-cli.mjs";
12
11
  import { assertAgentWorkspaceBound, managedLarkCliEnv } from "../app/agent-lark-cli-workspace.mjs";
13
12
  import { isPiNativeCompactionRequired, PiCompactionBreaker, PiCompactionRecoveryMachine, } from "./pi-compaction-recovery.mjs";
@@ -94,37 +93,23 @@ function persistPreviousSession(agent, previous) {
94
93
  // In-memory ref still holds for this process; restart will miss it only if this write failed.
95
94
  }
96
95
  }
97
- function isBuiltinPiAgent(agent) {
98
- return agent.adapter.id === "pi"
99
- && (isBuiltinPiDistribution(agent.config.piDistribution) || agent.config.runtime === "builtin-pi");
100
- }
101
96
  function authFailureScopeOf(agent) {
102
97
  return {
103
98
  runtime: agent.config.runtime,
104
99
  model: agent.config.model,
105
- piDistribution: agent.config.piDistribution,
106
100
  adapterId: agent.adapter.id,
107
101
  };
108
102
  }
109
103
  function currentAuthFailure(agent) {
110
104
  if (!agent.authFailureActive)
111
105
  return null;
112
- const kind = agent.authFailureKind
113
- ?? (agent.authFailureProvider ? "missing-provider" : "generic");
114
- if (kind === "missing-provider") {
115
- if (!agent.authFailureProvider)
116
- return null;
117
- return { kind: "missing-provider", runtime: "pi", piDistribution: "builtin", provider: agent.authFailureProvider };
118
- }
119
106
  const runtime = agent.adapter.id === "codex" || agent.adapter.id === "claude" || agent.adapter.id === "pi"
120
107
  ? agent.adapter.id : null;
121
108
  if (!runtime)
122
109
  return null;
123
110
  return {
124
- kind: "generic",
111
+ kind: agent.authFailureKind === "missing-provider" ? "missing-provider" : "generic",
125
112
  runtime,
126
- ...(runtime === "pi" && (agent.config.piDistribution === "builtin" || agent.config.piDistribution === "external")
127
- ? { piDistribution: agent.config.piDistribution } : {}),
128
113
  provider: agent.authFailureProvider,
129
114
  };
130
115
  }
@@ -335,7 +320,6 @@ export function createRuntimeHost(options) {
335
320
  } : {}),
336
321
  LARKIN_CONFIG_DIR: process.env.LARKIN_CONFIG_DIR,
337
322
  LARKIN_HOME: process.env.LARKIN_HOME,
338
- ...(config.piDistribution ? { LARKIN_PI_DISTRIBUTION: config.piDistribution } : {}),
339
323
  LARKIN_STATE_DIR: effectivePiStateDir(config),
340
324
  ...(process.env.HOME ? { HOME: process.env.HOME } : {}),
341
325
  ...(process.env.SHELL ? { SHELL: process.env.SHELL } : {}),
@@ -597,10 +581,6 @@ export function createRuntimeHost(options) {
597
581
  messageId: record.messageId, status: "consumed" });
598
582
  }
599
583
  };
600
- const ownedConfigDir = () => {
601
- const value = process.env.LARKIN_CONFIG_DIR?.trim();
602
- return value || null;
603
- };
604
584
  const projectAuthFailure = (agent, readiness, failure) => {
605
585
  agent.authFailureActive = true;
606
586
  agent.authFailureKind = failure.kind;
@@ -618,12 +598,7 @@ export function createRuntimeHost(options) {
618
598
  if (agent.authFailureKind !== "missing-provider" || !agent.authFailureProvider)
619
599
  return true;
620
600
  const failure = currentAuthFailure(agent);
621
- if (!failure || !authFailureAppliesTo(authFailureScopeOf(agent), failure))
622
- return false;
623
- const configDir = ownedConfigDir();
624
- if (!configDir)
625
- return false;
626
- return officialPiHasStoredProvider(configDir, agent.config.agentId, agent.authFailureProvider);
601
+ return Boolean(failure && authFailureAppliesTo(authFailureScopeOf(agent), failure));
627
602
  };
628
603
  const resultFor = (agent, record, result) => {
629
604
  if (result.status === "accepted") {
@@ -638,12 +613,12 @@ export function createRuntimeHost(options) {
638
613
  deliveryId: record.deliveryId, messageId: record.messageId, status: "accepted" });
639
614
  return { status: "accepted", deliveryId: record.deliveryId };
640
615
  }
641
- const missing = result.status === "rejected" && isBuiltinPiAgent(agent)
616
+ const missing = result.status === "rejected" && agent.adapter.id === "pi"
642
617
  ? classifyPiMissingCredentialRejection(result.reason)
643
618
  : null;
644
619
  if (missing) {
645
620
  const readiness = missingProviderCredentialReadiness(agent.adapter.id, missing.provider);
646
- const reason = readiness.reason ?? `Provider ${missing.provider} is missing from this Agent's official credential store.`;
621
+ const reason = readiness.reason ?? result.reason;
647
622
  if (record.status !== "error") {
648
623
  record.reason = reason;
649
624
  record.retryable = false;
@@ -1620,26 +1595,30 @@ export function createRuntimeHost(options) {
1620
1595
  record.errorCategory = classifiedCategory;
1621
1596
  else
1622
1597
  delete record.errorCategory;
1623
- const missing = event.errorCategory === "auth" && !event.retryable && isBuiltinPiAgent(agent)
1598
+ const missing = agent.adapter.id === "pi"
1624
1599
  ? classifyPiMissingCredentialRejection(event.upstream?.message)
1625
1600
  ?? classifyPiMissingCredentialRejection(event.message)
1626
1601
  : null;
1627
- if (missing)
1602
+ if (missing) {
1603
+ record.retryable = false;
1604
+ record.errorCategory = "auth";
1628
1605
  record.authProvider = missing.provider;
1629
- const finalRecord = setRecord(agent, record, event.retryable ? "pending" : "error");
1606
+ }
1607
+ const terminal = Boolean(missing) || !event.retryable;
1608
+ const finalRecord = setRecord(agent, record, terminal ? "error" : "pending");
1630
1609
  if (finalRecord.status !== "consumed")
1631
1610
  emit({ type: "delivery", agentId: agent.config.agentId,
1632
1611
  deliveryId: record.deliveryId, messageId: record.messageId,
1633
- status: event.retryable ? "deferred" : "error", reason: event.message });
1634
- if (event.errorCategory === "auth" && !event.retryable) {
1635
- const readiness = missing
1636
- ? missingProviderCredentialReadiness(agent.adapter.id, missing.provider)
1637
- : providerAuthenticationFailureReadiness(agent.adapter.id, event.upstream?.provider);
1638
- projectAuthFailure(agent, readiness, missing
1639
- ? { kind: "missing-provider", provider: missing.provider }
1640
- : { kind: "generic", provider: genericAuthProvider(agent, event.upstream) });
1641
- }
1642
- if (event.retryable && !agent.busy && !agent.turnInProgress)
1612
+ status: terminal ? "error" : "deferred", reason: event.message });
1613
+ if (missing) {
1614
+ const readiness = missingProviderCredentialReadiness(agent.adapter.id, missing.provider);
1615
+ projectAuthFailure(agent, readiness, { kind: "missing-provider", provider: missing.provider });
1616
+ }
1617
+ else if (event.errorCategory === "auth" && !event.retryable) {
1618
+ const readiness = providerAuthenticationFailureReadiness(agent.adapter.id, event.upstream?.provider);
1619
+ projectAuthFailure(agent, readiness, { kind: "generic", provider: genericAuthProvider(agent, event.upstream) });
1620
+ }
1621
+ if (!terminal && event.retryable && !agent.busy && !agent.turnInProgress)
1643
1622
  void retryPending(agent);
1644
1623
  }
1645
1624
  else if (event.type === "configuration-error") {
@@ -1914,7 +1893,6 @@ export function createRuntimeHost(options) {
1914
1893
  && authFailureAppliesTo({
1915
1894
  runtime: config.runtime,
1916
1895
  model: config.model,
1917
- piDistribution: config.piDistribution,
1918
1896
  adapterId: adapter.id,
1919
1897
  }, previousFailure));
1920
1898
  const candidate = {
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CURRENT_RUNTIME_MODELS = void 0;
4
- // Authored catalog keys are adapter ids only. builtin-pi is a user-facing sibling, not a stored runtime.
4
+ // Authored catalog keys are adapter ids only.
5
5
  // Pi, Codex and Claude replace these placeholders/fallbacks at runtime with their machine-readable catalogs.
6
6
  // Claude's supported stdin control-channel list is the live authority; its entries below
7
7
  // remain explicit compatibility candidates for config loading and discovery failures.
@@ -1,4 +1,4 @@
1
- // Authored catalog keys are adapter ids only. builtin-pi is a user-facing sibling, not a stored runtime.
1
+ // Authored catalog keys are adapter ids only.
2
2
  // Pi, Codex and Claude replace these placeholders/fallbacks at runtime with their machine-readable catalogs.
3
3
  // Claude's supported stdin control-channel list is the live authority; its entries below
4
4
  // remain explicit compatibility candidates for config loading and discovery failures.
@@ -38,25 +38,22 @@ 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");
56
+ const pi_compaction_recovery_js_1 = require("./pi-compaction-recovery.cjs");
60
57
  function safeProviderId(value) {
61
58
  const provider = typeof value === "string" ? value.trim() : "";
62
59
  return /^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$/.test(provider) ? provider : null;
@@ -64,9 +61,6 @@ function safeProviderId(value) {
64
61
  function safeProviderLabel(value) {
65
62
  return safeProviderId(value);
66
63
  }
67
- function isBuiltinPiDistribution(value) {
68
- return value === "builtin";
69
- }
70
64
  /** Model ids are `provider/model`; only the provider prefix is used for scope. */
71
65
  function configuredProviderId(model) {
72
66
  const value = typeof model === "string" ? model.trim() : "";
@@ -89,53 +83,20 @@ function parsePersistedAuthFailure(state) {
89
83
  const provider = safeProviderId(failure.provider);
90
84
  if (kind === "missing-provider" && !provider)
91
85
  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
- };
86
+ return { kind, runtime, provider };
100
87
  }
101
88
  const legacy = safeProviderId(record.authFailureProvider);
102
- return legacy
103
- ? { kind: "missing-provider", runtime: "pi", piDistribution: "builtin", provider: legacy }
104
- : null;
89
+ return legacy ? { kind: "missing-provider", runtime: "pi", provider: legacy } : null;
105
90
  }
106
91
  function currentAdapterId(current) {
107
- return current.adapterId ?? (current.runtime === "builtin-pi" ? "pi" : current.runtime);
108
- }
109
- function currentIsBuiltinPi(current) {
110
- return currentAdapterId(current) === "pi"
111
- && (isBuiltinPiDistribution(current.piDistribution) || current.runtime === "builtin-pi");
92
+ return current.adapterId ?? current.runtime;
112
93
  }
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
94
  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
95
  if (failure.runtime !== currentAdapterId(current))
128
96
  return false;
129
- if (failure.runtime === "pi") {
130
- const persistedBuiltin = failure.piDistribution === "builtin";
131
- if (currentIsBuiltinPi(current) !== persistedBuiltin)
132
- return false;
133
- }
134
97
  if (!failure.provider)
135
98
  return true;
136
99
  const currentProvider = configuredProviderId(current.model);
137
- if (currentIsBuiltinPi(current))
138
- return currentProvider === failure.provider;
139
100
  return currentProvider ? currentProvider === failure.provider : true;
140
101
  }
141
102
  function readinessForPersistedAuthFailure(failure) {
@@ -154,6 +115,20 @@ function classifyPiMissingCredentialRejection(message) {
154
115
  const provider = match ? safeProviderLabel(match[2]) : null;
155
116
  return provider && match ? { provider, diagnostic: `${match[1]} ${provider}` } : null;
156
117
  }
118
+ function runtimeInstallNextAction(runtime) {
119
+ if (runtime === "pi")
120
+ return "Install Pi and ensure `pi` is on PATH, or set LARKIN_PI_COMMAND.";
121
+ if (runtime === "codex")
122
+ return "Install Codex and ensure `codex` is on PATH, or set LARKIN_CODEX_COMMAND.";
123
+ return "Install Claude Code and ensure `claude` is on PATH, or set LARKIN_CLAUDE_COMMAND.";
124
+ }
125
+ function runtimeLoginNextAction(runtime) {
126
+ if (runtime === "pi")
127
+ return "Log in with the external `pi` CLI, then retry.";
128
+ if (runtime === "codex")
129
+ return "Run `codex login`, then retry.";
130
+ return "Run `claude login`, then retry.";
131
+ }
157
132
  function providerAuthenticationFailureReadiness(runtime, provider) {
158
133
  const label = safeProviderLabel(provider);
159
134
  return {
@@ -162,23 +137,20 @@ function providerAuthenticationFailureReadiness(runtime, provider) {
162
137
  reason: label
163
138
  ? `Provider ${label} API-key authentication failed during a Runtime turn.`
164
139
  : "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.",
140
+ nextAction: runtimeLoginNextAction(runtime),
166
141
  };
167
142
  }
168
- /** P0 分类;Pi nextAction 共用 UX preset 恢复文案,不写官方 provider ID。 */
169
143
  function missingProviderCredentialReadiness(runtime, provider) {
170
144
  const label = safeProviderLabel(provider);
171
145
  return {
172
146
  runtime,
173
147
  state: "unauthenticated",
174
148
  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.",
149
+ ? `Provider ${label} is not authenticated for this runtime.`
150
+ : "The configured provider is not authenticated for this runtime.",
151
+ nextAction: runtime === "pi" && label
152
+ ? `Log in with the external \`pi\` CLI for provider ${label}, then retry.`
153
+ : runtimeLoginNextAction(runtime),
182
154
  };
183
155
  }
184
156
  class RuntimePrerequisiteError extends Error {
@@ -211,27 +183,37 @@ function classifyRuntimePrerequisite(runtime, error, executable) {
211
183
  const reason = (error instanceof Error ? error.message : String(error)).replace(/[\r\n]+/g, " ").slice(0, 500);
212
184
  if (/ENOENT|not found|no such file|spawn .* failed/i.test(reason))
213
185
  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.`,
186
+ runtime, state: "missing", ...(executable ? { executable } : {}),
187
+ reason: `${runtime} is not installed`,
188
+ nextAction: runtimeInstallNextAction(runtime),
216
189
  };
217
190
  if (/no authenticated available models|login|credential|unauthenticated|unauthorized|oauth/i.test(reason))
218
191
  return {
219
192
  runtime, state: "unauthenticated", ...(executable ? { executable } : {}), reason,
220
- // 此分类没有 distribution:外部 Pi 不能指向 Dashboard / pi-auth login。
193
+ nextAction: runtimeLoginNextAction(runtime),
194
+ };
195
+ if (/older than the minimum|not a supported version(?: line)?|version output must contain exactly one/i.test(reason)) {
196
+ return {
197
+ runtime, state: "incompatible", ...(executable ? { executable } : {}), reason,
221
198
  nextAction: runtime === "pi"
222
- ? "Run the official `pi` login flow, then retry."
223
- : `Authenticate ${runtime}, then retry.`,
199
+ ? `Upgrade pi to ${pi_compaction_recovery_js_1.MINIMUM_PI_VERSION} or newer`
200
+ : `Upgrade ${runtime}, then retry.`,
224
201
  };
225
- if (/protocol (?:version )?(?:mismatch|unsupported|incompatible)|unsupported (?:rpc|protocol|schema)|schema (?:mismatch|incompatible)|requires (?:a )?newer version/i.test(reason))
202
+ }
203
+ if (/protocol (?:version )?(?:mismatch|unsupported|incompatible)|unsupported (?:rpc|protocol|schema)|schema (?:mismatch|incompatible)|requires (?:a )?newer version/i.test(reason)) {
226
204
  return {
227
205
  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.`,
206
+ nextAction: runtime === "pi"
207
+ ? "Upgrade local Pi to a version that supports the documented RPC protocol."
208
+ : `Upgrade ${runtime}, then retry.`,
229
209
  };
230
- if (/timeout|timed out|unexpected EOF|\bEOF\b|TLS|ECONNRESET|socket hang up|network|temporar(?:y|ily)|unavailable/i.test(reason))
210
+ }
211
+ if (/timeout|timed out|unexpected EOF|\bEOF\b|TLS|ECONNRESET|socket hang up|network|temporar(?:y|ily)|unavailable/i.test(reason)) {
231
212
  return {
232
213
  runtime, state: "unavailable", ...(executable ? { executable } : {}), reason,
233
214
  nextAction: `Retry ${runtime}; Larkin will use its bounded Runtime recreate/backoff policy.`,
234
215
  };
216
+ }
235
217
  return {
236
218
  runtime, state: "unavailable", ...(executable ? { executable } : {}), reason,
237
219
  nextAction: `Retry ${runtime}; the failure is not proven to be a protocol incompatibility.`,
@@ -254,47 +236,30 @@ function executableVersion(executable, env, commandArgs = []) {
254
236
  }
255
237
  /** Resolve and handshake through each runtime's structured native control protocol. */
256
238
  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" });
239
+ const env = { ...process.env, ...options.env };
240
+ const command = selectedCommand(options);
241
+ const executable = resolveRuntimeExecutable(command, env);
242
+ if (!executable) {
243
+ return {
244
+ runtime: options.runtime,
245
+ state: "missing",
246
+ reason: `${options.runtime} is not installed`,
247
+ nextAction: runtimeInstallNextAction(options.runtime),
248
+ };
263
249
  }
264
- if (options.runtime === "pi" && piDistribution === "builtin") {
250
+ let version = executableVersion(executable, env, options.commandArgs);
251
+ if (options.runtime === "pi") {
265
252
  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)` };
253
+ const probe = (0, node_child_process_1.spawnSync)(executable, [...options.commandArgs ?? [], "--version"], {
254
+ env, encoding: "utf8", timeout: 5_000, maxBuffer: 64 * 1024,
255
+ });
256
+ version = (0, pi_compaction_recovery_js_1.parsePiExecutableVersion)(String(probe.stdout || ""));
270
257
  }
271
258
  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 }) };
259
+ const classified = classifyRuntimePrerequisite("pi", error, executable);
260
+ return { ...classified, executable, ...(version ? { version } : {}) };
275
261
  }
276
262
  }
277
- const command = selectedCommand(options);
278
- 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) {
289
- 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.",
295
- };
296
- }
297
- const version = executableVersion(executable, env, options.commandArgs);
298
263
  try {
299
264
  if (options.runtime === "pi") {
300
265
  const { discoverPiModelCatalog } = await Promise.resolve().then(() => __importStar(require("./pi-model-catalog.cjs")));
@@ -303,7 +268,6 @@ async function probeNativeRuntimeReadiness(options) {
303
268
  command: executable,
304
269
  commandArgs: options.commandArgs,
305
270
  env,
306
- agentDir: (0, pi_provider_config_js_1.ownedPiCatalogAgentDir)((0, root_layout_js_1.resolveConfigDir)(env, node_os_1.default.homedir()), piAgentId),
307
271
  });
308
272
  }
309
273
  else if (options.runtime === "codex") {