@aiwg/cli 2026.9.19 → 2026.9.21

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 (272) hide show
  1. package/agentic/code/providers/capability-matrix.yaml +58 -6
  2. package/agentic/code/providers/model-capabilities.v1.json +34 -0
  3. package/agentic/code/providers/model-catalog.v1.json +55 -13
  4. package/bin/aiwg.mjs +2 -0
  5. package/dist/src/api/index.d.ts +1 -0
  6. package/dist/src/api/index.js +1 -0
  7. package/dist/src/artifacts/enrichment/cli.js +1 -1
  8. package/dist/src/artifacts/views/cli.js +1 -1
  9. package/dist/src/audit/operator-decision.js +10 -0
  10. package/dist/src/auth/credential-store.js +127 -27
  11. package/dist/src/catalog/builtin-models.json +272 -40
  12. package/dist/src/catalog/cli.js +1 -1
  13. package/dist/src/catalog/cli.mjs +1 -1
  14. package/dist/src/cli/handlers/effect.js +872 -0
  15. package/dist/src/cli/handlers/help.js +2 -0
  16. package/dist/src/cli/handlers/index.js +4 -2
  17. package/dist/src/cli/handlers/models.js +41 -10
  18. package/dist/src/cli/handlers/ralph.js +1 -1
  19. package/dist/src/cli/handlers/sessions.js +113 -37
  20. package/dist/src/cli/handlers/subcommands.js +31 -0
  21. package/dist/src/cli/handlers/use.js +46 -9
  22. package/dist/src/cli/handlers/utilities.js +10 -0
  23. package/dist/src/cli/handlers/workspace.js +3 -1
  24. package/dist/src/cli/scope-resolver.js +112 -9
  25. package/dist/src/cli/services/deployment-verification.js +5 -0
  26. package/dist/src/config/aiwg-config.js +3 -0
  27. package/dist/src/decision/acceptance-rollout.js +93 -0
  28. package/dist/src/decision/acceptance.js +175 -0
  29. package/dist/src/decision/adapters/jev.js +234 -13
  30. package/dist/src/decision/adapters/llm-subagent.js +60 -12
  31. package/dist/src/decision/admission.js +550 -0
  32. package/dist/src/decision/batch-benchmark.js +47 -0
  33. package/dist/src/decision/batch-receipts/accounting.js +75 -0
  34. package/dist/src/decision/batch-receipts/export.js +40 -0
  35. package/dist/src/decision/batch-receipts/index.js +9 -0
  36. package/dist/src/decision/batch-receipts/protection.js +40 -0
  37. package/dist/src/decision/batch-receipts/receipt.js +44 -0
  38. package/dist/src/decision/batch-receipts/result-store.js +341 -0
  39. package/dist/src/decision/batch-receipts/store.js +362 -0
  40. package/dist/src/decision/batch-receipts/types.js +2 -0
  41. package/dist/src/decision/batch-receipts/validate.js +127 -0
  42. package/dist/src/decision/batch.js +68 -0
  43. package/dist/src/decision/calibration/index.js +4 -0
  44. package/dist/src/decision/calibration/receipts.js +130 -0
  45. package/dist/src/decision/calibration/registry.js +258 -0
  46. package/dist/src/decision/calibration/types.js +2 -0
  47. package/dist/src/decision/compile-cache/benchmark.js +62 -0
  48. package/dist/src/decision/compile-cache/compatibility.js +65 -0
  49. package/dist/src/decision/compile-cache/file-store.js +280 -0
  50. package/dist/src/decision/compile-cache/identity.js +26 -0
  51. package/dist/src/decision/compile-cache/index.js +9 -0
  52. package/dist/src/decision/compile-cache/prefix.js +21 -0
  53. package/dist/src/decision/compile-cache/records.js +86 -0
  54. package/dist/src/decision/compile-cache/runtime.js +68 -0
  55. package/dist/src/decision/compile-cache/store.js +108 -0
  56. package/dist/src/decision/compile-cache/types.js +2 -0
  57. package/dist/src/decision/context-plan.js +234 -0
  58. package/dist/src/decision/context-qualification.js +60 -0
  59. package/dist/src/decision/ensemble/aggregate.js +215 -0
  60. package/dist/src/decision/ensemble/contract.js +316 -0
  61. package/dist/src/decision/ensemble/drift.js +51 -0
  62. package/dist/src/decision/ensemble/index.js +6 -0
  63. package/dist/src/decision/ensemble/report.js +71 -0
  64. package/dist/src/decision/ensemble/types.js +2 -0
  65. package/dist/src/decision/evaluate.js +1024 -78
  66. package/dist/src/decision/file-lifecycle-store.js +168 -0
  67. package/dist/src/decision/graph-beam.js +40 -0
  68. package/dist/src/decision/graph-budget.js +110 -0
  69. package/dist/src/decision/graph-decision-bridge.js +93 -0
  70. package/dist/src/decision/graph-evidence.js +123 -0
  71. package/dist/src/decision/graph-flow-adapter.js +56 -0
  72. package/dist/src/decision/graph-flow.js +105 -0
  73. package/dist/src/decision/graph-parallel.js +79 -0
  74. package/dist/src/decision/graph-patterns.js +20 -0
  75. package/dist/src/decision/graph-run-store.js +66 -0
  76. package/dist/src/decision/graph-run.js +166 -0
  77. package/dist/src/decision/graph-skill-bridge.js +91 -0
  78. package/dist/src/decision/graph-templates.js +56 -0
  79. package/dist/src/decision/graph.js +115 -0
  80. package/dist/src/decision/index.js +35 -0
  81. package/dist/src/decision/job-accounting.js +93 -0
  82. package/dist/src/decision/job-contract.js +186 -0
  83. package/dist/src/decision/job-effects.js +95 -0
  84. package/dist/src/decision/job-evaluate.js +80 -0
  85. package/dist/src/decision/job-gateway.js +121 -0
  86. package/dist/src/decision/job-http.js +194 -0
  87. package/dist/src/decision/job-payload-store.js +258 -0
  88. package/dist/src/decision/job-poll-limiter.js +92 -0
  89. package/dist/src/decision/job-quota.js +158 -0
  90. package/dist/src/decision/job-runtime.js +240 -0
  91. package/dist/src/decision/job-scheduler.js +26 -0
  92. package/dist/src/decision/job-service.js +117 -0
  93. package/dist/src/decision/job-store.js +264 -0
  94. package/dist/src/decision/job-worker.js +141 -0
  95. package/dist/src/decision/lifecycle.js +148 -0
  96. package/dist/src/decision/patterns/artifacts.js +173 -0
  97. package/dist/src/decision/patterns/catalog.js +108 -0
  98. package/dist/src/decision/patterns/durable-review.js +237 -0
  99. package/dist/src/decision/patterns/index.js +8 -0
  100. package/dist/src/decision/patterns/playground.js +401 -0
  101. package/dist/src/decision/patterns/recorded.js +43 -0
  102. package/dist/src/decision/patterns/specs.js +174 -0
  103. package/dist/src/decision/patterns/types.js +2 -0
  104. package/dist/src/decision/portable-secrets.js +53 -0
  105. package/dist/src/decision/projection.js +210 -0
  106. package/dist/src/decision/qualification/capture.js +67 -0
  107. package/dist/src/decision/qualification/drift.js +68 -0
  108. package/dist/src/decision/qualification/gate-evidence.js +172 -0
  109. package/dist/src/decision/qualification/gates.js +83 -0
  110. package/dist/src/decision/qualification/index.js +12 -0
  111. package/dist/src/decision/qualification/load.js +275 -0
  112. package/dist/src/decision/qualification/manifest.js +37 -0
  113. package/dist/src/decision/qualification/privacy.js +41 -0
  114. package/dist/src/decision/qualification/quality.js +213 -0
  115. package/dist/src/decision/qualification/release.js +116 -0
  116. package/dist/src/decision/qualification/runner.js +408 -0
  117. package/dist/src/decision/qualification/types.js +2 -0
  118. package/dist/src/decision/receipts.js +30 -7
  119. package/dist/src/decision/result-cache/index.js +6 -0
  120. package/dist/src/decision/result-cache/integrity.js +28 -0
  121. package/dist/src/decision/result-cache/key.js +28 -0
  122. package/dist/src/decision/result-cache/service.js +92 -0
  123. package/dist/src/decision/result-cache/store.js +327 -0
  124. package/dist/src/decision/result-cache/types.js +3 -0
  125. package/dist/src/decision/review/authorization.js +110 -0
  126. package/dist/src/decision/review/effect-ledger-adapter.js +321 -0
  127. package/dist/src/decision/review/index.js +12 -0
  128. package/dist/src/decision/review/migrate.js +34 -0
  129. package/dist/src/decision/review/operator-audit.js +59 -0
  130. package/dist/src/decision/review/recovery-adapters.js +252 -0
  131. package/dist/src/decision/review/recovery.js +33 -0
  132. package/dist/src/decision/review/service.js +498 -0
  133. package/dist/src/decision/review/store.js +219 -0
  134. package/dist/src/decision/review/types.js +2 -0
  135. package/dist/src/decision/review/validate.js +205 -0
  136. package/dist/src/decision/scheduler.js +115 -0
  137. package/dist/src/decision/telemetry/context.js +42 -0
  138. package/dist/src/decision/telemetry/debug-sidecar.js +152 -0
  139. package/dist/src/decision/telemetry/exporter.js +77 -0
  140. package/dist/src/decision/telemetry/file-debug-backend.js +112 -0
  141. package/dist/src/decision/telemetry/index.js +13 -0
  142. package/dist/src/decision/telemetry/mapping.js +146 -0
  143. package/dist/src/decision/telemetry/metrics.js +164 -0
  144. package/dist/src/decision/telemetry/otlp-http.js +183 -0
  145. package/dist/src/decision/telemetry/redaction.js +93 -0
  146. package/dist/src/decision/telemetry/retention.js +109 -0
  147. package/dist/src/decision/telemetry/runtime.js +310 -0
  148. package/dist/src/decision/telemetry/trace.js +158 -0
  149. package/dist/src/decision/telemetry/types.js +3 -0
  150. package/dist/src/decision/validate.js +135 -5
  151. package/dist/src/effects/checkpoint-sinks.js +94 -0
  152. package/dist/src/effects/checkpoint.js +76 -0
  153. package/dist/src/effects/decision-links.js +54 -0
  154. package/dist/src/effects/errors.js +48 -0
  155. package/dist/src/effects/identity.js +178 -0
  156. package/dist/src/effects/index.js +25 -0
  157. package/dist/src/effects/keyring.js +160 -0
  158. package/dist/src/effects/keys.js +130 -0
  159. package/dist/src/effects/ledger.js +435 -0
  160. package/dist/src/effects/lifecycle.js +110 -0
  161. package/dist/src/effects/lock-recovery.js +269 -0
  162. package/dist/src/effects/reader.js +103 -0
  163. package/dist/src/effects/records.js +114 -0
  164. package/dist/src/effects/redaction.js +51 -0
  165. package/dist/src/effects/schema.js +73 -0
  166. package/dist/src/effects/store.js +239 -0
  167. package/dist/src/effects/types.js +49 -0
  168. package/dist/src/effects/verifiers/decision.js +168 -0
  169. package/dist/src/effects/verifiers/file.js +106 -0
  170. package/dist/src/effects/verifiers/git.js +206 -0
  171. package/dist/src/effects/verifiers/index.js +90 -0
  172. package/dist/src/effects/verifiers/registry.js +148 -0
  173. package/dist/src/effects/verifiers/review.js +123 -0
  174. package/dist/src/effects/verifiers/tracker.js +299 -0
  175. package/dist/src/effects/verifiers/types.js +21 -0
  176. package/dist/src/effects/verify.js +295 -0
  177. package/dist/src/evidence/bundle.js +2 -0
  178. package/dist/src/extensions/commands/definitions.js +28 -0
  179. package/dist/src/extensions/manifest.js +1 -0
  180. package/dist/src/marketplace/provenance.js +25 -27
  181. package/dist/src/mcp/cli.mjs +11 -1
  182. package/dist/src/mcp/grok-build-config.mjs +189 -0
  183. package/dist/src/mcp/registry.js +21 -1
  184. package/dist/src/mcp/registry.mjs +20 -1
  185. package/dist/src/models/grok-build-models.js +356 -0
  186. package/dist/src/models/index.js +1 -0
  187. package/dist/src/models/model-capabilities.v1.json +34 -0
  188. package/dist/src/models/model-catalog.v1.json +55 -13
  189. package/dist/src/models/model-discovery.js +41 -5
  190. package/dist/src/models/provider-policy.js +3 -2
  191. package/dist/src/plugin/skill-command-translator.js +1 -0
  192. package/dist/src/providers/capability-matrix.yaml +58 -6
  193. package/dist/src/providers/grok-build-acp.js +192 -0
  194. package/dist/src/providers/grok-build-dispatch.js +251 -0
  195. package/dist/src/providers/grok-build-headless.js +170 -0
  196. package/dist/src/providers/muse-paths.js +105 -0
  197. package/dist/src/providers/provider-definitions.js +93 -7
  198. package/dist/src/providers/provider-definitions.mjs +21 -1
  199. package/dist/src/providers/provider-inventory.js +3 -0
  200. package/dist/src/security/artifact-attestation.js +4 -8
  201. package/dist/src/security/signing.js +119 -0
  202. package/dist/src/sessions/adapters/grok-build.js +187 -0
  203. package/dist/src/sessions/adapters/muse.js +412 -0
  204. package/dist/src/sessions/contracts.js +1 -1
  205. package/dist/src/sessions/grok-build-cli.js +196 -0
  206. package/dist/src/sessions/index.js +3 -0
  207. package/dist/src/sessions/workspace-discovery.js +9 -5
  208. package/dist/src/skills/deployer.js +33 -5
  209. package/dist/src/smiths/context-pipeline/claude-hook.js +2 -0
  210. package/dist/src/smiths/context-pipeline/context-file-safety.js +18 -0
  211. package/dist/src/smiths/context-pipeline/finalization.js +1 -32
  212. package/dist/src/smiths/context-pipeline/generator.js +12 -0
  213. package/dist/src/smiths/context-pipeline/index.js +1 -1
  214. package/dist/src/smiths/context-pipeline/managed-hook.js +2 -0
  215. package/dist/src/smiths/context-pipeline/muse-bridge.js +50 -0
  216. package/dist/src/smiths/context-pipeline/provider-policy.js +5 -0
  217. package/dist/src/smiths/context-pipeline/workspace-context.js +22 -16
  218. package/dist/src/smiths/hook-bridge/grok-build-translator.js +64 -0
  219. package/dist/src/smiths/hook-bridge/index.js +3 -0
  220. package/dist/src/smiths/hook-bridge/shim.js +2 -0
  221. package/dist/src/smiths/hook-bridge/types.js +5 -0
  222. package/dist/src/smiths/skillsmith/collision-detector.js +1 -0
  223. package/dist/src/storage/protected-files.js +102 -0
  224. package/dist/src/tracker/forge-http.js +371 -0
  225. package/dist/src/tracker/project-inputs.js +41 -0
  226. package/package.json +2 -1
  227. package/schemas/decision/BatchReceipt.v1.schema.json +50 -0
  228. package/schemas/decision/CalibrationArtifact.v1.schema.json +76 -0
  229. package/schemas/decision/CalibrationCompatibility.v1.schema.json +18 -0
  230. package/schemas/decision/CalibrationGovernanceReceipt.v1.schema.json +44 -0
  231. package/schemas/decision/DecisionAdmissionEvidence.v1.schema.json +43 -0
  232. package/schemas/decision/DecisionBinding.schema.json +309 -0
  233. package/schemas/decision/DecisionBinding.v1alpha2.schema.json +369 -0
  234. package/schemas/decision/DecisionCacheTelemetry.v1.schema.json +20 -0
  235. package/schemas/decision/DecisionChampionChallenger.v1.schema.json +100 -0
  236. package/schemas/decision/DecisionCompileCacheEntry.v1.schema.json +35 -0
  237. package/schemas/decision/DecisionCompileCacheIdentity.v1.schema.json +26 -0
  238. package/schemas/decision/DecisionCompileCacheTombstone.v1.schema.json +31 -0
  239. package/schemas/decision/DecisionContextEvidence.v1.schema.json +136 -0
  240. package/schemas/decision/DecisionDefinition.schema.json +159 -0
  241. package/schemas/decision/DecisionDefinition.v1alpha2.schema.json +203 -0
  242. package/schemas/decision/DecisionDriftResponse.v1.schema.json +55 -0
  243. package/schemas/decision/DecisionEnsembleAggregate.v1.schema.json +86 -0
  244. package/schemas/decision/DecisionEnsembleIntegrityReport.v1.schema.json +64 -0
  245. package/schemas/decision/DecisionEnsemblePolicy.v1.schema.json +130 -0
  246. package/schemas/decision/DecisionGraph.v1.schema.json +77 -0
  247. package/schemas/decision/DecisionJob.v1.schema.json +71 -0
  248. package/schemas/decision/DecisionLifecyclePolicy.v1.schema.json +52 -0
  249. package/schemas/decision/DecisionProjectionPolicy.v1.schema.json +65 -0
  250. package/schemas/decision/DecisionProviderPrefixCompatibility.v1.schema.json +45 -0
  251. package/schemas/decision/DecisionProviderPrefixEvidence.v1.schema.json +17 -0
  252. package/schemas/decision/DecisionProviderPrefixIdentity.v1.schema.json +36 -0
  253. package/schemas/decision/DecisionResult.schema.json +524 -0
  254. package/schemas/decision/DecisionResult.v1alpha2.schema.json +619 -0
  255. package/schemas/decision/DecisionResultCacheEntry.v1.schema.json +53 -0
  256. package/schemas/decision/DecisionReview.schema.json +29 -0
  257. package/schemas/decision/DecisionRuleset.schema.json +313 -0
  258. package/schemas/decision/DecisionRuleset.v1alpha2.schema.json +313 -0
  259. package/schemas/decision/DecisionTelemetryTrace.v1.schema.json +95 -0
  260. package/schemas/decision/RulesetResult.schema.json +721 -0
  261. package/schemas/decision/RulesetResult.v1alpha2.schema.json +891 -0
  262. package/schemas/security/pr-evidence-receipt.v1.schema.json +77 -0
  263. package/schemas/security/threat-assessment-report.v1.schema.json +71 -1
  264. package/tools/agents/deploy-agents.mjs +21 -6
  265. package/tools/agents/providers/base.mjs +7 -4
  266. package/tools/agents/providers/codex.mjs +1 -1
  267. package/tools/agents/providers/grok-build.d.mts +7 -0
  268. package/tools/agents/providers/grok-build.mjs +249 -9
  269. package/tools/agents/providers/model-role.mjs +6 -3
  270. package/tools/agents/providers/muse-hooks.mjs +785 -0
  271. package/tools/agents/providers/muse-paths.mjs +112 -0
  272. package/tools/agents/providers/muse.mjs +336 -0
