@socketsecurity/lib 6.0.7 → 6.0.9

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 (323) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +1 -1
  3. package/dist/ai/agent-context.d.mts +103 -0
  4. package/dist/ai/agent-context.js +157 -0
  5. package/dist/ai/backends.d.mts +83 -0
  6. package/dist/ai/backends.js +173 -0
  7. package/dist/ai/credentials.d.mts +49 -0
  8. package/dist/ai/credentials.js +82 -0
  9. package/dist/ai/discover.d.mts +4 -0
  10. package/dist/ai/discover.js +1 -1
  11. package/dist/ai/exec.d.mts +52 -0
  12. package/dist/ai/exec.js +92 -0
  13. package/dist/ai/http.d.mts +132 -0
  14. package/dist/ai/http.js +130 -0
  15. package/dist/ai/profiles.d.mts +41 -6
  16. package/dist/ai/profiles.js +52 -10
  17. package/dist/ai/route.d.mts +82 -0
  18. package/dist/ai/route.js +171 -0
  19. package/dist/ai/spawn.d.mts +42 -2
  20. package/dist/ai/spawn.js +146 -33
  21. package/dist/ai/subagent-status.d.mts +48 -0
  22. package/dist/ai/subagent-status.js +57 -0
  23. package/dist/ai/tier.d.mts +60 -0
  24. package/dist/ai/tier.js +53 -0
  25. package/dist/ai/types.d.mts +25 -2
  26. package/dist/ai/worktree.js +4 -0
  27. package/dist/archives/tar.js +1 -1
  28. package/dist/archives/zip.js +2 -2
  29. package/dist/argv/parse.d.ts +19 -2
  30. package/dist/argv/parse.js +1 -1
  31. package/dist/arrays/join.js +4 -0
  32. package/dist/bin/find.js +4 -4
  33. package/dist/bin/prim.cjs +23322 -18018
  34. package/dist/bin/resolve.js +2 -2
  35. package/dist/cache/ttl/store.js +2 -2
  36. package/dist/cli/check-primordials.d.ts +8 -3
  37. package/dist/cli/check-primordials.js +4 -4
  38. package/dist/compression/_internal.js +1 -1
  39. package/dist/compression/brotli.d.ts +1 -2
  40. package/dist/compression/brotli.js +5 -1
  41. package/dist/compression/gzip.js +5 -1
  42. package/dist/config/layers.d.ts +53 -0
  43. package/dist/config/layers.js +83 -0
  44. package/dist/constants/packages.d.ts +3 -0
  45. package/dist/constants/packages.js +2 -1
  46. package/dist/constants/socket.d.ts +2 -6
  47. package/dist/constants/socket.js +12 -14
  48. package/dist/cover/code.js +2 -2
  49. package/dist/crypto/hash.d.ts +4 -1
  50. package/dist/crypto/hash.js +4 -1
  51. package/dist/dlx/arborist.js +13 -3
  52. package/dist/dlx/binary-cache.js +1 -1
  53. package/dist/dlx/binary-resolution.js +1 -1
  54. package/dist/dlx/detect.d.ts +8 -0
  55. package/dist/dlx/firewall.d.ts +8 -0
  56. package/dist/dlx/lockfile.js +5 -2
  57. package/dist/dlx/manifest.js +1 -1
  58. package/dist/dlx/package.js +4 -0
  59. package/dist/eco/cargo/parse-lockfile.d.ts +1 -2
  60. package/dist/eco/cargo/parse-lockfile.js +3 -3
  61. package/dist/eco/manifest/detect-format.js +1 -1
  62. package/dist/eco/npm/npm/parse-lockfile.d.ts +3 -4
  63. package/dist/eco/npm/npm/parse-lockfile.js +2 -2
  64. package/dist/eco/npm/parse-package-json.d.ts +11 -0
  65. package/dist/eco/npm/parse-package-json.js +1 -1
  66. package/dist/eco/npm/pnpm/parse-lockfile.d.ts +5 -3
  67. package/dist/eco/npm/pnpm/parse-lockfile.js +3 -3
  68. package/dist/eco/npm/yarnpkg/yarn/exec.js +1 -1
  69. package/dist/eco/npm/yarnpkg/yarn/parse-lockfile.d.ts +1 -2
  70. package/dist/eco/npm/yarnpkg/yarn/parse-lockfile.js +2 -2
  71. package/dist/env/proxy.js +1 -1
  72. package/dist/env/rewire.d.ts +6 -3
  73. package/dist/env/rewire.js +7 -8
  74. package/dist/env/socket.d.ts +7 -0
  75. package/dist/env/socket.js +10 -0
  76. package/dist/env/xdg.d.ts +17 -0
  77. package/dist/env/xdg.js +21 -1
  78. package/dist/errors/predicates.js +1 -1
  79. package/dist/errors/stack.js +1 -2
  80. package/dist/external/@npmcli/package-json.js +3455 -4881
  81. package/dist/external/@npmcli/promise-spawn.js +3 -1
  82. package/dist/external/@yarnpkg/extensions.js +1 -1
  83. package/dist/external/external-pack.js +1 -1
  84. package/dist/external/npm-pack.js +29164 -31799
  85. package/dist/external/pico-pack.js +4 -2
  86. package/dist/external/tar-fs.js +63 -16
  87. package/dist/external/which.js +3 -1
  88. package/dist/external-tools/bazel/asset-names.d.ts +1 -1
  89. package/dist/external-tools/bazel/asset-names.js +5 -2
  90. package/dist/external-tools/bazel/from-download.d.ts +1 -1
  91. package/dist/external-tools/bazel/from-download.js +5 -2
  92. package/dist/external-tools/bazel/resolve-bazel-version.js +4 -0
  93. package/dist/external-tools/bazel/resolve.d.ts +3 -3
  94. package/dist/external-tools/bazel/resolve.js +16 -8
  95. package/dist/external-tools/cdxgen/asset-names.d.ts +1 -1
  96. package/dist/external-tools/cdxgen/asset-names.js +5 -2
  97. package/dist/external-tools/cdxgen/from-download.d.ts +1 -1
  98. package/dist/external-tools/cdxgen/from-download.js +7 -4
  99. package/dist/external-tools/cdxgen/resolve.d.ts +3 -3
  100. package/dist/external-tools/cdxgen/resolve.js +16 -8
  101. package/dist/external-tools/from-download.d.ts +2 -2
  102. package/dist/external-tools/from-download.js +11 -5
  103. package/dist/external-tools/from-pip-venv.d.ts +1 -1
  104. package/dist/external-tools/from-pip-venv.js +12 -5
  105. package/dist/external-tools/janus/asset-names.d.ts +1 -1
  106. package/dist/external-tools/janus/asset-names.js +5 -2
  107. package/dist/external-tools/janus/from-download.d.ts +1 -1
  108. package/dist/external-tools/janus/from-download.js +5 -2
  109. package/dist/external-tools/janus/resolve.d.ts +3 -3
  110. package/dist/external-tools/janus/resolve.js +16 -8
  111. package/dist/external-tools/jre/asset-names.d.ts +1 -1
  112. package/dist/external-tools/jre/asset-names.js +5 -2
  113. package/dist/external-tools/jre/detect-platform-arch.js +1 -1
  114. package/dist/external-tools/jre/from-download.d.ts +1 -1
  115. package/dist/external-tools/jre/from-download.js +7 -4
  116. package/dist/external-tools/jre/from-java-home.js +2 -2
  117. package/dist/external-tools/jre/from-vfs.js +2 -2
  118. package/dist/external-tools/jre/resolve.d.ts +3 -3
  119. package/dist/external-tools/jre/resolve.js +16 -8
  120. package/dist/external-tools/manifest.d.ts +18 -0
  121. package/dist/external-tools/manifest.js +2 -2
  122. package/dist/external-tools/opengrep/asset-names.d.ts +1 -1
  123. package/dist/external-tools/opengrep/asset-names.js +5 -2
  124. package/dist/external-tools/opengrep/from-download.d.ts +1 -1
  125. package/dist/external-tools/opengrep/from-download.js +5 -2
  126. package/dist/external-tools/opengrep/resolve.d.ts +3 -3
  127. package/dist/external-tools/opengrep/resolve.js +16 -8
  128. package/dist/external-tools/python/asset-names.d.ts +1 -1
  129. package/dist/external-tools/python/asset-names.js +11 -4
  130. package/dist/external-tools/python/dlx.d.ts +3 -3
  131. package/dist/external-tools/python/dlx.js +20 -9
  132. package/dist/external-tools/python/from-download.d.ts +1 -1
  133. package/dist/external-tools/python/from-download.js +12 -5
  134. package/dist/external-tools/python/pin.js +6 -3
  135. package/dist/external-tools/python/pip-install.js +6 -3
  136. package/dist/external-tools/python/resolve.d.ts +3 -3
  137. package/dist/external-tools/python/resolve.js +19 -11
  138. package/dist/external-tools/python/uv-install.d.ts +89 -0
  139. package/dist/external-tools/python/uv-install.js +165 -0
  140. package/dist/external-tools/sbt/asset-names.d.ts +1 -1
  141. package/dist/external-tools/sbt/asset-names.js +5 -2
  142. package/dist/external-tools/sbt/from-download.d.ts +1 -1
  143. package/dist/external-tools/sbt/from-download.js +5 -2
  144. package/dist/external-tools/sbt/resolve.d.ts +3 -3
  145. package/dist/external-tools/sbt/resolve.js +16 -8
  146. package/dist/external-tools/skillspector/from-dlx.d.ts +1 -1
  147. package/dist/external-tools/skillspector/from-dlx.js +10 -3
  148. package/dist/external-tools/skillspector/from-uv.d.ts +30 -0
  149. package/dist/external-tools/skillspector/from-uv.js +56 -0
  150. package/dist/external-tools/skillspector/resolve.d.ts +20 -5
  151. package/dist/external-tools/skillspector/resolve.js +27 -6
  152. package/dist/external-tools/skillspector/types.d.ts +3 -1
  153. package/dist/external-tools/synp/asset-names.d.ts +1 -1
  154. package/dist/external-tools/synp/asset-names.js +6 -2
  155. package/dist/external-tools/synp/from-download.d.ts +1 -1
  156. package/dist/external-tools/synp/from-download.js +5 -2
  157. package/dist/external-tools/synp/resolve.d.ts +3 -3
  158. package/dist/external-tools/synp/resolve.js +16 -8
  159. package/dist/external-tools/trivy/asset-names.d.ts +1 -1
  160. package/dist/external-tools/trivy/asset-names.js +5 -2
  161. package/dist/external-tools/trivy/from-download.d.ts +1 -1
  162. package/dist/external-tools/trivy/from-download.js +7 -4
  163. package/dist/external-tools/trivy/resolve.d.ts +3 -3
  164. package/dist/external-tools/trivy/resolve.js +16 -8
  165. package/dist/external-tools/trufflehog/asset-names.d.ts +1 -1
  166. package/dist/external-tools/trufflehog/asset-names.js +5 -2
  167. package/dist/external-tools/trufflehog/from-download.d.ts +1 -1
  168. package/dist/external-tools/trufflehog/from-download.js +7 -4
  169. package/dist/external-tools/trufflehog/resolve.d.ts +3 -3
  170. package/dist/external-tools/trufflehog/resolve.js +16 -8
  171. package/dist/external-tools/uv/asset-names.d.ts +36 -0
  172. package/dist/external-tools/uv/asset-names.js +73 -0
  173. package/dist/external-tools/uv/from-download.d.ts +17 -0
  174. package/dist/external-tools/uv/from-download.js +50 -0
  175. package/dist/external-tools/uv/from-path.d.ts +5 -0
  176. package/dist/external-tools/uv/from-path.js +22 -0
  177. package/dist/external-tools/uv/from-vfs.d.ts +7 -0
  178. package/dist/external-tools/uv/from-vfs.js +26 -0
  179. package/dist/external-tools/uv/resolve.d.ts +25 -0
  180. package/dist/external-tools/uv/resolve.js +61 -0
  181. package/dist/external-tools/uv/types.d.ts +24 -0
  182. package/dist/external-tools/uv/types.js +2 -0
  183. package/dist/fleet/repo-config.d.ts +53 -0
  184. package/dist/fleet/repo-config.js +79 -0
  185. package/dist/fs/allowed-dirs-cache.d.ts +27 -1
  186. package/dist/fs/allowed-dirs-cache.js +39 -6
  187. package/dist/fs/copy.d.ts +88 -0
  188. package/dist/fs/copy.js +89 -0
  189. package/dist/fs/find.js +1 -1
  190. package/dist/fs/read-json-cache.d.ts +7 -0
  191. package/dist/fs/resolve-module.js +6 -2
  192. package/dist/fs/safe.js +1 -1
  193. package/dist/git/_internal.js +3 -3
  194. package/dist/git/repo.js +2 -4
  195. package/dist/git/staged.js +8 -0
  196. package/dist/git/tracked.d.ts +84 -0
  197. package/dist/git/tracked.js +163 -0
  198. package/dist/git/unstaged.js +8 -0
  199. package/dist/github/refs-graphql.js +4 -0
  200. package/dist/github/refs-rest.js +4 -0
  201. package/dist/globs/_internal.js +1 -1
  202. package/dist/globs/match.js +9 -1
  203. package/dist/globs/matcher.js +5 -1
  204. package/dist/http-request/browser.js +7 -3
  205. package/dist/http-request/checksum-file.js +1 -1
  206. package/dist/http-request/{browser-fetch.d.ts → fetch/browser.d.ts} +2 -2
  207. package/dist/http-request/{browser-fetch.js → fetch/browser.js} +4 -4
  208. package/dist/http-request/headers.js +1 -1
  209. package/dist/http-request/request-attempt.js +2 -2
  210. package/dist/http-request/user-agent.js +1 -1
  211. package/dist/integrity.d.ts +124 -71
  212. package/dist/integrity.js +168 -78
  213. package/dist/json/edit.js +38 -30
  214. package/dist/json/format.js +1 -1
  215. package/dist/logger/colors.d.ts +1 -2
  216. package/dist/logger/colors.js +2 -2
  217. package/dist/logger/symbols-builder.js +7 -8
  218. package/dist/logger/symbols.js +8 -8
  219. package/dist/native-messaging/install.d.ts +1 -1
  220. package/dist/native-messaging/install.js +7 -4
  221. package/dist/native-messaging/rate-limit.d.ts +7 -0
  222. package/dist/native-messaging/rate-limit.js +4 -0
  223. package/dist/node/async-hooks.js +1 -1
  224. package/dist/node/child-process.js +1 -1
  225. package/dist/node/crypto.js +1 -1
  226. package/dist/node/events.js +1 -1
  227. package/dist/node/fs-promises.js +1 -1
  228. package/dist/node/fs.d.ts +22 -6
  229. package/dist/node/fs.js +16 -3
  230. package/dist/node/http.js +1 -1
  231. package/dist/node/https.js +1 -1
  232. package/dist/node/module.d.ts +73 -2
  233. package/dist/node/module.js +97 -12
  234. package/dist/node/os.d.ts +10 -2
  235. package/dist/node/os.js +11 -4
  236. package/dist/node/path.d.ts +11 -2
  237. package/dist/node/path.js +17 -4
  238. package/dist/node/timers-promises.js +1 -1
  239. package/dist/node/url.js +1 -1
  240. package/dist/node/util.js +1 -1
  241. package/dist/objects/getters.js +1 -1
  242. package/dist/objects/mutate.js +2 -2
  243. package/dist/packages/edit-class.d.ts +2 -3
  244. package/dist/packages/edit-class.js +41 -35
  245. package/dist/packages/exports.js +4 -4
  246. package/dist/packages/fetch.js +1 -1
  247. package/dist/packages/isolation.js +2 -2
  248. package/dist/packages/licenses.js +2 -2
  249. package/dist/packages/manifest.d.ts +29 -0
  250. package/dist/packages/manifest.js +40 -4
  251. package/dist/packages/normalize.js +2 -2
  252. package/dist/packages/provenance.js +3 -3
  253. package/dist/packages/specs.js +1 -1
  254. package/dist/packages/tarball.js +4 -2
  255. package/dist/packages/types.d.ts +1 -2
  256. package/dist/paths/_internal.d.ts +1 -7
  257. package/dist/paths/_internal.js +9 -15
  258. package/dist/paths/conversion.js +1 -1
  259. package/dist/paths/dirnames.d.ts +1 -0
  260. package/dist/paths/dirnames.js +2 -0
  261. package/dist/paths/normalize.js +1 -1
  262. package/dist/paths/predicates.js +2 -1
  263. package/dist/paths/resolve.js +14 -19
  264. package/dist/paths/rewire.d.ts +5 -0
  265. package/dist/paths/socket.d.ts +137 -123
  266. package/dist/paths/socket.js +172 -131
  267. package/dist/perf/metrics.js +1 -1
  268. package/dist/perf/report.js +1 -1
  269. package/dist/primordials/process.d.ts +88 -0
  270. package/dist/primordials/process.js +132 -0
  271. package/dist/primordials/uncurry.d.ts +1 -2
  272. package/dist/process/spawn/child.js +8 -2
  273. package/dist/process/spawn/errors.js +1 -1
  274. package/dist/releases/github-archives.js +1 -1
  275. package/dist/releases/github-listing.d.ts +1 -2
  276. package/dist/schema/types.d.ts +3 -4
  277. package/dist/schema/validate.js +1 -1
  278. package/dist/secrets/broker.d.ts +35 -0
  279. package/dist/secrets/broker.js +72 -0
  280. package/dist/secrets/find.d.ts +8 -6
  281. package/dist/secrets/find.js +25 -5
  282. package/dist/secrets/keychain.d.ts +1 -1
  283. package/dist/secrets/linux.js +32 -44
  284. package/dist/secrets/macos.d.ts +1 -2
  285. package/dist/secrets/macos.js +20 -29
  286. package/dist/secrets/rc.d.ts +2 -2
  287. package/dist/secrets/rc.js +21 -13
  288. package/dist/secrets/socket-api-token.js +8 -0
  289. package/dist/secrets/windows.js +27 -33
  290. package/dist/shell/parse.d.ts +32 -0
  291. package/dist/shell/parse.js +60 -0
  292. package/dist/smol/detect.js +1 -1
  293. package/dist/smol/http.js +1 -1
  294. package/dist/smol/https.js +1 -1
  295. package/dist/smol/manifest.js +1 -1
  296. package/dist/smol/path.js +1 -1
  297. package/dist/smol/primordial.js +1 -1
  298. package/dist/smol/purl.js +1 -1
  299. package/dist/smol/versions.js +1 -1
  300. package/dist/smol/vfs.js +1 -1
  301. package/dist/sorts/_internal.d.ts +1 -2
  302. package/dist/sorts/_internal.js +2 -6
  303. package/dist/sorts/semver.js +2 -2
  304. package/dist/spinner/create-spinner-class.js +2 -2
  305. package/dist/spinner/spinner-internals.d.ts +1 -1
  306. package/dist/spinner/spinner-internals.js +9 -5
  307. package/dist/spinner/spinner.d.ts +4 -0
  308. package/dist/spinner/spinner.js +1 -1
  309. package/dist/stdio/progress.js +6 -2
  310. package/dist/stdio/prompts.d.ts +2 -10
  311. package/dist/stdio/prompts.js +11 -24
  312. package/dist/strings/format.js +1 -1
  313. package/dist/strings/search.js +1 -1
  314. package/dist/temporal/instant.js +2 -2
  315. package/dist/themes/context.d.ts +5 -3
  316. package/dist/themes/context.js +5 -6
  317. package/dist/url/assert-safe.d.ts +29 -0
  318. package/dist/url/assert-safe.js +54 -0
  319. package/dist/url/predicates.d.ts +31 -1
  320. package/dist/url/predicates.js +42 -1
  321. package/dist/url/types.d.ts +4 -0
  322. package/llms.txt +750 -0
  323. package/package.json +253 -125
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @file Availability-gated tier routing. `tier.mts` says which model+effort is
3
+ * the "perfect" choice for a unit of work; this module turns that hint into a
4
+ * concrete spawn target that ACTUALLY EXISTS on the machine. A tier resolves
5
+ * to its preferred engine only when that engine's CLI is installed AND a
6
+ * credential for it is resolvable; otherwise the resolver walks a
7
+ * cross-engine equivalence ladder (Claude → Codex → an open-weight provider
8
+ * via opencode) and returns the best available equivalent. Why gate on
9
+ * existence: a fleet machine may have Claude but no Codex, or Codex but an
10
+ * expired Claude key, or neither plus an opencode/synthetic seat. Hard-coding
11
+ * `fable` then fails at spawn time; routing here degrades gracefully and
12
+ * tells the caller WHY (the `reason`), so a skill can log "fell back to codex
13
+ * gpt-5.5 (claude unavailable)" instead of crashing. Pure given an
14
+ * availability/keyed context — no I/O — so callers fan out their `which` +
15
+ * credential probes once and pass the result in. Pairs with `buildArgs` in
16
+ * `spawn.mts`: a Fable candidate carries `effort: undefined` because Fable is
17
+ * adaptive-thinking-only and the spawn layer omits `--effort` for it anyway.
18
+ */
19
+ import type { CredentialProvider } from './credentials.mts';
20
+ import type { AiAgentName, AiEffort } from './types.mts';
21
+ import type { AiTier } from './tier.mts';
22
+ /**
23
+ * A concrete, spawnable target: which CLI engine to run, the model id, the
24
+ * reasoning effort to pass (undefined when the model ignores effort, e.g.
25
+ * Fable), and the credential provider whose key gates it.
26
+ */
27
+ export interface TierCandidate {
28
+ readonly effort: AiEffort | undefined;
29
+ readonly engine: AiAgentName;
30
+ readonly model: string;
31
+ readonly provider: CredentialProvider;
32
+ }
33
+ /**
34
+ * Why the resolver returned what it did. - `preferred` — the tier's
35
+ * first-choice engine was available + keyed. - `fell-over` — the preferred
36
+ * engine was missing/unkeyed; an equivalent on another engine was used
37
+ * (`requestedTier` names the tier originally asked for). Matches the
38
+ * `fellOver` vocabulary `spawnTierWithFallback` (spawn.mts) reports.
39
+ */
40
+ export type TierResolveReason = 'fell-over' | 'preferred';
41
+ export interface TierResolution {
42
+ readonly candidate: TierCandidate;
43
+ readonly reason: TierResolveReason;
44
+ readonly requestedTier?: AiTier | undefined;
45
+ }
46
+ /**
47
+ * The context a caller probes once and passes in: which engine CLIs exist, and
48
+ * which credential providers have a resolvable key. Both are sets so the
49
+ * resolver stays pure (no `which` / keychain I/O of its own).
50
+ */
51
+ export interface RouteContext {
52
+ readonly available: ReadonlySet<AiAgentName>;
53
+ readonly keyed: ReadonlySet<CredentialProvider>;
54
+ }
55
+ export declare const TIER_CHAINS: Readonly<Record<AiTier, readonly TierCandidate[]>>;
56
+ /**
57
+ * A candidate is usable when its engine CLI exists AND a credential for its
58
+ * provider is resolvable. Both gates matter: an installed Claude with an
59
+ * expired key is as unusable as a missing CLI.
60
+ */
61
+ export declare function isCandidateUsable(candidate: TierCandidate, ctx: RouteContext): boolean;
62
+ /**
63
+ * Resolve a tier to the best available concrete target. Prefers the tier's
64
+ * first-choice (Claude) candidate; if its engine is missing or unkeyed, walks
65
+ * the cross-engine equivalence ladder and returns the first usable equivalent,
66
+ * tagging the result `fell-over` with the original tier in `requestedTier`.
67
+ * Returns `undefined` only when NOTHING in the chain is usable — the caller
68
+ * then skips the work or surfaces a "no AI engine available" message.
69
+ */
70
+ export declare function resolveTier(tier: AiTier, ctx: RouteContext): TierResolution | undefined;
71
+ /**
72
+ * The ORDERED list of usable candidates for a tier — the runtime-fallback
73
+ * sequence. `resolveTier` returns only the single best pick (good when you
74
+ * trust it will work); this returns every usable candidate in preference order
75
+ * so a caller can advance to the next when one fails AT RUNTIME — e.g. the
76
+ * preferred model is installed + keyed (so it passes `isCandidateUsable`) yet
77
+ * its CLI reports it offline at spawn ("Claude Fable 5 is currently
78
+ * unavailable"). The static check can't predict an outage; only the spawn
79
+ * result can, so the caller walks this list until a spawn returns without the
80
+ * `unavailable` flag. Empty when nothing in the chain is usable.
81
+ */
82
+ export declare function usableTierCandidates(tier: AiTier, ctx: RouteContext): TierCandidate[];
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ /* Socket Lib - Built with rolldown */
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+ const require_ai_tier = require('./tier.js');
5
+
6
+ //#region src/ai/route.mts
7
+ /**
8
+ * @file Availability-gated tier routing. `tier.mts` says which model+effort is
9
+ * the "perfect" choice for a unit of work; this module turns that hint into a
10
+ * concrete spawn target that ACTUALLY EXISTS on the machine. A tier resolves
11
+ * to its preferred engine only when that engine's CLI is installed AND a
12
+ * credential for it is resolvable; otherwise the resolver walks a
13
+ * cross-engine equivalence ladder (Claude → Codex → an open-weight provider
14
+ * via opencode) and returns the best available equivalent. Why gate on
15
+ * existence: a fleet machine may have Claude but no Codex, or Codex but an
16
+ * expired Claude key, or neither plus an opencode/synthetic seat. Hard-coding
17
+ * `fable` then fails at spawn time; routing here degrades gracefully and
18
+ * tells the caller WHY (the `reason`), so a skill can log "fell back to codex
19
+ * gpt-5.5 (claude unavailable)" instead of crashing. Pure given an
20
+ * availability/keyed context — no I/O — so callers fan out their `which` +
21
+ * credential probes once and pass the result in. Pairs with `buildArgs` in
22
+ * `spawn.mts`: a Fable candidate carries `effort: undefined` because Fable is
23
+ * adaptive-thinking-only and the spawn layer omits `--effort` for it anyway.
24
+ */
25
+ /**
26
+ * Per-tier preference chain, most-preferred-first. The head is the "perfect"
27
+ * Claude choice from `AI_TIER`; the tail is the cross-engine equivalent ladder
28
+ * (Codex, then an open-weight provider reached through opencode). Effort is the
29
+ * shared `AiEffort` vocab; `buildArgs` translates per engine (codex clamps
30
+ * `max`→`xhigh`, Fable drops effort entirely).
31
+ *
32
+ * The Claude head reuses `AI_TIER` so a model-generation bump stays a single
33
+ * edit there. Fable's head carries `effort: undefined` — it is adaptive-only.
34
+ */
35
+ const FABLE = require_ai_tier.AI_TIER.fable;
36
+ const OPUS = require_ai_tier.AI_TIER.opus;
37
+ const SONNET = require_ai_tier.AI_TIER.sonnet;
38
+ const HAIKU = require_ai_tier.AI_TIER.haiku;
39
+ const TIER_CHAINS = {
40
+ __proto__: null,
41
+ fable: [
42
+ {
43
+ effort: void 0,
44
+ engine: "claude",
45
+ model: FABLE.model,
46
+ provider: "anthropic"
47
+ },
48
+ {
49
+ effort: "xhigh",
50
+ engine: "codex",
51
+ model: "gpt-5.5",
52
+ provider: "openai"
53
+ },
54
+ {
55
+ effort: "xhigh",
56
+ engine: "opencode",
57
+ model: "fireworks-ai/accounts/fireworks/models/glm-5p1",
58
+ provider: "fireworks"
59
+ }
60
+ ],
61
+ opus: [
62
+ {
63
+ effort: OPUS.effort,
64
+ engine: "claude",
65
+ model: OPUS.model,
66
+ provider: "anthropic"
67
+ },
68
+ {
69
+ effort: "high",
70
+ engine: "codex",
71
+ model: "gpt-5.5",
72
+ provider: "openai"
73
+ },
74
+ {
75
+ effort: "high",
76
+ engine: "opencode",
77
+ model: "fireworks-ai/accounts/fireworks/models/glm-5p1",
78
+ provider: "fireworks"
79
+ }
80
+ ],
81
+ sonnet: [
82
+ {
83
+ effort: SONNET.effort,
84
+ engine: "claude",
85
+ model: SONNET.model,
86
+ provider: "anthropic"
87
+ },
88
+ {
89
+ effort: "medium",
90
+ engine: "codex",
91
+ model: "gpt-5.5",
92
+ provider: "openai"
93
+ },
94
+ {
95
+ effort: "medium",
96
+ engine: "opencode",
97
+ model: "synthetic/hf:moonshotai/Kimi-K2.5",
98
+ provider: "synthetic"
99
+ }
100
+ ],
101
+ haiku: [
102
+ {
103
+ effort: HAIKU.effort,
104
+ engine: "claude",
105
+ model: HAIKU.model,
106
+ provider: "anthropic"
107
+ },
108
+ {
109
+ effort: "low",
110
+ engine: "codex",
111
+ model: "gpt-5.5",
112
+ provider: "openai"
113
+ },
114
+ {
115
+ effort: "low",
116
+ engine: "opencode",
117
+ model: "synthetic/hf:moonshotai/Kimi-K2.5",
118
+ provider: "synthetic"
119
+ }
120
+ ]
121
+ };
122
+ /**
123
+ * A candidate is usable when its engine CLI exists AND a credential for its
124
+ * provider is resolvable. Both gates matter: an installed Claude with an
125
+ * expired key is as unusable as a missing CLI.
126
+ */
127
+ function isCandidateUsable(candidate, ctx) {
128
+ return ctx.available.has(candidate.engine) && ctx.keyed.has(candidate.provider);
129
+ }
130
+ /**
131
+ * Resolve a tier to the best available concrete target. Prefers the tier's
132
+ * first-choice (Claude) candidate; if its engine is missing or unkeyed, walks
133
+ * the cross-engine equivalence ladder and returns the first usable equivalent,
134
+ * tagging the result `fell-over` with the original tier in `requestedTier`.
135
+ * Returns `undefined` only when NOTHING in the chain is usable — the caller
136
+ * then skips the work or surfaces a "no AI engine available" message.
137
+ */
138
+ function resolveTier(tier, ctx) {
139
+ const chain = TIER_CHAINS[tier] ?? TIER_CHAINS.sonnet;
140
+ for (let i = 0, { length } = chain; i < length; i += 1) {
141
+ const candidate = chain[i];
142
+ if (isCandidateUsable(candidate, ctx)) return i === 0 ? {
143
+ candidate,
144
+ reason: "preferred"
145
+ } : {
146
+ candidate,
147
+ requestedTier: tier,
148
+ reason: "fell-over"
149
+ };
150
+ }
151
+ }
152
+ /**
153
+ * The ORDERED list of usable candidates for a tier — the runtime-fallback
154
+ * sequence. `resolveTier` returns only the single best pick (good when you
155
+ * trust it will work); this returns every usable candidate in preference order
156
+ * so a caller can advance to the next when one fails AT RUNTIME — e.g. the
157
+ * preferred model is installed + keyed (so it passes `isCandidateUsable`) yet
158
+ * its CLI reports it offline at spawn ("Claude Fable 5 is currently
159
+ * unavailable"). The static check can't predict an outage; only the spawn
160
+ * result can, so the caller walks this list until a spawn returns without the
161
+ * `unavailable` flag. Empty when nothing in the chain is usable.
162
+ */
163
+ function usableTierCandidates(tier, ctx) {
164
+ return (TIER_CHAINS[tier] ?? TIER_CHAINS.sonnet).filter((c) => isCandidateUsable(c, ctx));
165
+ }
166
+
167
+ //#endregion
168
+ exports.TIER_CHAINS = TIER_CHAINS;
169
+ exports.isCandidateUsable = isCandidateUsable;
170
+ exports.resolveTier = resolveTier;
171
+ exports.usableTierCandidates = usableTierCandidates;
@@ -11,6 +11,8 @@
11
11
  * SDK installs. Retry: 3 attempts on overload (HTTP 529 / "Overloaded"), exp.
