@aiwg/cli 2026.10.1 → 2026.10.4

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 (361) hide show
  1. package/README.md +2 -2
  2. package/agentic/code/providers/capability-matrix.yaml +270 -0
  3. package/agentic/code/providers/model-capabilities.v1.json +3183 -24
  4. package/bin/aiwg.mjs +135 -47
  5. package/dist/src/a2a/codecs.js +9 -0
  6. package/dist/src/agents/grounding/knowledge-base.js +54 -6
  7. package/dist/src/artifacts/browser-export.js +6 -0
  8. package/dist/src/artifacts/checksum-manifest.js +1 -0
  9. package/dist/src/artifacts/citation-parser.js +173 -92
  10. package/dist/src/artifacts/citation-table-schema.js +59 -0
  11. package/dist/src/artifacts/cli.js +57 -18
  12. package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
  13. package/dist/src/artifacts/corpus-tools/vision-extract.js +107 -15
  14. package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
  15. package/dist/src/artifacts/corpus-views/renderers.js +3 -3
  16. package/dist/src/artifacts/discovery-eval.js +6 -4
  17. package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
  18. package/dist/src/artifacts/fortemi-core-sync.js +166 -40
  19. package/dist/src/artifacts/framework-capabilities.js +171 -0
  20. package/dist/src/artifacts/framework-index-paths.js +73 -0
  21. package/dist/src/artifacts/framework-source-digest.js +75 -0
  22. package/dist/src/artifacts/index-builder.js +285 -131
  23. package/dist/src/artifacts/index-files.js +132 -18
  24. package/dist/src/artifacts/index-preparation.js +65 -0
  25. package/dist/src/artifacts/index-refresh.js +576 -0
  26. package/dist/src/artifacts/index-worker.mjs +9 -0
  27. package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
  28. package/dist/src/artifacts/prebuilt-deployment.js +46 -0
  29. package/dist/src/artifacts/prebuilt-relations.js +80 -0
  30. package/dist/src/artifacts/query-engine.js +410 -88
  31. package/dist/src/artifacts/relations-builder.js +168 -0
  32. package/dist/src/artifacts/relations.js +148 -0
  33. package/dist/src/artifacts/repair.js +9 -4
  34. package/dist/src/artifacts/stats.js +5 -2
  35. package/dist/src/artifacts/types.js +30 -10
  36. package/dist/src/artifacts/watcher.js +1 -1
  37. package/dist/src/auth/credential-store.js +2 -1
  38. package/dist/src/catalog/cli.d.mts +5 -0
  39. package/dist/src/channel/manager.d.mts +20 -0
  40. package/dist/src/channel/manager.mjs +78 -12
  41. package/dist/src/cli/child-process-result.js +40 -0
  42. package/dist/src/cli/command-log.js +2 -3
  43. package/dist/src/cli/env.js +38 -16
  44. package/dist/src/cli/flag-parsing.js +236 -0
  45. package/dist/src/cli/handlers/artifacts.js +3 -0
  46. package/dist/src/cli/handlers/auth.js +3 -0
  47. package/dist/src/cli/handlers/decision.js +218 -5
  48. package/dist/src/cli/handlers/diagnose.js +13 -5
  49. package/dist/src/cli/handlers/effect.js +4 -2
  50. package/dist/src/cli/handlers/evidence.js +3 -0
  51. package/dist/src/cli/handlers/feedback.js +14 -5
  52. package/dist/src/cli/handlers/help.js +1 -0
  53. package/dist/src/cli/handlers/index.js +3 -1
  54. package/dist/src/cli/handlers/init.js +248 -30
  55. package/dist/src/cli/handlers/lint.js +5 -0
  56. package/dist/src/cli/handlers/mc.js +23 -0
  57. package/dist/src/cli/handlers/models.js +169 -10
  58. package/dist/src/cli/handlers/ralph-launcher.js +2 -0
  59. package/dist/src/cli/handlers/ralph.js +3 -0
  60. package/dist/src/cli/handlers/refresh.js +28 -0
  61. package/dist/src/cli/handlers/regenerate.js +14 -0
  62. package/dist/src/cli/handlers/resource-versions.js +3 -0
  63. package/dist/src/cli/handlers/rules.js +195 -0
  64. package/dist/src/cli/handlers/run.js +4 -0
  65. package/dist/src/cli/handlers/runtime-info.js +25 -11
  66. package/dist/src/cli/handlers/script-runner.js +19 -8
  67. package/dist/src/cli/handlers/session.js +406 -62
  68. package/dist/src/cli/handlers/sessions.js +243 -76
  69. package/dist/src/cli/handlers/setup-manifest.js +474 -79
  70. package/dist/src/cli/handlers/setup.js +180 -39
  71. package/dist/src/cli/handlers/steward.js +11 -0
  72. package/dist/src/cli/handlers/subcommands.js +60 -3
  73. package/dist/src/cli/handlers/team.js +18 -8
  74. package/dist/src/cli/handlers/uhp.js +3 -0
  75. package/dist/src/cli/handlers/use.js +307 -55
  76. package/dist/src/cli/handlers/utilities.js +125 -26
  77. package/dist/src/cli/handlers/version.js +8 -0
  78. package/dist/src/cli/prompt-utils.js +72 -0
  79. package/dist/src/cli/provider-resolution.js +11 -0
  80. package/dist/src/cli/router.js +15 -1
  81. package/dist/src/cli/services/deployment-verification.js +19 -9
  82. package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
  83. package/dist/src/cli/skill-usage.js +2 -3
  84. package/dist/src/config/aiwg-config.js +349 -35
  85. package/dist/src/config/cli.js +256 -23
  86. package/dist/src/config/decision-config.js +106 -0
  87. package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
  88. package/dist/src/config/dispatch-thresholds-runtime.mjs +38 -0
  89. package/dist/src/config/gitignore.js +50 -0
  90. package/dist/src/config/index-graph-overrides.js +36 -0
  91. package/dist/src/config/project-artifacts-health.d.mts +37 -0
  92. package/dist/src/config/project-artifacts-health.mjs +14 -3
  93. package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
  94. package/dist/src/config/user-config-dir.d.mts +9 -0
  95. package/dist/src/config/user-config.js +38 -11
  96. package/dist/src/config/user-registry.js +23 -15
  97. package/dist/src/config/user-state.js +7 -0
  98. package/dist/src/decision/adapters/jev.js +75 -27
  99. package/dist/src/decision/ask.js +203 -43
  100. package/dist/src/decision/context-live-qualification.js +2 -2
  101. package/dist/src/decision/driver.js +14 -7
  102. package/dist/src/decision/ensemble/aggregate.js +23 -10
  103. package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
  104. package/dist/src/decision/entry.js +25 -6
  105. package/dist/src/decision/graph-live-qualification.js +1 -1
  106. package/dist/src/decision/graph-run.js +9 -0
  107. package/dist/src/decision/heldout/collector.js +15 -14
  108. package/dist/src/decision/heldout/contract.js +30 -7
  109. package/dist/src/decision/index.js +1 -0
  110. package/dist/src/decision/interop.js +60 -8
  111. package/dist/src/decision/jev-credentials.js +15 -1
  112. package/dist/src/decision/ledger.js +942 -0
  113. package/dist/src/decision/offload-activation.js +137 -0
  114. package/dist/src/decision/offload.js +550 -0
  115. package/dist/src/decision/qualification/load.js +4 -6
  116. package/dist/src/decision/savings.js +28 -0
  117. package/dist/src/decision/validate.js +6 -3
  118. package/dist/src/effects/dispatch-verifier.js +252 -0
  119. package/dist/src/effects/index.js +1 -0
  120. package/dist/src/effects/types.js +5 -1
  121. package/dist/src/effects/verifiers/git.js +2 -1
  122. package/dist/src/effects/verifiers/tracker.js +26 -14
  123. package/dist/src/extensions/commands/definitions.js +19 -0
  124. package/dist/src/extensions/project-local-remove.js +36 -1
  125. package/dist/src/features/installer.js +2 -2
  126. package/dist/src/flow/graph-metadata.js +5 -0
  127. package/dist/src/gates/providers/loader.js +64 -18
  128. package/dist/src/installation/manager-command.d.mts +18 -0
  129. package/dist/src/installation/manager-command.mjs +15 -3
  130. package/dist/src/installation/manager.d.mts +49 -0
  131. package/dist/src/installation/manager.mjs +95 -5
  132. package/dist/src/issues/cli.js +4 -4
  133. package/dist/src/issues/local.js +24 -5
  134. package/dist/src/jobs/runner.js +1 -1
  135. package/dist/src/lint/cli.js +27 -1
  136. package/dist/src/lint/loader.js +2 -1
  137. package/dist/src/lint/reporters.js +25 -1
  138. package/dist/src/lint/rule-activation.js +43 -0
  139. package/dist/src/lint/runner.js +137 -62
  140. package/dist/src/mcp/adapters/codex-runtime.js +366 -56
  141. package/dist/src/mcp/claude-install.d.mts +4 -0
  142. package/dist/src/mcp/claude-install.mjs +41 -0
  143. package/dist/src/mcp/cli.d.mts +1 -0
  144. package/dist/src/mcp/cli.mjs +620 -85
  145. package/dist/src/mcp/config-file.d.mts +28 -0
  146. package/dist/src/mcp/config-file.mjs +279 -0
  147. package/dist/src/mcp/config-layers.d.mts +36 -0
  148. package/dist/src/mcp/config-layers.mjs +348 -0
  149. package/dist/src/mcp/credentials.d.mts +51 -0
  150. package/dist/src/mcp/credentials.mjs +484 -0
  151. package/dist/src/mcp/grok-build-config.d.mts +6 -0
  152. package/dist/src/mcp/grok-build-config.mjs +17 -27
  153. package/dist/src/mcp/helpers.mjs +109 -4
  154. package/dist/src/mcp/muse-native-config.d.mts +13 -0
  155. package/dist/src/mcp/muse-native-config.mjs +1 -0
  156. package/dist/src/mcp/omp-config.d.mts +4 -0
  157. package/dist/src/mcp/omp-config.mjs +50 -29
  158. package/dist/src/mcp/profiles.js +97 -23
  159. package/dist/src/mcp/profiles.mjs +99 -27
  160. package/dist/src/mcp/registry.js +248 -131
  161. package/dist/src/mcp/registry.mjs +169 -100
  162. package/dist/src/mcp/server-config.d.mts +3 -0
  163. package/dist/src/mcp/server-config.mjs +89 -0
  164. package/dist/src/mcp/server.mjs +127 -82
  165. package/dist/src/mcp/test-simple.mjs +2 -1
  166. package/dist/src/mcp/toml-editor.d.mts +4 -0
  167. package/dist/src/mcp/toml-string.d.mts +1 -0
  168. package/dist/src/mcp/toml-string.mjs +9 -0
  169. package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
  170. package/dist/src/mcp/toml-strip-mcp.mjs +135 -0
  171. package/dist/src/mcp/tool-filters.d.mts +46 -0
  172. package/dist/src/mcp/tool-filters.mjs +357 -0
  173. package/dist/src/mcp/tools/agentic-sandbox.mjs +3 -1
  174. package/dist/src/mcp/tools/decision.mjs +22 -3
  175. package/dist/src/mcp/tools/discovery.mjs +62 -55
  176. package/dist/src/mcp/tools/orchestration.mjs +50 -2
  177. package/dist/src/mcp/tools/subsystems.mjs +39 -8
  178. package/dist/src/mcp/tools/worker-invoke.mjs +2856 -0
  179. package/dist/src/mcp/tools/worker-shell-control.mjs +289 -0
  180. package/dist/src/mcp/tools/worker-stdin-runtime.mjs +79 -0
  181. package/dist/src/memory/project-registry.js +2 -2
  182. package/dist/src/mission-protocol/codecs.js +647 -1
  183. package/dist/src/mission-protocol/types.js +110 -0
  184. package/dist/src/mission-protocol/worker-status.js +2 -0
  185. package/dist/src/models/config-loader.js +76 -14
  186. package/dist/src/models/grok-build-models.js +93 -41
  187. package/dist/src/models/model-capabilities.v1.json +3183 -24
  188. package/dist/src/models/model-discovery.js +931 -67
  189. package/dist/src/models/provider-policy.js +719 -11
  190. package/dist/src/models/qualification-digest.d.mts +2 -0
  191. package/dist/src/models/qualification-digest.mjs +17 -0
  192. package/dist/src/models/resolver.js +261 -0
  193. package/dist/src/models/worker-direct-readiness.js +550 -0
  194. package/dist/src/models/worker-dispatch-offer.js +169 -0
  195. package/dist/src/models/worker-health-readiness.js +144 -0
  196. package/dist/src/models/worker-installation.d.mts +39 -0
  197. package/dist/src/models/worker-installation.mjs +986 -0
  198. package/dist/src/models/wrapper-route.js +18 -0
  199. package/dist/src/ops/registry.js +9 -14
  200. package/dist/src/plugins/standalone-packager.js +4 -3
  201. package/dist/src/process/bounded-child-process.d.mts +84 -0
  202. package/dist/src/process/bounded-child-process.mjs +430 -0
  203. package/dist/src/process/cli-command.d.mts +16 -0
  204. package/dist/src/process/cli-command.mjs +75 -0
  205. package/dist/src/process/signal-child.d.mts +6 -0
  206. package/dist/src/process/signal-child.mjs +7 -0
  207. package/dist/src/providers/capability-matrix.js +8 -0
  208. package/dist/src/providers/capability-matrix.yaml +270 -0
  209. package/dist/src/providers/deployed-skill-roots.js +20 -0
  210. package/dist/src/providers/grok-build-acp.js +3 -2
  211. package/dist/src/providers/grok-build-headless.js +53 -23
  212. package/dist/src/providers/grok-build-inspect.js +1 -0
  213. package/dist/src/providers/omp-agent.d.mts +8 -0
  214. package/dist/src/providers/omp-diagnostics.d.mts +1 -0
  215. package/dist/src/providers/omp-paths.d.mts +13 -0
  216. package/dist/src/providers/provider-definitions.js +9 -1
  217. package/dist/src/providers/provider-definitions.mjs +9 -2
  218. package/dist/src/providers/skill-ownership.d.mts +9 -0
  219. package/dist/src/providers/skill-ownership.mjs +88 -0
  220. package/dist/src/rules/activation.d.mts +21 -0
  221. package/dist/src/rules/activation.mjs +62 -0
  222. package/dist/src/rules/inline-budget.d.mts +26 -0
  223. package/dist/src/rules/inline-budget.mjs +66 -0
  224. package/dist/src/rules/inventory.js +129 -0
  225. package/dist/src/rules/pin-state.js +73 -0
  226. package/dist/src/rules/pins.d.mts +14 -0
  227. package/dist/src/rules/pins.mjs +112 -0
  228. package/dist/src/rules/rule-frontmatter.schema.json +197 -0
  229. package/dist/src/serve/executor-registry.js +16 -24
  230. package/dist/src/serve/fleet-mission-conductor.js +9 -0
  231. package/dist/src/serve/mission-conductor.js +47 -12
  232. package/dist/src/serve/shared-host-scheduler.js +2 -0
  233. package/dist/src/serve/worker-invocation.js +558 -0
  234. package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
  235. package/dist/src/serve/worker-stdin-frame.mjs +107 -0
  236. package/dist/src/sessions/adapter-registry.js +49 -0
  237. package/dist/src/sessions/adapters/claude.js +39 -54
  238. package/dist/src/sessions/adapters/codex.js +82 -67
  239. package/dist/src/sessions/adapters/copilot.js +4 -4
  240. package/dist/src/sessions/adapters/cursor.js +40 -57
  241. package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
  242. package/dist/src/sessions/adapters/factory.js +31 -27
  243. package/dist/src/sessions/adapters/generic.js +43 -9
  244. package/dist/src/sessions/adapters/grok-build.js +11 -11
  245. package/dist/src/sessions/adapters/grokbot-locator.js +111 -0
  246. package/dist/src/sessions/adapters/grokbot.js +434 -24
  247. package/dist/src/sessions/adapters/hermes.js +27 -29
  248. package/dist/src/sessions/adapters/muse-workspace-scan.js +128 -0
  249. package/dist/src/sessions/adapters/muse.js +200 -104
  250. package/dist/src/sessions/adapters/omp.js +28 -14
  251. package/dist/src/sessions/adapters/openclaw.js +89 -79
  252. package/dist/src/sessions/adapters/opencode.js +27 -24
  253. package/dist/src/sessions/adapters/openhuman.js +18 -60
  254. package/dist/src/sessions/adapters/pi.js +30 -14
  255. package/dist/src/sessions/adapters/warp.js +3 -3
  256. package/dist/src/sessions/adapters/windsurf.js +19 -48
  257. package/dist/src/sessions/batch-contracts.js +25 -5
  258. package/dist/src/sessions/batch-import.js +72 -51
  259. package/dist/src/sessions/candidates.js +47 -11
  260. package/dist/src/sessions/contracts.js +75 -2
  261. package/dist/src/sessions/coverage-preflight.js +134 -0
  262. package/dist/src/sessions/discovery.js +3 -0
  263. package/dist/src/sessions/export-plan.js +4 -3
  264. package/dist/src/sessions/grok-build-cli.js +67 -5
  265. package/dist/src/sessions/import-exclusions.js +72 -0
  266. package/dist/src/sessions/import-lease.js +34 -18
  267. package/dist/src/sessions/import-limits.js +37 -0
  268. package/dist/src/sessions/importer.js +84 -46
  269. package/dist/src/sessions/index.js +2 -0
  270. package/dist/src/sessions/lifecycle.js +45 -0
  271. package/dist/src/sessions/policy.js +133 -25
  272. package/dist/src/sessions/readers.js +106 -53
  273. package/dist/src/sessions/refresh.js +106 -0
  274. package/dist/src/sessions/repository.js +199 -63
  275. package/dist/src/sessions/workspace-discovery.js +315 -88
  276. package/dist/src/sessions/workspace-matching.js +107 -0
  277. package/dist/src/skills/adapters/clawhub.js +10 -8
  278. package/dist/src/skills/adapters/openclaw.js +10 -7
  279. package/dist/src/skills/importer.js +1 -0
  280. package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
  281. package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
  282. package/dist/src/smiths/context-pipeline/finalization.js +6 -5
  283. package/dist/src/smiths/context-pipeline/generator.js +21 -4
  284. package/dist/src/smiths/context-pipeline/parallelism-section.js +195 -14
  285. package/dist/src/smiths/context-pipeline/workspace-context.js +116 -9
  286. package/dist/src/smiths/hook-bridge/codex-translator.js +6 -5
  287. package/dist/src/smiths/mcpsmith/example.js +1 -1
  288. package/dist/src/smiths/mcpsmith/generator.js +1 -1
  289. package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
  290. package/dist/src/smiths/toolsmith/runtime-discovery.mjs +85 -31
  291. package/dist/src/storage/backends/fs.js +18 -76
  292. package/dist/src/storage/backends/logseq.js +68 -7
  293. package/dist/src/storage/backends/obsidian.js +1 -0
  294. package/dist/src/storage/fortemi-qualification-receipt.js +2 -2
  295. package/dist/src/testing/generators/test-code-generator.js +57 -30
  296. package/dist/src/tracker/forge-http.js +2 -1
  297. package/dist/src/uhp/client.js +11 -1
  298. package/dist/src/uhp/mission.js +5 -0
  299. package/dist/src/update/checker.d.mts +2 -0
  300. package/dist/src/update/checker.mjs +5 -5
  301. package/dist/src/update/notifier.mjs +54 -2
  302. package/dist/src/update/service.d.mts +22 -0
  303. package/dist/src/utils/contained-filesystem.d.mts +37 -0
  304. package/dist/src/utils/contained-filesystem.mjs +683 -0
  305. package/dist/src/utils/temporary-directory.js +36 -0
  306. package/dist/src/writing/example-generator.js +1 -1
  307. package/dist/src/writing/fidelity.js +18 -1
  308. package/package.json +32 -2
  309. package/schemas/mission-v1.schema.json +2429 -0
  310. package/schemas/models/model-catalog.v1.schema.json +301 -0
  311. package/schemas/models/model-config-compatibility.v1.schema.json +281 -0
  312. package/schemas/models/model-policy.v1.schema.json +14 -0
  313. package/schemas/models/provider-model-capabilities.v1.schema.json +1072 -0
  314. package/tools/_resolve-impl.mjs +39 -2
  315. package/tools/agents/deploy-agents.mjs +64 -23
  316. package/tools/agents/providers/base.mjs +153 -166
  317. package/tools/agents/providers/claude.mjs +8 -24
  318. package/tools/agents/providers/codex.mjs +18 -11
  319. package/tools/agents/providers/cursor.mjs +19 -18
  320. package/tools/agents/providers/grok-build.mjs +3 -1
  321. package/tools/agents/providers/grokbot.mjs +11 -12
  322. package/tools/agents/providers/hermes.mjs +62 -49
  323. package/tools/agents/providers/omp.mjs +5 -2
  324. package/tools/agents/providers/openclaw-translator.mjs +19 -5
  325. package/tools/agents/providers/openclaw.mjs +9 -4
  326. package/tools/agents/providers/pi.mjs +5 -0
  327. package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
  328. package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
  329. package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
  330. package/tools/agents/providers/rule-delivery.mjs +1270 -0
  331. package/tools/agents/providers/warp.mjs +20 -26
  332. package/tools/cli/decision-offload-report.mjs +40 -0
  333. package/tools/cli/workspace-status.mjs +862 -0
  334. package/tools/plugin/package-plugins.mjs +186 -8
  335. package/tools/plugin/plugin-links.mjs +114 -0
  336. package/tools/providers/antigravity-transport.mjs +3 -1
  337. package/tools/providers/deepseek-harness-transport.mjs +360 -0
  338. package/tools/providers/omp-transport.mjs +194 -0
  339. package/tools/ralph-external/lib/claude-adapter.mjs +389 -0
  340. package/tools/ralph-external/lib/codex-adapter.mjs +432 -0
  341. package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
  342. package/tools/ralph-external/lib/deepseek-harness-adapter.mjs +397 -0
  343. package/tools/ralph-external/lib/factory-adapter.mjs +503 -0
  344. package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
  345. package/tools/ralph-external/lib/muse-adapter.mjs +364 -0
  346. package/tools/ralph-external/lib/omp-adapter.mjs +315 -0
  347. package/tools/ralph-external/lib/opencode-adapter.mjs +575 -0
  348. package/tools/ralph-external/lib/openhuman-adapter.mjs +75 -0
  349. package/tools/ralph-external/lib/pi-adapter.mjs +329 -0
  350. package/tools/ralph-external/lib/provider-adapter.mjs +748 -0
  351. package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
  352. package/tools/ralph-external/lib/session-environment.mjs +28 -0
  353. package/tools/ralph-external/lib/systemd-client.mjs +49 -0
  354. package/tools/ralph-external/lib/worker-health.mjs +439 -0
  355. package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
  356. package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
  357. package/tools/ralph-external/process-monitor.mjs +1017 -0
  358. package/tools/ralph-external/session-launcher.mjs +5057 -0
  359. package/tools/scripts/resource-preflight.mjs +541 -0
  360. package/tools/skills/deploy-skills-codex.mjs +2 -1
  361. package/vscode-extension/schemas/aiwg.config.v1.json +2916 -0