@@ -94,6 +94,7 @@ const SKILLS_ONLY_PROVIDERS = new Set([
94
94
  'cursor',
95
95
  'grokbot',
96
96
  'hermes',
97
+ 'muse', // #236: skills deploy natively; no command translation (indexed-only agents/commands/rules)
97
98
  'openhuman',
98
99
  'pi',
99
100
  'omp',
@@ -405,11 +405,18 @@ providers:
405
405
  display_name: Grok Build
406
406
  status: experimental
407
407
  # xAI Grok Build CLI/TUI. Distinct from Grok Bot (`grokbot`).
408
- # Wave 1 (#2575): native kernel skills + AGENTS.md. Agents/rules writers deferred #2577.
408
+ # #2577: fixture-backed native subagents and background tasks; see
409
+ # test/unit/providers/grok-build-provider.test.ts and
410
+ # test/unit/providers/grok-build-dispatch.test.ts. MCP is independently
411
+ # covered by test/unit/providers/grok-build-native-integration.test.ts.
412
+ # Headless and ACP protocol contracts are tested in grok-build-headless.test.ts
413
+ # and grok-build-acp.test.ts. ACP does not establish a daemon lifecycle.
414
+ # No fixture supports native cron, multi-agent teams, mission control,
415
+ # or AIWG behavior registration; those claims remain false.
409
416
  daemon_tier: unsupported
410
417
  daemon_pty_adapter: false
411
418
  artifact_paths:
412
- agents: "Indexed: aiwg discover / aiwg show agent (native .grok/agents writer deferred #2577)"
419
+ agents: .grok/agents/ # qualified AIWG model workers only
413
420
  commands: null
414
421
  skills: .grok/skills/
415
422
  skills_cross_agent: .grok/.aiwg/skills/ # --copy-all opt-in mirror
@@ -417,16 +424,16 @@ providers:
417
424
  behaviors: null
418
425
  native_features:
419
426
  cron: false
420
- agent_teams: false
421
- tasks: false
427
+ agent_teams: false # independent subagents do not imply native team orchestration
428
+ tasks: true # native background subagents/tasks
422
429
  mcp: true
423
430
  behaviors: false
424
431
  mission_control: false
425
432
  daemon: false
426
433
  emulation:
427
434
  cron: null
428
- agent_teams: null
429
- tasks: aiwg-mc
435
+ agent_teams: aiwg-mc
436
+ tasks: native
430
437
  mcp: null
431
438
  behaviors: aiwg-mc
432
439
  mission_control: aiwg-mc
@@ -479,6 +486,51 @@ providers:
479
486
  deploy_target: mixed
480
487
  aggregated_output: true
481
488
 
489
+ muse:
490
+ display_name: Muse Code
491
+ status: experimental
492
+ # Meta's terminal/CI coding agent (Muse Spark-powered). Explicitly not a
493
+ # model-API surface: Glimmer/Image/Voice are out of scope.
494
+ # Skill writer (.agents/skills + XDG user root), discover-first AGENTS.md
495
+ # bridge, managed .muse/hooks.json, and opt-in MCP settings profile.
496
+ # ADR: docs/architecture/adr-muse-provider-target.md · epic #223.
497
+ daemon_tier: unsupported
498
+ daemon_pty_adapter: false
499
+ artifact_paths:
500
+ agents: "Indexed: aiwg discover / aiwg show agent (native writer deferred)"
501
+ commands: null
502
+ # Project root is fixed; the user root resolves at deploy time from
503
+ # XDG_CONFIG_HOME (default ~/.config/muse/skills when unset). Never
504
+ # advertise ~/.muse as a skill root, and never silently mirror into
505
+ # ~/.agents/skills (#226).
506
+ skills: .agents/skills/
507
+ skills_cross_agent: null
508
+ rules: "Indexed: aiwg show rule + AGENTS.md discover-first bridge"
509
+ behaviors: null
510
+ native_features:
511
+ cron: false
512
+ agent_teams: false
513
+ tasks: false
514
+ mcp: true
515
+ behaviors: false
516
+ mission_control: false
517
+ daemon: false
518
+ emulation:
519
+ cron: null
520
+ agent_teams: null
521
+ tasks: aiwg-mc
522
+ mcp: null
523
+ behaviors: aiwg-mc
524
+ mission_control: aiwg-mc
525
+ daemon: null
526
+ hook_wiring:
527
+ at_link_support: false
528
+ hook_file: .muse/hooks.json
529
+ fallback: full-inject
530
+ context_file: AGENTS.md
531
+ deploy_target: mixed
532
+ aggregated_output: false
533
+
482
534
  openclaw:
483
535
  display_name: OpenClaw
484
536
  status: stable
@@ -0,0 +1,192 @@
1
+ /** Grok Build ACP stdio client. Separate from one-shot headless execution. */
2
+ import { spawn } from 'node:child_process';
3
+ import { redactGrokOutput } from './grok-build-headless.js';
4
+ export class GrokAcpClient {
5
+ child;
6
+ env;
7
+ timeoutMs;
8
+ maxStderrBytes;
9
+ cwd;
10
+ onUpdate;
11
+ pending = new Map();
12
+ nextId = 1;
13
+ stdoutBuffer = '';
14
+ stderrBuffer = '';
15
+ closed = false;
16
+ terminated = false;
17
+ sessionId;
18
+ text = '';
19
+ constructor(options) {
20
+ this.env = options.env ?? process.env;
21
+ this.cwd = options.cwd;
22
+ this.timeoutMs = Math.min(Math.max(options.timeoutMs ?? 30_000, 1), 120_000);
23
+ this.maxStderrBytes = options.maxStderrBytes ?? 1024 * 1024;
24
+ this.onUpdate = options.onUpdate;
25
+ this.child = spawn(options.command ?? 'grok', [...(options.prefixArgs ?? []), '--no-auto-update', ...(options.disableSubagents ? ['--no-subagents'] : []), 'agent', 'stdio'], {
26
+ cwd: options.cwd, env: this.env, stdio: ['pipe', 'pipe', 'pipe'], shell: false,
27
+ });
28
+ this.child.on('error', error => this.failAll(new Error(`Grok ACP launch failed: ${error.message}`)));
29
+ this.child.on('close', code => {
30
+ this.failAll(new Error(`Grok ACP closed (exit ${code ?? 'signal'})`));
31
+ void options.onExit?.();
32
+ });
33
+ this.child.stdout.on('data', (chunk) => this.receive(chunk.toString('utf8')));
34
+ this.child.stderr.on('data', (chunk) => {
35
+ this.stderrBuffer += chunk.toString('utf8');
36
+ if (Buffer.byteLength(this.stderrBuffer) > this.maxStderrBytes) {
37
+ this.failAll(new Error('Grok ACP stderr limit exceeded'));
38
+ this.close();
39
+ }
40
+ });
41
+ }
42
+ get stderr() { return redactGrokOutput(this.stderrBuffer, this.env); }
43
+ failAll(error) {
44
+ this.closed = true;
45
+ for (const [id, pending] of this.pending) {
46
+ clearTimeout(pending.timer);
47
+ pending.reject(error);
48
+ this.pending.delete(id);
49
+ }
50
+ }
51
+ receive(chunk) {
52
+ this.stdoutBuffer += chunk;
53
+ if (this.stdoutBuffer.length > 8 * 1024 * 1024) {
54
+ this.failAll(new Error('Grok ACP stdout limit exceeded'));
55
+ this.close();
56
+ return;
57
+ }
58
+ let end;
59
+ while ((end = this.stdoutBuffer.indexOf('\n')) >= 0) {
60
+ const line = this.stdoutBuffer.slice(0, end).trim();
61
+ this.stdoutBuffer = this.stdoutBuffer.slice(end + 1);
62
+ if (!line)
63
+ continue;
64
+ let message;
65
+ try {
66
+ message = JSON.parse(line);
67
+ }
68
+ catch {
69
+ this.failAll(new Error('Invalid Grok ACP JSON-RPC message'));
70
+ this.close();
71
+ return;
72
+ }
73
+ if (message.method === 'session/update') {
74
+ const params = message.params;
75
+ const update = params?.update;
76
+ if (update) {
77
+ const safe = JSON.parse(redactGrokOutput(JSON.stringify(update), this.env));
78
+ const content = safe.content;
79
+ if (safe.sessionUpdate === 'agent_message_chunk' && typeof content?.text === 'string')
80
+ this.text += content.text;
81
+ this.onUpdate?.(safe);
82
+ }
83
+ continue;
84
+ }
85
+ const id = message.id;
86
+ if (typeof id !== 'number')
87
+ continue;
88
+ const pending = this.pending.get(id);
89
+ if (!pending)
90
+ continue;
91
+ this.pending.delete(id);
92
+ clearTimeout(pending.timer);
93
+ const error = message.error;
94
+ if (error)
95
+ pending.reject(new Error(`Grok ACP request failed: ${redactGrokOutput(String(error.message ?? 'provider error'), this.env)}`));
96
+ else
97
+ pending.resolve((message.result && typeof message.result === 'object' ? message.result : {}));
98
+ }
99
+ }
100
+ request(method, params) {
101
+ if (this.closed)
102
+ return Promise.reject(new Error('Grok ACP connection is closed'));
103
+ const id = this.nextId++;
104
+ return new Promise((resolve, reject) => {
105
+ const timer = setTimeout(() => {
106
+ this.pending.delete(id);
107
+ reject(new Error(`Grok ACP ${method} timed out`));
108
+ this.close();
109
+ }, this.timeoutMs);
110
+ this.pending.set(id, { resolve, reject, timer });
111
+ this.child.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', id, method, params })}\n`, error => {
112
+ if (error) {
113
+ clearTimeout(timer);
114
+ this.pending.delete(id);
115
+ reject(new Error(`Grok ACP ${method} write failed`));
116
+ }
117
+ });
118
+ });
119
+ }
120
+ async initialize() {
121
+ const init = await this.request('initialize', {
122
+ protocolVersion: 1,
123
+ clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: true },
124
+ });
125
+ const methods = Array.isArray(init.authMethods)
126
+ ? init.authMethods.map(item => item.id) : [];
127
+ const authMethod = this.env.XAI_API_KEY && methods.includes('xai.api_key') ? 'xai.api_key'
128
+ : methods.includes('cached_token') ? 'cached_token' : null;
129
+ if (!authMethod) {
130
+ const reason = methods.includes('grok.com')
131
+ ? 'grok.com interactive authentication is not qualified for AIWG ACP'
132
+ : 'no supported non-interactive method was offered';
133
+ throw new Error(`Grok ACP authentication unavailable: ${reason}`);
134
+ }
135
+ await this.request('authenticate', { methodId: authMethod, _meta: { headless: true } });
136
+ const session = await this.request('session/new', { cwd: this.cwd, mcpServers: [] });
137
+ if (typeof session.sessionId !== 'string' || !session.sessionId)
138
+ throw new Error('Grok ACP session/new returned no sessionId');
139
+ this.sessionId = session.sessionId;
140
+ return { authMethod, sessionId: session.sessionId };
141
+ }
142
+ async prompt(prompt, signal) {
143
+ if (!this.sessionId)
144
+ throw new Error('Grok ACP session is not initialized');
145
+ if (!prompt.trim())
146
+ throw new Error('Grok ACP prompt is required');
147
+ const aborted = () => Object.assign(new Error('Grok ACP prompt aborted'), { name: 'AbortError' });
148
+ // A pre-aborted request never starts a provider turn, so there is nothing
149
+ // to cancel. Sending session/cancel here could cancel an unrelated turn.
150
+ if (signal?.aborted)
151
+ throw aborted();
152
+ this.text = '';
153
+ let abortRequested = false;
154
+ const onAbort = () => { abortRequested = true; this.cancel(); };
155
+ signal?.addEventListener('abort', onAbort, { once: true });
156
+ try {
157
+ const result = await this.request('session/prompt', { sessionId: this.sessionId, prompt: [{ type: 'text', text: prompt }] });
158
+ // Grok can deliver final session/update chunks immediately after the
159
+ // completion response; give the pipe a bounded settling window.
160
+ await new Promise(resolve => setTimeout(resolve, 150));
161
+ if (abortRequested || signal?.aborted)
162
+ throw aborted();
163
+ return { text: this.text.trim(), ...(typeof result.stopReason === 'string' ? { stopReason: result.stopReason } : {}) };
164
+ }
165
+ catch (error) {
166
+ if (abortRequested || signal?.aborted)
167
+ throw aborted();
168
+ throw error;
169
+ }
170
+ finally {
171
+ signal?.removeEventListener('abort', onAbort);
172
+ }
173
+ }
174
+ cancel() {
175
+ if (this.closed || !this.sessionId)
176
+ return;
177
+ this.child.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', method: 'session/cancel', params: { sessionId: this.sessionId } })}\n`);
178
+ }
179
+ close() {
180
+ if (this.terminated)
181
+ return;
182
+ this.terminated = true;
183
+ this.failAll(new Error('Grok ACP connection closed'));
184
+ this.child.stdin.end();
185
+ if (!this.child.kill('SIGTERM'))
186
+ return;
187
+ const forceTimer = setTimeout(() => this.child.kill('SIGKILL'), 2_000);
188
+ forceTimer.unref();
189
+ this.child.once('close', () => clearTimeout(forceTimer));
190
+ }
191
+ }
192
+ //# sourceMappingURL=grok-build-acp.js.map
@@ -0,0 +1,251 @@
1
+ /** AIWG-controlled Grok Build dispatch: budgets, cap admission and isolation. */
2
+ import { execFile } from 'node:child_process';
3
+ import { promisify } from 'node:util';
4
+ import { lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, unlink, writeFile } from 'node:fs/promises';
5
+ import { tmpdir } from 'node:os';
6
+ import { join, resolve } from 'node:path';
7
+ import { createHash, randomUUID } from 'node:crypto';
8
+ import { readAiwgConfig, resolveParallelism } from '../config/aiwg-config.js';
9
+ import { runGrokHeadless } from './grok-build-headless.js';
10
+ import { GrokAcpClient } from './grok-build-acp.js';
11
+ const git = promisify(execFile);
12
+ const dispatchers = new Map();
13
+ async function projectKey(projectRoot) {
14
+ const root = await realpath(projectRoot);
15
+ try {
16
+ return await realpath(await gitOut(root, 'rev-parse', '--path-format=absolute', '--git-common-dir'));
17
+ }
18
+ catch (error) {
19
+ if (/not a git repository/i.test(String(error.stderr ?? '')))
20
+ return root;
21
+ throw new Error('Cannot resolve Grok Build project Git identity; dispatch refused', { cause: error });
22
+ }
23
+ }
24
+ async function slotDirectory(key) {
25
+ const isGitDir = await lstat(join(key, 'objects')).then(info => info.isDirectory(), () => false)
26
+ && await lstat(join(key, 'HEAD')).then(info => info.isFile(), () => false);
27
+ const dir = isGitDir
28
+ ? join(key, 'aiwg-grok-dispatch-slots')
29
+ : join(tmpdir(), `aiwg-grok-dispatch-${process.getuid?.() ?? 'user'}-${createHash('sha256').update(key).digest('hex')}`);
30
+ await mkdir(dir, { recursive: true, mode: 0o700 });
31
+ const info = await lstat(dir);
32
+ if (!info.isDirectory() || (process.platform !== 'win32' && ((info.mode & 0o077) !== 0 || info.uid !== process.getuid?.()))) {
33
+ throw new Error('Grok Build dispatch slot directory is not private to this user');
34
+ }
35
+ return dir;
36
+ }
37
+ /** Atomic project slots are shared by independent AIWG processes and Git worktrees. */
38
+ export async function acquireGrokProjectSlot(key, limit) {
39
+ if (!Number.isInteger(limit) || limit < 1)
40
+ throw new Error('Invalid Grok Build project parallelism cap');
41
+ const dir = await slotDirectory(key);
42
+ const occupied = await readdir(dir);
43
+ if (occupied.some(name => /^\d+\.json$/.test(name) && Number.parseInt(name, 10) >= limit)) {
44
+ throw new Error('Grok Build project parallelism cap was lowered while workers are active; wait for them to finish');
45
+ }
46
+ slot: for (let index = 0; index < limit; index++) {
47
+ const file = join(dir, `${index}.json`);
48
+ const token = randomUUID();
49
+ let handle;
50
+ try {
51
+ handle = await open(file, 'wx', 0o600);
52
+ }
53
+ catch (error) {
54
+ if (error.code !== 'EEXIST')
55
+ throw error;
56
+ let info;
57
+ try {
58
+ info = await lstat(file);
59
+ }
60
+ catch (race) {
61
+ if (race.code === 'ENOENT') {
62
+ index--;
63
+ continue slot;
64
+ }
65
+ throw race;
66
+ }
67
+ if (!info.isFile() || (process.platform !== 'win32' && (info.mode & 0o077) !== 0)) {
68
+ throw new Error(`Unsafe Grok Build dispatch slot ${index}; review ownership before retrying`);
69
+ }
70
+ let owner;
71
+ for (let attempt = 0; attempt < 20; attempt++) {
72
+ try {
73
+ owner = JSON.parse(await readFile(file, 'utf8'));
74
+ break;
75
+ }
76
+ catch (readError) {
77
+ if (readError.code === 'ENOENT') {
78
+ index--;
79
+ continue slot;
80
+ }
81
+ if (attempt === 19)
82
+ throw new Error(`Incomplete Grok Build dispatch slot ${index}; review ownership before retrying`);
83
+ await new Promise(resolveWait => setTimeout(resolveWait, 10));
84
+ }
85
+ }
86
+ if (!owner)
87
+ throw new Error(`Incomplete Grok Build dispatch slot ${index}; review ownership before retrying`);
88
+ if (!Number.isInteger(owner.pid) || (owner.pid ?? 0) < 1 || typeof owner.token !== 'string') {
89
+ throw new Error(`Invalid Grok Build dispatch slot ${index}; review ownership before retrying`);
90
+ }
91
+ try {
92
+ process.kill(owner.pid, 0);
93
+ }
94
+ catch (probeError) {
95
+ if (probeError.code === 'ESRCH') {
96
+ throw new Error(`Stale Grok Build dispatch slot ${index}; confirm no worker remains, then remove it explicitly`);
97
+ }
98
+ if (probeError.code !== 'EPERM')
99
+ throw probeError;
100
+ }
101
+ continue;
102
+ }
103
+ try {
104
+ await handle.writeFile(`${JSON.stringify({ pid: process.pid, token, limit })}\n`);
105
+ }
106
+ catch (error) {
107
+ await handle.close();
108
+ await unlink(file);
109
+ throw error;
110
+ }
111
+ await handle.close();
112
+ let released = false;
113
+ return async () => {
114
+ if (released)
115
+ return;
116
+ const owner = JSON.parse(await readFile(file, 'utf8'));
117
+ if (owner.token !== token)
118
+ throw new Error('Grok Build dispatch slot ownership changed; refusing to release another worker');
119
+ await unlink(file);
120
+ released = true;
121
+ };
122
+ }
123
+ throw new Error(`Grok Build project parallelism cap ${limit} reached`);
124
+ }
125
+ async function gitOut(cwd, ...args) {
126
+ const result = await git('git', args, { cwd, timeout: 15_000, maxBuffer: 1024 * 1024 });
127
+ return result.stdout.trim();
128
+ }
129
+ /** Create a detached worktree and save its record in Git's per-worktree metadata. */
130
+ export async function prepareGrokWorktree(source, owner = randomUUID()) {
131
+ const root = await gitOut(source, 'rev-parse', '--show-toplevel');
132
+ const dirty = await gitOut(root, 'status', '--porcelain');
133
+ if (dirty)
134
+ throw new Error('Grok Build worktree dispatch requires a clean source checkout; commit or preserve current changes before dispatch');
135
+ const baseCommit = await gitOut(root, 'rev-parse', 'HEAD');
136
+ const worktree = await mkdtemp(join(tmpdir(), 'aiwg-grok-worktree-'));
137
+ await gitOut(root, 'worktree', 'add', '--detach', worktree, baseCommit);
138
+ const gitDir = await gitOut(worktree, 'rev-parse', '--absolute-git-dir');
139
+ const record = {
140
+ schema: 'aiwg.grok-build.worktree.v1', owner, source: resolve(root), path: worktree,
141
+ baseCommit, createdAt: new Date().toISOString(),
142
+ recovery: `git -C ${JSON.stringify(root)} worktree list --porcelain`,
143
+ };
144
+ await writeFile(join(gitDir, 'aiwg-grok-owner.json'), `${JSON.stringify(record, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
145
+ return record;
146
+ }
147
+ export class GrokBuildDispatcher {
148
+ active = 0;
149
+ maxParallel;
150
+ key;
151
+ constructor(maxParallel, key) { this.maxParallel = maxParallel; this.key = key; }
152
+ static async forProject(projectRoot) {
153
+ const config = await readAiwgConfig(projectRoot);
154
+ const cap = resolveParallelism(config?.parallelism, 'grok-build').max_parallel_subagents;
155
+ if (!Number.isInteger(cap) || cap < 1)
156
+ throw new Error('Invalid Grok Build project parallelism cap');
157
+ const key = await projectKey(projectRoot);
158
+ const existing = dispatchers.get(key);
159
+ if (existing) {
160
+ existing.maxParallel = cap;
161
+ return existing;
162
+ }
163
+ const dispatcher = new GrokBuildDispatcher(cap, key);
164
+ dispatchers.set(key, dispatcher);
165
+ return dispatcher;
166
+ }
167
+ get activeDispatches() { return this.active; }
168
+ async openAcp(options) {
169
+ if (await projectKey(options.projectRoot) !== this.key)
170
+ throw new Error('Grok Build dispatcher project root changed');
171
+ if (this.active >= this.maxParallel)
172
+ throw new Error(`Grok Build project parallelism cap ${this.maxParallel} reached`);
173
+ if (!await options.authorize())
174
+ throw new Error('Grok Build dispatch authorization gate denied');
175
+ if (!await options.budgetRemaining())
176
+ throw new Error('Grok Build orchestration budget exhausted');
177
+ const release = await acquireGrokProjectSlot(this.key, this.maxParallel);
178
+ this.active += 1;
179
+ let settle;
180
+ let fail;
181
+ const exited = new Promise((resolveExit, rejectExit) => { settle = resolveExit; fail = rejectExit; });
182
+ // The process can exit before its caller asks to close the session.
183
+ // Keep the rejection observable through close() without an unhandled one.
184
+ void exited.catch(() => { });
185
+ let worktree;
186
+ let client;
187
+ let released = false;
188
+ const releaseAfterExit = async () => {
189
+ if (released)
190
+ return;
191
+ released = true;
192
+ this.active -= 1;
193
+ try {
194
+ await release();
195
+ settle();
196
+ }
197
+ catch (error) {
198
+ fail(error instanceof Error ? error : new Error(String(error)));
199
+ }
200
+ };
201
+ try {
202
+ worktree = options.isolate ? await prepareGrokWorktree(options.projectRoot) : undefined;
203
+ const env = { ...process.env, ...options.env };
204
+ client = new GrokAcpClient({
205
+ ...options, cwd: worktree?.path ?? options.projectRoot, env,
206
+ disableSubagents: true, onExit: releaseAfterExit,
207
+ });
208
+ const { authMethod, sessionId } = await client.initialize();
209
+ return {
210
+ client, authMethod, sessionId, ...(worktree ? { worktree } : {}),
211
+ close: async () => { client.close(); await exited; },
212
+ };
213
+ }
214
+ catch (error) {
215
+ if (client) {
216
+ client.close();
217
+ await exited;
218
+ }
219
+ else
220
+ await releaseAfterExit();
221
+ throw error;
222
+ }
223
+ }
224
+ async dispatch(options) {
225
+ if (await projectKey(options.projectRoot) !== this.key)
226
+ throw new Error('Grok Build dispatcher project root changed');
227
+ if (this.active >= this.maxParallel)
228
+ throw new Error(`Grok Build project parallelism cap ${this.maxParallel} reached`);
229
+ if (!await options.authorize())
230
+ throw new Error('Grok Build dispatch authorization gate denied');
231
+ if (!await options.budgetRemaining())
232
+ throw new Error('Grok Build orchestration budget exhausted');
233
+ const release = await acquireGrokProjectSlot(this.key, this.maxParallel);
234
+ this.active += 1;
235
+ try {
236
+ const worktree = options.isolate ? await prepareGrokWorktree(options.projectRoot) : undefined;
237
+ // Grok's internal autonomous subagent fan-out has no documented hard
238
+ // project cap. Disable it in AIWG-controlled headless workers so every
239
+ // parallel worker consumes one dispatcher slot. Interactive Grok use
240
+ // remains outside this bounded API and must not be claimed as enforced.
241
+ const env = { ...process.env, ...options.env, GROK_SUBAGENTS: '0' };
242
+ const result = await runGrokHeadless({ ...options, cwd: worktree?.path ?? options.projectRoot, env, disableSubagents: true });
243
+ return { result, ...(worktree ? { worktree } : {}) };
244
+ }
245
+ finally {
246
+ this.active -= 1;
247
+ await release();
248
+ }
249
+ }
250
+ }
251
+ //# sourceMappingURL=grok-build-dispatch.js.map