12
12
  * backoff (5s / 15s / 45s). Each retry is a fresh subprocess.
13
13
  */
14
+ import type { RouteContext, TierCandidate } from './route.mts';
15
+ import type { AiTier } from './tier.mts';
14
16
  import type { AgentSpawnResult, AiAgentName, SpawnAiAgentOptions } from './types.mts';
15
17
  export declare function backoffFor(attempt: number): number;
16
18
  /**
@@ -22,7 +24,16 @@ export declare function backoffFor(attempt: number): number;
22
24
  * Update sites (when an agent changes its flag surface): 1. The relevant case
23
25
  * below. 2. The agent's docs link (cited inline).
24
26
  */
25
- export declare function buildArgs(agent: AiAgentName, opts: SpawnAiAgentOptions): string[];
27
+ export declare function buildArgs(agent: AiAgentName, options: SpawnAiAgentOptions): string[];
28
+ /**
29
+ * Fable and Mythos run adaptive thinking only — thinking is always on and there
30
+ * is no manual thinking-budget knob. The effort dial does not apply the way it
31
+ * does on Opus, so the spawn layer drops `--effort` for these models rather
32
+ * than passing a level they should ignore. Matches both alias and full-id
33
+ * shapes (`fable`, `claude-fable-5`, `mythos`, `claude-mythos-5`).
34
+ */
35
+ export declare function isAdaptiveOnlyModel(model: string): boolean;
36
+ export declare function isModelUnavailable(stdout: string, stderr: string): boolean;
26
37
  export declare function isOverloaded(stdout: string, stderr: string): boolean;