@@ -9,13 +9,15 @@
9
9
  * @version 2024.12.0
10
10
  */
11
11
 
12
+ import { signalChild } from '../process/signal-child.mjs';
12
13
  import fs from 'fs/promises';
13
14
  import { readFileSync, existsSync } from 'fs';
14
15
  import path from 'path';
15
16
  import { fileURLToPath } from 'url';
16
- import { execFileSync, execSync, spawn } from 'child_process';
17
+ import { spawn } from 'child_process';
17
18
  import os from 'os';
18
19
  import { resolveUserConfigDir } from '../config/user-config-dir.mjs';
20
+ import { boundedExecFileSync } from '../process/bounded-child-process.mjs';
19
21
  import {
20
22
  assertCanonicalInstallation,
21
23
  createInstallationIdentity,
@@ -52,9 +54,9 @@ async function runWithTimeout(cmd, args, options = {}) {
52
54
  let settled = false;
53
55
  const timer = setTimeout(() => {
54
56
  if (settled) return;
55
- try { child.kill('SIGTERM'); } catch { /* already exited */ }
57
+ try { signalChild(child, 'SIGTERM'); } catch { /* already exited */ }
56
58
  const kill9 = setTimeout(() => {
57
- try { child.kill('SIGKILL'); } catch { /* already exited */ }
59
+ try { signalChild(child, 'SIGKILL'); } catch { /* already exited */ }
58
60
  }, 5_000);
59
61
  kill9.unref?.();
60
62
  settled = true;
@@ -135,6 +137,50 @@ export function getPackageRoot() {
135
137
  return path.resolve(__dirname, '..', '..');
136
138
  }
137
139
 
140
+ /**
141
+ * Resolve the installation root bin/aiwg.mjs actually dispatches to.
142
+ *
143
+ * This is the exact decision `resolveRouterPath()` in bin/aiwg.mjs makes
144
+ * when picking which `dist/` to load the compiled router (and therefore
145
+ * every compiled-dist module it imports, including the MCP server) from:
146
+ * the dev-mode edge checkout when configured and present and distinct from
147
+ * the package root, otherwise the package root itself. Shared so health
148
+ * checks (doctor) validate the layout the launcher will actually execute
149
+ * instead of re-deriving — and risking drifting from — the same decision
150
+ * (#276).
151
+ *
152
+ * @param {string} packageRoot - This install's own package root (`getPackageRoot()`).
153
+ * @param {{devMode?: boolean, edgePath?: string}} config - Channel config (`loadConfig()`).
154
+ * @returns {string} The effective root whose `dist/src/...` the launcher loads from.
155
+ */
156
+ export function resolveEffectiveInstallationRoot(packageRoot, config) {
157
+ if (config?.devMode && config.edgePath && config.edgePath !== packageRoot) {
158
+ return config.edgePath;
159
+ }
160
+ return packageRoot;
161
+ }
162
+
163
+ /**
164
+ * Resolve the absolute path to the MCP server entrypoint the production
165
+ * launcher actually loads: `bin/aiwg.mjs` always dispatches to the
166
+ * *compiled* router (`resolveRouterPath()`, never an uncompiled `src/`
167
+ * tree), whose MCP handler imports `../../mcp/cli.mjs` relative to its own
168
+ * compiled location, which in turn imports `./server.mjs` relative to
169
+ * itself — i.e. always `<effective root>/dist/src/mcp/server.mjs`, in every
170
+ * layout (npm install, source checkout, dev-mode edge checkout). There is
171
+ * no runtime path that falls back to `src/mcp/server.mjs` directly, so a
172
+ * health check that also accepts that source path can report OK for a
173
+ * layout where `aiwg mcp serve` will actually fail (#276).
174
+ *
175
+ * @param {string} packageRoot - This install's own package root (`getPackageRoot()`).
176
+ * @param {{devMode?: boolean, edgePath?: string}} config - Channel config (`loadConfig()`).
177
+ * @returns {string} Absolute path to the compiled MCP server entrypoint.
178
+ */
179
+ export function resolveMcpServerEntrypointPath(packageRoot, config) {
180
+ const root = resolveEffectiveInstallationRoot(packageRoot, config);
181
+ return path.join(root, 'dist', 'src', 'mcp', 'server.mjs');
182
+ }
183
+
138
184
  /**
139
185
  * Load channel configuration
140
186
  * @returns {Promise<object>} Channel configuration
@@ -237,6 +283,9 @@ export async function getFrameworkRoot(options = {}) {
237
283
  */
238
284
  export async function switchToEdge() {
239
285
  const config = await loadConfig();
286
+ if (typeof config.edgePath !== 'string' || !path.isAbsolute(config.edgePath)) {
287
+ throw new Error('Edge installation path must be absolute');
288
+ }
240
289
 
241
290
  console.log('Switching to edge channel (bleeding edge from main branch)...');
242
291
  console.log('');
@@ -256,8 +305,8 @@ export async function switchToEdge() {
256
305
  const sparseConfig = path.join(config.edgePath, '.git', 'info', 'sparse-checkout');
257
306
  const hasSparse = await fs.access(sparseConfig).then(() => true).catch(() => false);
258
307
  if (!hasSparse) {
259
- execSync('git sparse-checkout init --cone', { cwd: config.edgePath, stdio: 'pipe' });
260
- execSync('git sparse-checkout set --no-cone "/*" "!/.aiwg"', { cwd: config.edgePath, stdio: 'pipe' });
308
+ boundedExecFileSync('git', ['sparse-checkout', 'init', '--cone'], 'quick', { cwd: config.edgePath, stdio: 'pipe' });
309
+ boundedExecFileSync('git', ['sparse-checkout', 'set', '--no-cone', '/*', '!/.aiwg'], 'quick', { cwd: config.edgePath, stdio: 'pipe' });
261
310
  }
262
311
  } catch {
263
312
  // Sparse checkout is optional — older git may not support it
@@ -275,11 +324,12 @@ export async function switchToEdge() {
275
324
  console.log(`Cloning repository to ${config.edgePath}...`);
276
325
  await fs.mkdir(path.dirname(config.edgePath), { recursive: true });
277
326
  try {
278
- execSync(`git clone --branch main ${REPO_URL} "${config.edgePath}"`, { stdio: 'inherit' });
327
+ // Cloning the full repository; long tier (#3062).
328
+ boundedExecFileSync('git', ['clone', '--branch', 'main', '--', REPO_URL, config.edgePath], 'long', { stdio: 'inherit' });
279
329
  // Exclude dogfooding artifacts from edge clones — users want framework source only
280
330
  try {
281
- execSync('git sparse-checkout init --cone', { cwd: config.edgePath, stdio: 'pipe' });
282
- execSync('git sparse-checkout set --no-cone "/*" "!/.aiwg"', { cwd: config.edgePath, stdio: 'pipe' });
331
+ boundedExecFileSync('git', ['sparse-checkout', 'init', '--cone'], 'quick', { cwd: config.edgePath, stdio: 'pipe' });
332
+ boundedExecFileSync('git', ['sparse-checkout', 'set', '--no-cone', '/*', '!/.aiwg'], 'quick', { cwd: config.edgePath, stdio: 'pipe' });
283
333
  } catch {
284
334
  // Sparse checkout is optional — older git versions may not support it
285
335
  console.log('Note: sparse checkout not available, .aiwg/ will be present in edge install.');
@@ -375,7 +425,7 @@ export async function switchToNext() {
375
425
  console.log('');
376
426
 
377
427
  try {
378
- execFileSync(status.identity.managerExecutable, ['install', '--global', 'aiwg@next'], { stdio: 'inherit' });
428
+ boundedExecFileSync(status.identity.managerExecutable, ['install', '--global', 'aiwg@next'], 'long', { stdio: 'inherit' });
379
429
  } catch (error) {
380
430
  console.error('Failed to install aiwg@next:', error.message);
381
431
  console.error('Check that npm is available and you have write access to the global prefix.');
@@ -409,7 +459,7 @@ export async function switchToNightly() {
409
459
  console.log('');
410
460
 
411
461
  try {
412
- execFileSync(status.identity.managerExecutable, ['install', '--global', 'aiwg@nightly'], { stdio: 'inherit' });
462
+ boundedExecFileSync(status.identity.managerExecutable, ['install', '--global', 'aiwg@nightly'], 'long', { stdio: 'inherit' });
413
463
  } catch (error) {
414
464
  console.error('Failed to install aiwg@nightly:', error.message);
415
465
  console.error('Check that npm is available and you have write access to the global prefix.');
@@ -491,6 +541,19 @@ export async function getVersionInfo() {
491
541
  const packageJsonPath = path.join(packageRoot, 'package.json');
492
542
  const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
493
543
 
544
+ const launcherRoot = process.env.AIWG_LAUNCHER_ROOT || packageRoot;
545
+ const runtimePath = resolveEffectiveInstallationRoot(launcherRoot, config);
546
+ const readVersion = async (root) => {
547
+ try {
548
+ const pkg = JSON.parse(await fs.readFile(path.join(root, 'package.json'), 'utf8'));
549
+ return typeof pkg.version === 'string' ? pkg.version : '(unknown)';
550
+ } catch {
551
+ return '(unknown)';
552
+ }
553
+ };
554
+ const launcherVersion = await readVersion(launcherRoot);
555
+ const runtimeVersion = await readVersion(runtimePath);
556
+
494
557
  // Detect pre-release channel from version string when channel.json says 'stable'
495
558
  // This handles the case where a user ran `npm install -g aiwg@next` directly —
496
559
  // npm updates the binary but channel.json stays as 'stable'.
@@ -510,6 +573,9 @@ export async function getVersionInfo() {
510
573
 
511
574
  const info = {
512
575
  version,
576
+ launcherVersion,
577
+ runtimeVersion,
578
+ runtimePath,
513
579
  channel,
514
580
  packageRoot,
515
581
  installation,
@@ -526,11 +592,11 @@ export async function getVersionInfo() {
526
592
  if (config.channel === 'edge') {
527
593
  // Get git info for edge channel
528
594
  try {
529
- const gitHash = execSync('git rev-parse --short HEAD', {
595
+ const gitHash = boundedExecFileSync('git', ['rev-parse', '--short', 'HEAD'], 'quick', {
530
596
  cwd: config.edgePath,
531
597
  encoding: 'utf8',
532
598
  }).trim();
533
- const gitBranch = execSync('git branch --show-current', {
599
+ const gitBranch = boundedExecFileSync('git', ['branch', '--show-current'], 'quick', {
534
600
  cwd: config.edgePath,
535
601
  encoding: 'utf8',
536
602
  }).trim();
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Shared `spawnSync`/`boundedSpawnSync` result-to-exit-code mapping (#3062
3
+ * review item 7).
4
+ *
5
+ * `SpawnSyncReturns.status` is `null` on spawn failure, timeout, or signal
6
+ * termination — not `0`. Several call sites derived a CLI exit code with
7
+ * `result.status ?? 0`, which reports *success* for exactly those failure
8
+ * cases. This helper never does that: a `status` of `null` defaults to a
9
+ * non-zero exit, and when the bounded helper's `error`/`signal` fields are
10
+ * present, their message (already enriched with the tier/bound/override
11
+ * guidance for a timeout) is surfaced instead of being silently dropped.
12
+ *
13
+ * Deliberately lives under `src/cli/` rather than `src/process/` so it
14
+ * composes with, but does not modify, the bounded helper itself.
15
+ *
16
+ * @module src/cli/child-process-result
17
+ */
18
+ /**
19
+ * Map one spawn result to `{ exitCode, message? }`.
20
+ *
21
+ * - `result.error` set (spawn failure, or a bounded-helper timeout with its
22
+ * enriched message) → non-zero, `message` is `error.message` (optionally
23
+ * prefixed with `context`).
24
+ * - No `error`, but `result.signal` set (child killed by a signal, with no
25
+ * separate error object) → non-zero, `message` names the signal.
26
+ * - Otherwise → `result.status ?? 1` (a `null`/`undefined` status with
27
+ * neither `error` nor `signal` set is still treated as a failure, never
28
+ * as success).
29
+ */
30
+ export function exitCodeForSpawnResult(result, context) {
31
+ const prefix = context ? `${context}: ` : '';
32
+ if (result.error) {
33
+ return { exitCode: 1, message: `${prefix}${result.error.message}` };
34
+ }
35
+ if (result.signal) {
36
+ return { exitCode: 1, message: `${prefix}terminated by signal ${result.signal}` };
37
+ }
38
+ return { exitCode: result.status ?? 1 };
39
+ }
40
+ //# sourceMappingURL=child-process-result.js.map
@@ -2,7 +2,7 @@ import { mkdir, readFile, rename, stat, writeFile, appendFile } from 'fs/promise
2
2
  import { existsSync } from 'fs';
3
3
  import { createHash } from 'crypto';
4
4
  import path from 'path';
5
- import os from 'os';
5
+ import { getUserStateDir } from '../config/user-state.js';
6
6
  import { readAiwgConfig } from '../config/aiwg-config.js';
7
7
  import { PROJECT_AIWG_LOCATION_FILE, projectAiwgPath, projectControlPath, } from '../config/project-artifacts.js';
8
8
  const DEFAULT_MAX_BYTES = 1_048_576;
@@ -170,8 +170,7 @@ function resolveLogPath(scope, projectRoot, env) {
170
170
  return null;
171
171
  return projectAiwgPath(projectRoot, 'telemetry', 'cli-commands.jsonl');
172
172
  }
173
- const stateHome = env.XDG_STATE_HOME || path.join(os.homedir(), '.local', 'state');
174
- return path.join(stateHome, 'aiwg', 'cli-commands.jsonl');
173
+ return path.join(getUserStateDir(env), 'cli-commands.jsonl');
175
174
  }
176
175
  async function appendBoundedJsonl(filePath, event, maxBytes) {
177
176
  await mkdir(path.dirname(filePath), { recursive: true });
@@ -25,9 +25,24 @@
25
25
  *
26
26
  * Handlers MUST call this helper instead of re-deriving the check locally.
27
27
  * Divergent isTTY checks scattered across handlers have caused bugs in the
28
- * past (#918 audit findings).
28
+ * past (#918 audit findings, and #3062 review item 12: `init` only checked
29
+ * `CI === 'true'`, `setup project` ignored CI/TERM entirely, and `session`
30
+ * ignored its own `--non-interactive` flag — each reinventing a narrower
31
+ * version of this same check instead of using it).
32
+ *
33
+ * @param explicitNonInteractive When `true`, short-circuits to `false`
34
+ * without inspecting the environment at all. Pass the caller's own
35
+ * explicit non-interactive flag here (e.g. `--non-interactive`, or
36
+ * `--yes` where it means "don't prompt") so the single interactive
37
+ * decision takes the command's explicit flags as input, rather than
38
+ * every call site re-deriving its own mix of flag-vs-environment
39
+ * precedence. Omit it (or pass `false`) to fall through to the
40
+ * environment-only checks below, unchanged from before this parameter
41
+ * existed.
29
42
  */
30
- export function isInteractive() {
43
+ export function isInteractive(explicitNonInteractive = false) {
44
+ if (explicitNonInteractive)
45
+ return false;
31
46
  if (!process.stdin.isTTY)
32
47
  return false;
33
48
  if (!process.stdout.isTTY)
@@ -40,25 +55,32 @@ export function isInteractive() {
40
55
  return false;
41
56
  return true;
42
57
  }
58
+ /**
59
+ * Variables that mark a continuous-integration environment. Exported so tests
60
+ * that need the interactive path can clear exactly what `isCI()` reads.
61
+ */
62
+ export const CI_ENV_VARS = [
63
+ 'CI',
64
+ 'CONTINUOUS_INTEGRATION',
65
+ 'BUILD_NUMBER',
66
+ 'RUN_ID',
67
+ 'GITHUB_ACTIONS',
68
+ 'GITLAB_CI',
69
+ 'CIRCLECI',
70
+ 'TRAVIS',
71
+ 'BUILDKITE',
72
+ 'JENKINS_URL',
73
+ 'TF_BUILD', // Azure DevOps
74
+ 'TEAMCITY_VERSION',
75
+ ];
76
+ /** Other variables `isInteractive()` reads. */
77
+ export const INTERACTIVE_ENV_VARS = ['TERM', 'DEBIAN_FRONTEND'];
43
78
  /**
44
79
  * Return true iff we're running in a continuous-integration environment.
45
80
  * Checks the common CI env vars set by major CI systems.
46
81
  */
47
82
  export function isCI() {
48
- const ciVars = [
49
- 'CI',
50
- 'CONTINUOUS_INTEGRATION',
51
- 'BUILD_NUMBER',
52
- 'RUN_ID',
53
- 'GITHUB_ACTIONS',
54
- 'GITLAB_CI',
55
- 'CIRCLECI',
56
- 'TRAVIS',
57
- 'BUILDKITE',
58
- 'JENKINS_URL',
59
- 'TF_BUILD', // Azure DevOps
60
- 'TEAMCITY_VERSION',
61
- ];
83
+ const ciVars = CI_ENV_VARS;
62
84
  for (const v of ciVars) {
63
85
  const val = process.env[v];
64
86
  if (val && val !== '0' && val.toLowerCase() !== 'false')
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Shared strict CLI flag/value parsing (#3062 review item 11, and the
3
+ * second-round review's finding 4).
4
+ *
5
+ * Several handlers (`init`, `setup`, `session`, `setup-run`) each grew
6
+ * their own small `flagValue(args, name)` helper, and every one of them
7
+ * treated a flag that is present but missing its value the same as a flag
8
+ * that was never given at all — `--prompt` as the very last token, or
9
+ * immediately followed by another flag, silently resolved to `undefined`
10
+ * instead of erroring. At a terminal that let the handler fall through
11
+ * into an interactive prompt instead of reporting the mistake; without one
12
+ * it could proceed on a silently-wrong default.
13
+ *
14
+ * The first-round shared parser fixed that but introduced its own gaps,
15
+ * found by the second review:
16
+ *
17
+ * - It validated only the *first* occurrence of a repeated single-value
18
+ * flag, so `--provider claude --provider` (a malformed second
19
+ * occurrence) silently passed.
20
+ * - It always resolved a repeated flag to its first occurrence, which
21
+ * silently changed `aiwg session`'s pre-existing last-occurrence-wins
22
+ * precedence for `--provider`/`--profile` to first-wins — a real
23
+ * behavior regression, not just a new validation gap.
24
+ * - `--flag=value` was never recognized at all.
25
+ * - Scanning never stopped at a bare `--` terminator.
26
+ * - An empty-string value (`--prompt ''`) was accepted as a valid value
27
+ * for flags where that is never meaningful.
28
+ *
29
+ * {@link scanFlagOccurrences} is the single-pass tokenizer every other
30
+ * helper here is built on: it finds *every* occurrence of the named
31
+ * flag(s), in one scan, validating each one independently, and stops
32
+ * recognizing flags entirely once it sees a bare `--` token (everything
33
+ * after that point is positional, per POSIX convention). `--flag value`
34
+ * and `--flag=value` are both accepted; in the space-separated form a
35
+ * value that itself looks like another flag (starts with `--`) is treated
36
+ * as a missing value — pass it via the `=` form instead
37
+ * (`--flag=--literal`) when a value must start with `--`. A value starting
38
+ * with a single `-` is always accepted in either form.
39
+ *
40
+ * Callers choose `precedence: 'first' | 'last'` to match whatever
41
+ * precedence the command already had before this module existed — see
42
+ * each call site's own comment for which one applies and why. Callers
43
+ * MUST catch {@link MissingFlagValueError} (or let it propagate to a
44
+ * handler-level catch) and report it before any preflight check, spawn,
45
+ * or write — never after.
46
+ */
47
+ /** Thrown when a recognized flag is present but has no usable value following it. */
48
+ export class MissingFlagValueError extends Error {
49
+ /** The exact flag token that was missing its value (e.g. `--prompt`). */
50
+ flagName;
51
+ constructor(flagName) {
52
+ super(`${flagName} requires a value`);
53
+ this.name = 'MissingFlagValueError';
54
+ this.flagName = flagName;
55
+ }
56
+ }
57
+ function splitEquals(token) {
58
+ const eq = token.indexOf('=');
59
+ if (eq === -1)
60
+ return null;
61
+ return [token.slice(0, eq), token.slice(eq + 1)];
62
+ }
63
+ /**
64
+ * Single-pass scan for every occurrence of any of `names` in `args`. See
65
+ * the module doc comment for the full set of semantics this implements.
66
+ *
67
+ * Throws {@link MissingFlagValueError} on the *first* occurrence (in
68
+ * left-to-right order) that has no usable value or an empty one (when
69
+ * `options.rejectEmpty`) — every occurrence is checked, not just the
70
+ * first one found overall, so a malformed *later* occurrence is still an
71
+ * error even when an earlier one was valid.
72
+ */
73
+ export function scanFlagOccurrences(args, names, options = {}) {
74
+ const occurrences = [];
75
+ for (let i = 0; i < args.length; i += 1) {
76
+ const token = args[i];
77
+ if (token === undefined)
78
+ continue;
79
+ if (token === '--')
80
+ break; // bare terminator — stop recognizing flags entirely
81
+ if (token.startsWith('--')) {
82
+ const eqSplit = splitEquals(token);
83
+ if (eqSplit && names.includes(eqSplit[0])) {
84
+ const [flag, value] = eqSplit;
85
+ if (options.rejectEmpty && value === '')
86
+ throw new MissingFlagValueError(flag);
87
+ occurrences.push({ index: i, flag, value });
88
+ continue;
89
+ }
90
+ }
91
+ if (names.includes(token)) {
92
+ const next = args[i + 1];
93
+ if (next === undefined || next.startsWith('--')) {
94
+ throw new MissingFlagValueError(token);
95
+ }
96
+ if (options.rejectEmpty && next === '') {
97
+ throw new MissingFlagValueError(token);
98
+ }
99
+ occurrences.push({ index: i, flag: token, value: next });
100
+ i += 1; // skip the consumed value token
101
+ }
102
+ }
103
+ return occurrences;
104
+ }
105
+ /**
106
+ * Look up the value of a (possibly repeated) single-value flag.
107
+ *
108
+ * - None of `names` appear at all → `undefined` (the flag was never
109
+ * given; not an error).
110
+ * - `names` appear once or more, every occurrence validated → the first
111
+ * or last occurrence's value, per `options.precedence` (default
112
+ * `'first'`). Pass `'last'` only for a command whose pre-existing
113
+ * behavior (before this module existed) already let a later occurrence
114
+ * override an earlier one — see the call site's comment.
115
+ */
116
+ export function requireFlagValue(args, options, ...names) {
117
+ const occurrences = scanFlagOccurrences(args, names, options);
118
+ if (occurrences.length === 0)
119
+ return undefined;
120
+ return options.precedence === 'last'
121
+ ? occurrences[occurrences.length - 1].value
122
+ : occurrences[0].value;
123
+ }
124
+ /**
125
+ * Same validation contract as {@link requireFlagValue}, but collects the
126
+ * value of *every* occurrence in left-to-right order — for repeatable
127
+ * flags such as `--param`/`--script`. Returns `[]` when the flag never
128
+ * appears.
129
+ */
130
+ export function collectFlagValues(args, options, ...names) {
131
+ return scanFlagOccurrences(args, names, options).map((occurrence) => occurrence.value);
132
+ }
133
+ /**
134
+ * Parse a strict `true`/`false` flag value. `undefined` in means the flag
135
+ * was not given (not an error, and not a default — callers decide the
136
+ * default). Anything other than exactly `true`/`false` throws, naming
137
+ * `flagName` in the message.
138
+ */
139
+ export function parseBooleanFlagValue(value, flagName) {
140
+ if (value === undefined)
141
+ return undefined;
142
+ if (value === 'true')
143
+ return true;
144
+ if (value === 'false')
145
+ return false;
146
+ throw new Error(`${flagName} must be true or false (got '${value}')`);
147
+ }
148
+ /**
149
+ * Parse a comma-separated list flag value, trimming whitespace and
150
+ * dropping empty entries. Returns `undefined` when `raw` is `undefined`
151
+ * (flag not given); returns `[]` only if every entry was empty.
152
+ */
153
+ export function parseListFlagValue(raw) {
154
+ if (raw === undefined)
155
+ return undefined;
156
+ return raw.split(',').map((entry) => entry.trim()).filter(Boolean);
157
+ }
158
+ /**
159
+ * Split one repeatable `<name>=<value>` entry (as used by `--script`,
160
+ * `--param`) into its parts. Throws, naming `flagName`, when `entry` has
161
+ * no `=`, an empty name, or an empty value.
162
+ */
163
+ export function parseKeyValueEntry(entry, flagName) {
164
+ const eq = entry.indexOf('=');
165
+ if (eq <= 0 || eq === entry.length - 1) {
166
+ throw new Error(`${flagName} requires the form <name>=<value> (got '${entry}')`);
167
+ }
168
+ return [entry.slice(0, eq).trim(), entry.slice(eq + 1).trim()];
169
+ }
170
+ /**
171
+ * The index of the first bare `--` terminator in `args`, or `args.length`
172
+ * when there is none — a loop bounded by this never looks at anything
173
+ * after the terminator, which per POSIX convention is never a flag or a
174
+ * command word again (#3062 go/no-go review, blocker 4).
175
+ */
176
+ export function argsTerminatorIndex(args) {
177
+ const index = args.indexOf('--');
178
+ return index === -1 ? args.length : index;
179
+ }
180
+ /**
181
+ * The set of array indexes in `args` consumed as the *value* of a
182
+ * `--flag value` (two-token) occurrence of any name in `valueFlagNames`
183
+ * (#3062 go/no-go review, blocker 4). A `--flag=value` (one-token) form
184
+ * has no separate value index to report — the value is part of the same
185
+ * token, so it can never coincidentally equal a bare positional word or a
186
+ * different flag's own name the way a space-separated value can.
187
+ *
188
+ * This does not validate occurrences (a missing/malformed value is the
189
+ * paired value-flag parser's own job — e.g. {@link requireFlagValue} on
190
+ * the same `args` and `valueFlagNames`, called separately); it exists
191
+ * purely so a positional/switch scan knows which indexes are already
192
+ * spoken for and must not be reinterpreted as something else.
193
+ */
194
+ export function valueTokenIndexes(args, valueFlagNames) {
195
+ const consumed = new Set();
196
+ const limit = args.length;
197
+ for (let i = 0; i < limit; i += 1) {
198
+ const token = args[i];
199
+ if (token === undefined)
200
+ continue;
201
+ if (token === '--')
202
+ break;
203
+ if (token.startsWith('--') && token.includes('='))
204
+ continue; // value is part of this same token
205
+ if (valueFlagNames.includes(token) && i + 1 < limit) {
206
+ consumed.add(i + 1);
207
+ i += 1; // the value token itself is spoken for; do not also treat it as a flag name
208
+ }
209
+ }
210
+ return consumed;
211
+ }
212
+ /**
213
+ * True iff `name` appears as a bare positional token or an exact-match
214
+ * boolean switch anywhere in `args` *before* the `--` terminator, and is
215
+ * not itself the already-consumed value of one of `valueFlagNames` (#3062
216
+ * go/no-go review, blocker 4).
217
+ *
218
+ * Use this instead of `args.includes(name)` (or an equivalent hand-rolled
219
+ * loop) for any boolean switch or positional command word that a value-
220
+ * taking flag's own value could coincidentally equal — e.g. a free-text
221
+ * `--prompt` argument that happens to contain the literal word a command
222
+ * also uses as a switch, or a value that collides with another flag's own
223
+ * name.
224
+ */
225
+ export function hasPositionalOrSwitch(args, name, valueFlagNames) {
226
+ const consumed = valueTokenIndexes(args, valueFlagNames);
227
+ const limit = argsTerminatorIndex(args);
228
+ for (let i = 0; i < limit; i += 1) {
229
+ if (consumed.has(i))
230
+ continue;
231
+ if (args[i] === name)
232
+ return true;
233
+ }
234
+ return false;
235
+ }
236
+ //# sourceMappingURL=flag-parsing.js.map
@@ -32,6 +32,9 @@ export const artifactsHandler = {
32
32
  description: 'Move or inspect the configured project AIWG artifact root',
33
33
  category: 'index',
34
34
  aliases: ['artifact'],
35
+ async help() {
36
+ return { exitCode: 0, message: usage(), rawOutput: true };
37
+ },
35
38
  async execute(ctx) {
36
39
  const action = ctx.args.find(arg => !arg.startsWith('-')) ?? 'help';
37
40
  if (action === 'help' || ctx.args.includes('--help') || ctx.args.includes('-h')) {
@@ -37,6 +37,9 @@ export function createAuthHandler(dependencies = {}) {
37
37
  description: "Log in, inspect access, and log out of paid AIWG web resources",
38
38
  category: "maintenance",
39
39
  aliases: [],
40
+ async help() {
41
+ return { exitCode: 0, message: usage(), rawOutput: true };
42
+ },
40
43
  async execute(ctx) {
41
44
  if (!ctx.args.length || ["help", "--help", "-h"].includes(ctx.args[0])) {
42
45
  console.log(usage());