27
38
  export declare function pickAgent(requested: AiAgentName | undefined, cwd: string): Promise<AiAgentName>;
28
39
  /**
@@ -46,4 +57,33 @@ export declare function pickAgent(requested: AiAgentName | undefined, cwd: strin
46
57
  * Throws when the requested agent isn't on PATH (or, when no agent
47
58
  * is requested, when none of the known agents are on PATH).
48
59
  */
49
- export declare function spawnAiAgent(opts: SpawnAiAgentOptions): Promise<AgentSpawnResult>;
60
+ export declare function spawnAiAgent(options: SpawnAiAgentOptions): Promise<AgentSpawnResult>;
61
+ /**
62
+ * Result of a tier spawn that may have fallen over one or more offline models.
63
+ * `result` is the spawn that actually ran (the first whose model was not
64
+ * `unavailable`, or the last attempt if every candidate was down). `candidate`
65
+ * is the engine/model that produced it. `fellOver` lists the candidates that
66
+ * reported their model offline before this one — empty on a first-try success.
67
+ */
68
+ export interface TierSpawnResult {
69
+ readonly candidate: TierCandidate;
70
+ readonly fellOver: readonly TierCandidate[];
71
+ readonly result: AgentSpawnResult;
72
+ }
73
+ /**
74
+ * Spawn a tier's work, automatically FALLING OVER to the next agent when a
75
+ * model is offline. Walks the tier's usable candidates (Claude → Codex →
76
+ * open-weight) in order; if a spawn comes back with `unavailable` (the model is
77
+ * down or gated — e.g. "Claude Fable 5 is currently unavailable"), it advances
78
+ * to the next candidate instead of failing. This is the runtime complement to
79
+ * `route.mts`'s static availability check: that check can't predict an outage,
80
+ * so the live spawn result drives the fallback.
81
+ *
82
+ * Returns the first non-`unavailable` spawn (success OR a genuine work failure
83
+ * on a model that WAS reachable — a real failure shouldn't silently retry on a
84
+ * weaker model). If every candidate is offline, returns the last attempt with
85
+ * its `unavailable` flag set, so the caller can report "all models down".
86
+ * Throws only when the tier has no usable candidate at all (nothing installed +
87
+ * keyed) — same contract as `resolveTier` returning undefined.
88
+ */
89
+ export declare function spawnTierWithFallback(tier: AiTier, ctx: RouteContext, options: Omit<SpawnAiAgentOptions, 'agent' | 'effort' | 'model'>): Promise<TierSpawnResult>;
package/dist/ai/spawn.js CHANGED
@@ -2,13 +2,14 @@
2
2
  /* Socket Lib - Built with rolldown */
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
  const require_primordials_error = require('../primordials/error.js');
5
- const require_primordials_date = require('../primordials/date.js');
6
5
  const require_primordials_object = require('../primordials/object.js');
6
+ const require_primordials_date = require('../primordials/date.js');
7
7
  const require_errors_message = require('../errors/message.js');
8
- const require_ai_discover = require('./discover.js');
9
8
  const require_process_spawn_errors = require('../process/spawn/errors.js');
10
9
  const require_process_spawn_child = require('../process/spawn/child.js');
10
+ const require_ai_discover = require('./discover.js');
11
11
  const require_primordials_promise = require('../primordials/promise.js');
12
+ const require_ai_route = require('./route.js');
12
13
 
13
14
  //#region src/ai/spawn.mts
14
15
  /**
@@ -38,63 +39,120 @@ function backoffFor(attempt) {
38
39
  * Update sites (when an agent changes its flag surface): 1. The relevant case
39
40
  * below. 2. The agent's docs link (cited inline).
40
41
  */
41
- function buildArgs(agent, opts) {
42
- const allAllowed = [...opts.tools, ...opts.allow ?? []];
42
+ function buildArgs(agent, options) {
43
+ options = {
44
+ __proto__: null,
45
+ ...options
46
+ };
47
+ const allAllowed = [...options.tools, ...options.allow ?? []];
43
48
  switch (agent) {
44
49
  case "claude": {
45
50
  const args = [
46
51
  "--print",
47
52
  "--no-session-persistence",
48
53
  "--permission-mode",
49
- opts.permissionMode,
54
+ options.permissionMode,
50
55
  "--add-dir",
51
- opts.cwd
56
+ options.cwd
52
57
  ];
53
- for (const dir of opts.addDirs ?? []) args.push("--add-dir", dir);
54
- if (opts.model) args.push("--model", opts.model);
55
- if (opts.effort) args.push("--effort", opts.effort);
58
+ for (const dir of options.addDirs ?? []) args.push("--add-dir", dir);
59
+ if (options.model) args.push("--model", options.model);
60
+ if (options.effort && !isAdaptiveOnlyModel(options.model ?? "")) args.push("--effort", options.effort);
56
61
  if (allAllowed.length > 0) args.push("--allowedTools", ...allAllowed);
57
- if (opts.disallow.length > 0) args.push("--disallowedTools", ...opts.disallow);
58
- if (opts.extraArgs) args.push(...opts.extraArgs);
62
+ if (options.disallow.length > 0) args.push("--disallowedTools", ...options.disallow);
63
+ if (options.extraArgs) args.push(...options.extraArgs);
59
64
  return args;
60
65
  }
61
66
  case "codex": {
62
67
  const args = ["--print"];
63
- if (opts.permissionMode === "plan") args.push("--read-only");
64
- if (opts.model) args.push("--model", opts.model);
68
+ if (options.permissionMode === "plan") args.push("--read-only");
69
+ if (options.model) args.push("--model", options.model);
70
+ if (options.effort) {
71
+ const codexEffort = options.effort === "max" ? "xhigh" : options.effort;
72
+ args.push("-c", `model_reasoning_effort=${codexEffort}`);
73
+ }
65
74
  if (allAllowed.length > 0) args.push("--tools", allAllowed.join(","));
66
- if (opts.disallow.length > 0) args.push("--disallow-tools", opts.disallow.join(","));
67
- args.push("--cwd", opts.cwd);
68
- if (opts.extraArgs) args.push(...opts.extraArgs);
75
+ if (options.disallow.length > 0) args.push("--disallow-tools", options.disallow.join(","));
76
+ args.push("--cwd", options.cwd);
77
+ if (options.extraArgs) args.push(...options.extraArgs);
69
78
  return args;
70
79
  }
71
80
  case "gemini": {
72
81
  const args = [
73
82
  "--no-interactive",
74
83
  "--workspace",
75
- opts.cwd
84
+ options.cwd
76
85
  ];
77
- if (opts.model) args.push("--model", opts.model);
86
+ if (options.model) args.push("--model", options.model);
78
87
  if (allAllowed.length > 0) args.push("--allowed-tools", allAllowed.join(","));
79
- if (opts.disallow.length > 0) args.push("--denied-tools", opts.disallow.join(","));
80
- if (opts.permissionMode === "plan") args.push("--read-only");
81
- if (opts.extraArgs) args.push(...opts.extraArgs);
88
+ if (options.disallow.length > 0) args.push("--denied-tools", options.disallow.join(","));
89
+ if (options.permissionMode === "plan") args.push("--read-only");
90
+ if (options.extraArgs) args.push(...options.extraArgs);
82
91
  return args;
83
92
  }
84
93
  case "opencode": {
85
94
  const args = [
86
95
  "--print",
87
96
  "--cwd",
88
- opts.cwd
97
+ options.cwd
89
98
  ];
90
- if (opts.model) args.push("--model", opts.model);
99
+ if (options.model) args.push("--model", options.model);
91
100
  if (allAllowed.length > 0) args.push("--tools", allAllowed.join(","));
92
- if (opts.disallow.length > 0) args.push("--no-tools", opts.disallow.join(","));
93
- if (opts.extraArgs) args.push(...opts.extraArgs);
101
+ if (options.disallow.length > 0) args.push("--no-tools", options.disallow.join(","));
102
+ if (options.extraArgs) args.push(...options.extraArgs);
94
103
  return args;
95
104
  }
96
105
  }
97
106
  }
107
+ /**
108
+ * Fable and Mythos run adaptive thinking only — thinking is always on and there
109
+ * is no manual thinking-budget knob. The effort dial does not apply the way it
110
+ * does on Opus, so the spawn layer drops `--effort` for these models rather
111
+ * than passing a level they should ignore. Matches both alias and full-id
112
+ * shapes (`fable`, `claude-fable-5`, `mythos`, `claude-mythos-5`).
113
+ */
114
+ function isAdaptiveOnlyModel(model) {
115
+ return /\b(?:fable|mythos)\b/i.test(model) || /claude-(?:fable|mythos)/i.test(model);
116
+ }
117
+ const MODEL_UNAVAILABLE_PHRASES = [
118
+ "access denied",
119
+ "currently unavailable",
120
+ "forbidden",
121
+ "have access",
122
+ "is unavailable",
123
+ "isn’t available",
124
+ "isn't available",
125
+ "may not exist",
126
+ "no access to",
127
+ "no such model",
128
+ "not authorized",
129
+ "not authorised",
130
+ "not available",
131
+ "permission denied",
132
+ "permission_denied",
133
+ "temporarily unavailable",
134
+ "unauthorized",
135
+ "unauthorised"
136
+ ];
137
+ const MODEL_EXISTENCE_PHRASES = [
138
+ "does not exist",
139
+ "doesn't exist",
140
+ "no such",
141
+ "not exist",
142
+ "not found",
143
+ "unavailable",
144
+ "unknown",
145
+ "unreachable"
146
+ ];
147
+ function isModelUnavailable(stdout, stderr) {
148
+ const text = `${stdout}\n${stderr}`.toLowerCase();
149
+ for (let i = 0, { length } = MODEL_UNAVAILABLE_PHRASES; i < length; i += 1) if (text.includes(MODEL_UNAVAILABLE_PHRASES[i])) return true;
150
+ if (/\bmodel[_-]?not[_-]?found\b/i.test(text) || /\bapi error:\s*(?:403|404)\b/i.test(text)) return true;
151
+ if (text.includes("model")) {
152
+ for (let i = 0, { length } = MODEL_EXISTENCE_PHRASES; i < length; i += 1) if (text.includes(MODEL_EXISTENCE_PHRASES[i])) return true;
153
+ }
154
+ return false;
155
+ }
98
156
  function isOverloaded(stdout, stderr) {
99
157
  const re = /API Error: 529|Overloaded/i;
100
158
  return re.test(stdout) || re.test(stderr);
@@ -134,9 +192,13 @@ async function pickAgent(requested, cwd) {
134
192
  * Throws when the requested agent isn't on PATH (or, when no agent
135
193
  * is requested, when none of the known agents are on PATH).
136
194
  */
137
- async function spawnAiAgent(opts) {
138
- const agent = await pickAgent(opts.agent, opts.cwd);
139
- const args = buildArgs(agent, opts);
195
+ async function spawnAiAgent(options) {
196
+ options = {
197
+ __proto__: null,
198
+ ...options
199
+ };
200
+ const agent = await pickAgent(options.agent, options.cwd);
201
+ const args = buildArgs(agent, options);
140
202
  let stdout = "";
141
203
  let stderr = "";
142
204
  let exitCode = 0;
@@ -149,12 +211,12 @@ async function spawnAiAgent(opts) {
149
211
  exitCode = 0;
150
212
  try {
151
213
  const child = require_process_spawn_child.spawn(agent, args, {
152
- cwd: opts.cwd,
214
+ cwd: options.cwd,
153
215
  stdio: "pipe",
154
216
  stdioString: true,
155
- timeout: opts.timeoutMs
217
+ timeout: options.timeoutMs
156
218
  });
157
- child.stdin?.end(opts.prompt);
219
+ child.stdin?.end(options.prompt);
158
220
  const result = await child;
159
221
  stdout = String(result.stdout ?? "");
160
222
  stderr = String(result.stderr ?? "");
@@ -176,14 +238,65 @@ async function spawnAiAgent(opts) {
176
238
  attempts,
177
239
  durationMs: require_primordials_date.DateNow() - start,
178
240
  exitCode,
241
+ overloaded: isOverloaded(stdout, stderr),
179
242
  stderr,
180
- stdout
243
+ stdout,
244
+ unavailable: isModelUnavailable(stdout, stderr)
245
+ };
246
+ }
247
+ /**
248
+ * Spawn a tier's work, automatically FALLING OVER to the next agent when a
249
+ * model is offline. Walks the tier's usable candidates (Claude → Codex →
250
+ * open-weight) in order; if a spawn comes back with `unavailable` (the model is
251
+ * down or gated — e.g. "Claude Fable 5 is currently unavailable"), it advances
252
+ * to the next candidate instead of failing. This is the runtime complement to
253
+ * `route.mts`'s static availability check: that check can't predict an outage,
254
+ * so the live spawn result drives the fallback.
255
+ *
256
+ * Returns the first non-`unavailable` spawn (success OR a genuine work failure
257
+ * on a model that WAS reachable — a real failure shouldn't silently retry on a
258
+ * weaker model). If every candidate is offline, returns the last attempt with
259
+ * its `unavailable` flag set, so the caller can report "all models down".
260
+ * Throws only when the tier has no usable candidate at all (nothing installed +
261
+ * keyed) — same contract as `resolveTier` returning undefined.
262
+ */
263
+ async function spawnTierWithFallback(tier, ctx, options) {
264
+ const candidates = require_ai_route.usableTierCandidates(tier, ctx);
265
+ if (candidates.length === 0) throw new require_primordials_error.ErrorCtor(`spawnTierWithFallback: no usable agent for tier "${tier}". No candidate engine is both installed and keyed (checked: ${candidates.length}). Install/authenticate one of the tier's engines, or pick a different tier.`);
266
+ const fellOver = [];
267
+ let last;
268
+ for (let i = 0, { length } = candidates; i < length; i += 1) {
269
+ const candidate = candidates[i];
270
+ const result = await spawnAiAgent({
271
+ ...options,
272
+ agent: candidate.engine,
273
+ effort: candidate.effort,
274
+ model: candidate.model
275
+ });
276
+ last = {
277
+ candidate,
278
+ result
279
+ };
280
+ if (!result.unavailable) return {
281
+ candidate,
282
+ fellOver,
283
+ result
284
+ };
285
+ fellOver.push(candidate);
286
+ }
287
+ return {
288
+ candidate: last.candidate,
289
+ fellOver: fellOver.slice(0, -1),
290
+ result: last.result
181
291
  };
182
292
  }
183
293
 
184
294
  //#endregion
185
295
  exports.backoffFor = backoffFor;
186
296
  exports.buildArgs = buildArgs;
297
+ exports.isAdaptiveOnlyModel = isAdaptiveOnlyModel;
298
+ exports.isModelUnavailable = isModelUnavailable;
187
299
  exports.isOverloaded = isOverloaded;
188
300
  exports.pickAgent = pickAgent;
189
- exports.spawnAiAgent = spawnAiAgent;
301
+ exports.spawnAiAgent = spawnAiAgent;
302
+ exports.spawnTierWithFallback = spawnTierWithFallback;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @file The terminal-status contract a delegated subagent returns to its
3
+ * orchestrator. Subagent-driven development depends on a SMALL, fixed status
4
+ * vocabulary so the orchestrator can route deterministically instead of
5
+ * parsing free-form prose: a subagent that "sort of finished but has a worry"
6
+ * must be distinguishable from one that is genuinely blocked, because they
7
+ * escalate differently. The four states and their escalation paths are the
8
+ * contract; `escalationFor` is the single place that maps a state to what the
9
+ * orchestrator does next. Encoding it as a typed union + map (rather than a
10
+ * doc convention) is the code-is-law surface: a stray status string fails the
11
+ * guard, and `agent-delegation.md` is checked against this union so the prose
12
+ * can't drift from the code.
13
+ */
14
+ /**
15
+ * A subagent's terminal status.
16
+ *
17
+ * - `done` — work complete, no reservations; the orchestrator advances.
18
+ * - `done-with-concerns` — work complete but the subagent flagged a risk or
19
+ * follow-up the orchestrator should surface before advancing.
20
+ * - `needs-context` — the subagent lacks information it cannot obtain itself; the
21
+ * orchestrator supplies it and re-dispatches (a fresh attempt, not the same
22
+ * model retrying blind).
23
+ * - `blocked` — the work cannot proceed without a decision or action only the
24
+ * user can provide; the orchestrator escalates to the user and stops.
25
+ */
26
+ export type SubagentStatus = 'blocked' | 'done' | 'done-with-concerns' | 'needs-context';
27
+ /**
28
+ * What the orchestrator does for each terminal status. `advance` continues to
29
+ * the next unit of work; `surface` advances but raises the concern first;
30
+ * `redispatch` re-runs the unit with the missing context added; `escalate`
31
+ * stops and hands the decision to the user.
32
+ */
33
+ export type SubagentEscalation = 'advance' | 'escalate' | 'redispatch' | 'surface';
34
+ /**
35
+ * The canonical status set, sorted, for callers that need to enumerate or
36
+ * validate against the full vocabulary (the doc-parity check reads this).
37
+ */
38
+ export declare const SUBAGENT_STATUSES: readonly SubagentStatus[];
39
+ /**
40
+ * Map a terminal status to the orchestrator action it requires. A status
41
+ * outside the vocabulary is itself a contract violation, so this throws rather
42
+ * than guessing — never force a retry on an unrecognized state.
43
+ */
44
+ export declare function escalationFor(status: SubagentStatus): SubagentEscalation;
45
+ /**
46
+ * True when `value` names a status in the contract.
47
+ */
48
+ export declare function isSubagentStatus(value: string): value is SubagentStatus;