@aiwg/cli 2026.10.4 → 2026.10.6

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 (220) hide show
  1. package/agentic/code/addons/composition-engine/lib/runtime.mjs +1401 -0
  2. package/agentic/code/addons/composition-engine/lib/validator.mjs +513 -0
  3. package/agentic/code/addons/composition-engine/schemas/flow-graph.schema.json +372 -0
  4. package/agentic/code/providers/model-capabilities.v1.json +74 -50
  5. package/bin/aiwg.mjs +3 -1
  6. package/dist/src/artifacts/browser-export.js +1 -0
  7. package/dist/src/artifacts/citation-parser.js +8 -1
  8. package/dist/src/artifacts/cli.js +72 -9
  9. package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
  10. package/dist/src/artifacts/fortemi-core-sync.js +26 -8
  11. package/dist/src/artifacts/graph-query.js +18 -8
  12. package/dist/src/artifacts/index-adapters.js +339 -0
  13. package/dist/src/artifacts/index-builder.js +146 -16
  14. package/dist/src/artifacts/index-files.js +15 -4
  15. package/dist/src/artifacts/index-preparation.js +91 -26
  16. package/dist/src/artifacts/index-reader.js +44 -0
  17. package/dist/src/artifacts/index-refresh.js +130 -56
  18. package/dist/src/artifacts/index-status.js +20 -5
  19. package/dist/src/artifacts/index-worker.mjs +9 -7
  20. package/dist/src/artifacts/memory-maintenance.js +503 -0
  21. package/dist/src/artifacts/prebuilt-relations.js +3 -1
  22. package/dist/src/artifacts/query-engine.js +263 -108
  23. package/dist/src/artifacts/relations-builder.js +2 -2
  24. package/dist/src/artifacts/source-graph.js +2 -2
  25. package/dist/src/artifacts/types.js +9 -1
  26. package/dist/src/cli/handlers/decision.js +19 -1
  27. package/dist/src/cli/handlers/guided-setup.js +470 -0
  28. package/dist/src/cli/handlers/help.js +2 -2
  29. package/dist/src/cli/handlers/housekeeper.js +1110 -0
  30. package/dist/src/cli/handlers/index.js +4 -2
  31. package/dist/src/cli/handlers/init.js +41 -6
  32. package/dist/src/cli/handlers/local-executor.js +5 -3
  33. package/dist/src/cli/handlers/mc.js +509 -53
  34. package/dist/src/cli/handlers/models.js +32 -2
  35. package/dist/src/cli/handlers/ralph-launcher.js +76 -4
  36. package/dist/src/cli/handlers/rules.js +1 -1
  37. package/dist/src/cli/handlers/script-runner.js +73 -2
  38. package/dist/src/cli/handlers/serve.js +5 -3
  39. package/dist/src/cli/handlers/sessions.js +40 -6
  40. package/dist/src/cli/handlers/setup.js +428 -1
  41. package/dist/src/cli/handlers/skill-lint.js +1 -1
  42. package/dist/src/cli/handlers/subcommands.js +118 -8
  43. package/dist/src/cli/handlers/use.js +279 -93
  44. package/dist/src/cli/handlers/workspace.js +3 -1
  45. package/dist/src/cli/prompt-utils.js +8 -0
  46. package/dist/src/cli/router.js +16 -1
  47. package/dist/src/config/aiwg-config.js +42 -0
  48. package/dist/src/config/cli.js +7 -3
  49. package/dist/src/config/decision-config.js +14 -1
  50. package/dist/src/config/native-sandbox-warnings.js +25 -0
  51. package/dist/src/contributors/validation.js +6 -5
  52. package/dist/src/decision/admission.js +7 -3
  53. package/dist/src/decision/benchmark.js +469 -0
  54. package/dist/src/decision/ledger.js +22 -3
  55. package/dist/src/decision/pricing.js +147 -0
  56. package/dist/src/decision/qualification/gate-evidence.js +18 -15
  57. package/dist/src/decision/qualification/load-staged.js +539 -0
  58. package/dist/src/decision/qualification/load.js +109 -33
  59. package/dist/src/decision/qualification/runner.js +5 -2
  60. package/dist/src/decision/review/service.js +6 -4
  61. package/dist/src/decision/review/validate.js +23 -2
  62. package/dist/src/decision/savings.js +8 -3
  63. package/dist/src/discovery/index.js +492 -0
  64. package/dist/src/discovery/interview.js +233 -0
  65. package/dist/src/discovery/plan-apply.js +571 -0
  66. package/dist/src/discovery/plan-store.js +171 -0
  67. package/dist/src/discovery/plan-types.js +2 -0
  68. package/dist/src/discovery/plan-validation.js +139 -0
  69. package/dist/src/discovery/types.js +2 -0
  70. package/dist/src/extensions/commands/definitions.js +49 -9
  71. package/dist/src/extensions/manifest.js +71 -44
  72. package/dist/src/extensions/project-local-discovery.js +1 -1
  73. package/dist/src/extensions/project-quickref.js +18 -17
  74. package/dist/src/extensions/validation.js +32 -29
  75. package/dist/src/housekeeper/daemon-config.js +148 -0
  76. package/dist/src/housekeeper/ipc.js +84 -0
  77. package/dist/src/housekeeper/lifecycle.js +148 -0
  78. package/dist/src/housekeeper/platform.js +35 -0
  79. package/dist/src/housekeeper/status.js +70 -0
  80. package/dist/src/housekeeper/units.js +114 -0
  81. package/dist/src/jobs/flow.js +22 -21
  82. package/dist/src/lint/rule-activation.js +20 -5
  83. package/dist/src/lint/runner.js +1 -1
  84. package/dist/src/mcp/cli.mjs +5 -6
  85. package/dist/src/mcp/config-file.mjs +6 -2
  86. package/dist/src/mcp/config-layers.mjs +23 -7
  87. package/dist/src/mcp/profiles.js +18 -31
  88. package/dist/src/mcp/profiles.mjs +18 -32
  89. package/dist/src/mcp/registry.js +7 -27
  90. package/dist/src/mcp/registry.mjs +7 -28
  91. package/dist/src/mcp/server.mjs +34 -1
  92. package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
  93. package/dist/src/mcp/tools/command-run.mjs +3 -2
  94. package/dist/src/mcp/tools/decision.mjs +49 -48
  95. package/dist/src/mcp/tools/discovery.mjs +46 -21
  96. package/dist/src/mcp/tools/orchestration.mjs +22 -22
  97. package/dist/src/mcp/tools/subsystems.mjs +9 -8
  98. package/dist/src/mcp/tools/worker-invoke.mjs +17 -4
  99. package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
  100. package/dist/src/memory/audit.js +719 -0
  101. package/dist/src/memory/canonical-context.js +392 -13
  102. package/dist/src/memory/canonical-maintenance.js +95 -0
  103. package/dist/src/memory/cli-result.js +22 -0
  104. package/dist/src/memory/cli.js +176 -0
  105. package/dist/src/memory/context-pack.js +57 -6
  106. package/dist/src/memory/cost.js +512 -0
  107. package/dist/src/memory/firewall-classification.d.mts +7 -0
  108. package/dist/src/memory/firewall-classification.mjs +32 -0
  109. package/dist/src/memory/index.js +8 -0
  110. package/dist/src/memory/line-maintenance.js +68 -0
  111. package/dist/src/memory/maintenance-cli.js +286 -0
  112. package/dist/src/memory/maintenance-contract.js +136 -0
  113. package/dist/src/memory/maintenance-index.js +18 -0
  114. package/dist/src/memory/maintenance-owner.js +2 -0
  115. package/dist/src/memory/maintenance-record.js +138 -0
  116. package/dist/src/memory/maintenance.js +254 -0
  117. package/dist/src/memory/provider-memory-adapter.js +154 -0
  118. package/dist/src/memory/recommend-cli.js +83 -0
  119. package/dist/src/memory/recommend.js +269 -0
  120. package/dist/src/memory/scheduled.js +81 -0
  121. package/dist/src/memory/taxonomy.js +44 -0
  122. package/dist/src/mission-protocol/codecs.js +19 -9
  123. package/dist/src/models/config-loader.js +11 -1
  124. package/dist/src/models/model-capabilities.v1.json +74 -50
  125. package/dist/src/models/provider-policy.js +125 -62
  126. package/dist/src/models/resolver.js +45 -8
  127. package/dist/src/models/worker-installation.d.mts +7 -0
  128. package/dist/src/models/worker-installation.mjs +169 -37
  129. package/dist/src/models/wrapper-route.js +1 -1
  130. package/dist/src/output-modes/registry.js +8 -7
  131. package/dist/src/plugin/metadata-validator.js +1 -1
  132. package/dist/src/providers/deploy-version.d.mts +1 -0
  133. package/dist/src/providers/deploy-version.mjs +17 -0
  134. package/dist/src/providers/provider-definitions.js +19 -16
  135. package/dist/src/providers/skill-ownership.d.mts +11 -2
  136. package/dist/src/providers/skill-ownership.mjs +35 -17
  137. package/dist/src/rules/activation.d.mts +11 -2
  138. package/dist/src/rules/activation.mjs +82 -6
  139. package/dist/src/rules/inventory.js +1 -1
  140. package/dist/src/rules/rule-frontmatter.schema.json +2 -0
  141. package/dist/src/schema/zod-validation.d.mts +6 -0
  142. package/dist/src/schema/zod-validation.mjs +50 -0
  143. package/dist/src/serve/executor-registry.js +297 -20
  144. package/dist/src/serve/executor-token.d.mts +1 -0
  145. package/dist/src/serve/executor-token.mjs +8 -0
  146. package/dist/src/serve/shared-host-scheduler.js +1102 -31
  147. package/dist/src/serve/worker-invocation.js +114 -15
  148. package/dist/src/sessions/adapters/claude.js +19 -18
  149. package/dist/src/sessions/adapters/codex.js +33 -19
  150. package/dist/src/sessions/adapters/copilot.js +14 -13
  151. package/dist/src/sessions/adapters/cursor.js +19 -18
  152. package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
  153. package/dist/src/sessions/adapters/factory.js +11 -10
  154. package/dist/src/sessions/adapters/generic.js +32 -23
  155. package/dist/src/sessions/adapters/grokbot.js +35 -35
  156. package/dist/src/sessions/adapters/hermes.js +20 -19
  157. package/dist/src/sessions/adapters/muse.js +50 -49
  158. package/dist/src/sessions/adapters/omp.js +5 -4
  159. package/dist/src/sessions/adapters/openclaw.js +30 -29
  160. package/dist/src/sessions/adapters/opencode.js +26 -26
  161. package/dist/src/sessions/adapters/openhuman.js +24 -23
  162. package/dist/src/sessions/adapters/pi.js +5 -4
  163. package/dist/src/sessions/adapters/windsurf.js +8 -8
  164. package/dist/src/sessions/analytics.js +10 -9
  165. package/dist/src/sessions/batch-contracts.js +1 -1
  166. package/dist/src/sessions/batch-import.js +202 -2
  167. package/dist/src/sessions/candidates.js +7 -6
  168. package/dist/src/sessions/contracts.js +73 -54
  169. package/dist/src/sessions/coverage-preflight.js +26 -1
  170. package/dist/src/sessions/output-registration.js +11 -10
  171. package/dist/src/sessions/policy.js +18 -7
  172. package/dist/src/sessions/refresh.js +2 -3
  173. package/dist/src/sessions/repository.js +4 -2
  174. package/dist/src/sessions/workspace-discovery.js +92 -26
  175. package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
  176. package/dist/src/smiths/context-pipeline/claude-hook.js +42 -6
  177. package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
  178. package/dist/src/smiths/context-pipeline/workspace-context.js +106 -10
  179. package/dist/src/update/checker.d.mts +4 -0
  180. package/dist/src/update/checker.mjs +14 -0
  181. package/dist/src/writing/exemplar-selection.js +6 -6
  182. package/dist/src/writing/voice-evaluation.js +24 -23
  183. package/dist/src/writing/writer-migration.js +14 -13
  184. package/dist/src/writing/writer-profile.js +19 -18
  185. package/dist/src/writing/writing-brief.js +18 -17
  186. package/dist/src/writing/writing-receipt.js +47 -46
  187. package/package.json +5 -2
  188. package/schemas/decision/DecisionReview.schema.json +78 -1
  189. package/schemas/mission-v1.schema.json +3 -0
  190. package/tools/agents/deploy-agents.mjs +67 -39
  191. package/tools/agents/providers/antigravity.mjs +6 -1
  192. package/tools/agents/providers/base.mjs +19 -13
  193. package/tools/agents/providers/claude.mjs +1 -1
  194. package/tools/agents/providers/codex.mjs +50 -56
  195. package/tools/agents/providers/copilot.mjs +8 -2
  196. package/tools/agents/providers/cursor.mjs +1 -1
  197. package/tools/agents/providers/deepseek-harness.mjs +1 -1
  198. package/tools/agents/providers/factory.mjs +7 -1
  199. package/tools/agents/providers/grok-build.mjs +18 -2
  200. package/tools/agents/providers/grokbot.mjs +1 -1
  201. package/tools/agents/providers/hermes.mjs +7 -13
  202. package/tools/agents/providers/muse-hooks.mjs +21 -14
  203. package/tools/agents/providers/muse.mjs +7 -2
  204. package/tools/agents/providers/omp.mjs +28 -4
  205. package/tools/agents/providers/opencode.mjs +14 -5
  206. package/tools/agents/providers/openhuman.mjs +1 -1
  207. package/tools/agents/providers/pi.mjs +1 -1
  208. package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
  209. package/tools/agents/providers/rule-delivery.mjs +263 -71
  210. package/tools/agents/providers/windsurf.mjs +7 -0
  211. package/tools/cli/workspace-status.mjs +5 -0
  212. package/tools/commands/deploy-prompts-codex.mjs +11 -8
  213. package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
  214. package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
  215. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  216. package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
  217. package/tools/ralph-external/process-monitor.mjs +7 -4
  218. package/tools/ralph-external/session-launcher.mjs +280 -32
  219. package/tools/skills/deploy-skills-codex.mjs +11 -7
  220. package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
@@ -4,7 +4,7 @@ import path from 'node:path';
4
4
  import { createHash } from 'node:crypto';
5
5
  import YAML from 'yaml';
6
6
  import { importImpl } from '../../_resolve-impl.mjs';
7
- import { collectFrameworkArtifacts, getAddonFiles, isKernelSkill, listMdFiles, listSkillDirs, normalizeDeploymentMode, resolveAiwgRoot } from './base.mjs';
7
+ import { withRuleDeployment, collectFrameworkArtifacts, getAddonFiles, isKernelSkill, listMdFiles, listSkillDirs, normalizeDeploymentMode, resolveAiwgRoot } from './base.mjs';
8
8
  export const name = 'omp';
9
9
  export const aliases = ['oh-my-pi'];
10
10
  export const paths = { agents: '.omp/agents', commands: '.omp/prompts', skills: '.agents/skills', rules: '.omp/rules' };
@@ -131,7 +131,7 @@ function deployType(files, target, opts, type, transform) {
131
131
  }
132
132
  export const deployAgents = (files, target, opts = {}) => deployType(files, target, opts, 'agents', transformAgent);
133
133
  export const deployCommands = (files, target, opts = {}) => deployType(files, target, opts, 'prompts', transformCommand);
134
- export const deployRules = (files, target, opts = {}) => deployType(files, target, opts, 'rules', transformRule);
134
+ export const deployRules = (files, target, opts = {}) => opts.ruleDelivery ? 0 : deployType(files, target, opts, 'rules', transformRule);
135
135
  export function deploySkills(dirs, target, opts = {}) {
136
136
  let count = 0; const seen = new Map(); const root = roots(target, opts);
137
137
  for (const dir of [...new Set(dirs)]) {
@@ -223,10 +223,20 @@ export function deployExtensionBridge(target, opts = {}) {
223
223
  return writeOwned(path.join(roots(target, opts).native, 'extensions/aiwg-bridge.ts'), fs.readFileSync(src, 'utf8'), src, opts, 'omp-extension');
224
224
  }
225
225
  export async function postDeploy(target, opts) {
226
- if (opts.createAgentsMd || (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly)) createAgentsMd(target, opts.srcRoot, opts.dryRun);
226
+ if (opts.contextFiles !== false && (opts.createAgentsMd || (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly))) createAgentsMd(target, opts.srcRoot, opts.dryRun);
227
227
  }
228
228
  export const getFileExtension = () => '.md';
229
229
  export async function deploy(opts) {
230
+ return withRuleDeployment(opts, { name, paths, kernelSkillsPath }, async staged => {
231
+ let count = await deploySelected(staged);
232
+ for (const srcRoot of staged.additionalSources || []) {
233
+ count += await deploySelected({ ...staged, srcRoot });
234
+ }
235
+ return count;
236
+ });
237
+ }
238
+
239
+ async function deploySelected(opts) {
230
240
  const mode = normalizeDeploymentMode(opts.mode);
231
241
  const include = { includeAgents: true, includeCommands: opts.deployCommands || opts.commandsOnly, includeSkills: opts.deploySkills || opts.skillsOnly, includeRules: opts.deployRules || opts.rulesOnly };
232
242
  const directSource = ['agents', 'commands', 'skills', 'rules'].some(type => fs.existsSync(path.join(opts.srcRoot, type)));
@@ -251,7 +261,21 @@ export async function deploy(opts) {
251
261
  let count = 0;
252
262
  if (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly) count += deployAgents(selected('agents'), opts.target, opts);
253
263
  if (include.includeCommands && !opts.skillsOnly && !opts.rulesOnly) count += deployCommands(selected('commands'), opts.target, opts);
254
- if (include.includeSkills && !opts.commandsOnly && !opts.rulesOnly) count += deploySkills(selected('skills'), opts.target, opts);
264
+ if (include.includeSkills && !opts.commandsOnly && !opts.rulesOnly) {
265
+ // Different frameworks may index same-named standard skills. With copying
266
+ // disabled they share only a stale-copy cleanup destination, not a native
267
+ // definition slot. Keep one cleanup pass; retain collision checks for every
268
+ // kernel skill and for explicitly copied standard skills.
269
+ const lazyNames = new Set();
270
+ const skills = selected('skills').filter(dir => {
271
+ if (opts.copyStandardSkills || isKernelSkill(dir)) return true;
272
+ const basename = path.basename(dir);
273
+ if (lazyNames.has(basename)) return false;
274
+ lazyNames.add(basename);
275
+ return true;
276
+ });
277
+ count += deploySkills(skills, opts.target, opts);
278
+ }
255
279
  if (include.includeRules && !opts.commandsOnly && !opts.skillsOnly) count += deployRules(selected('rules'), opts.target, opts);
256
280
  if (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly) count += deployExtensionBridge(opts.target, opts);
257
281
  await postDeploy(opts.target, opts); return count;
@@ -23,7 +23,9 @@ const staticModelCatalog = _require('../../../agentic/code/providers/model-catal
23
23
  let fs;
24
24
  try { const gfs = _require('graceful-fs'); gfs.gracefulify(realFs); fs = realFs; } catch { fs = realFs; }
25
25
  import path from 'path';
26
+ import { importImpl } from '../../_resolve-impl.mjs';
26
27
  import {
28
+ withRuleDeployment,
27
29
  ensureDir,
28
30
  listMdFiles,
29
31
  listMdFilesRecursive,
@@ -50,6 +52,7 @@ import {
50
52
  filterCommandsAgainstSkills,
51
53
  deploySoulCompanions
52
54
  } from './base.mjs';
55
+ const { assertConfigDestination, writeConfigAtomic } = await importImpl(import.meta.url, 'mcp/config-file.mjs');
53
56
  const modelCatalog = loadRuntimeModelCatalog(staticModelCatalog);
54
57
 
55
58
  // ============================================================================
@@ -375,6 +378,7 @@ export function deploySkills(skillDirs, targetDir, opts) {
375
378
  * Deploy rules to .opencode/rule/
376
379
  */
377
380
  export function deployRules(ruleFiles, targetDir, opts) {
381
+ if (opts.ruleDelivery) return [];
378
382
  const destDir = path.join(targetDir, paths.rules);
379
383
  ensureDir(destDir, opts.dryRun);
380
384
  cleanupOldRuleFiles(destDir, opts);
@@ -394,9 +398,9 @@ export function deployRules(ruleFiles, targetDir, opts) {
394
398
  * Non-destructive: a malformed existing opencode.json is left untouched (warn,
395
399
  * skip) rather than overwritten.
396
400
  *
397
- * @returns {boolean} true if the config was changed (or would be, in dry-run)
401
+ * @returns {Promise<boolean>} true if the config was changed (or would be, in dry-run)
398
402
  */
399
- export function mergeOpenCodeInstructions(targetDir, opts = {}) {
403
+ export async function mergeOpenCodeInstructions(targetDir, opts = {}) {
400
404
  const RULE_GLOB = `${paths.rules}*.md`; // .opencode/rule/*.md — opencode supports globs in instructions (verified in sst/opencode session/instruction.ts)
401
405
  // opencode auto-loads AGENTS.md/CLAUDE.md/CONTEXT.md but NOT AIWG.md, and the
402
406
  // generated AGENTS.md is a thin link-index that points to AIWG.md. The
@@ -407,6 +411,7 @@ export function mergeOpenCodeInstructions(targetDir, opts = {}) {
407
411
  const AIWG = 'AIWG.md';
408
412
  const wanted = [RULE_GLOB, AGENTS, AIWG];
409
413
  const configPath = path.join(targetDir, 'opencode.json');
414
+ await assertConfigDestination(configPath, targetDir);
410
415
 
411
416
  let config = {};
412
417
  if (fs.existsSync(configPath)) {
@@ -433,7 +438,7 @@ export function mergeOpenCodeInstructions(targetDir, opts = {}) {
433
438
 
434
439
  // Preserve operator-authored entries; append only what's missing, deduped.
435
440
  config.instructions = [...existing, ...missing];
436
- fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
441
+ await writeConfigAtomic(configPath, `${JSON.stringify(config, null, 2)}\n`, { projectRoot: targetDir });
437
442
  if (opts.verbose) {
438
443
  console.log(`Wired ${missing.length} entr${missing.length === 1 ? 'y' : 'ies'} into opencode.json instructions[]: ${missing.join(', ')}`);
439
444
  }
@@ -503,7 +508,7 @@ export async function postDeploy(targetDir, opts) {
503
508
  initializeFrameworkWorkspace(targetDir, opts.mode, opts.dryRun, opts.srcRoot);
504
509
 
505
510
  if (opts.createAgentsMd) {
506
- createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
511
+ if (opts.contextFiles !== false) createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
507
512
  }
508
513
 
509
514
  // PUW-035 (#1136): emit SDLC primary roles as TUI modes.
@@ -527,6 +532,10 @@ export function getFileExtension(type) {
527
532
  // ============================================================================
528
533
 
529
534
  export async function deploy(opts) {
535
+ return withRuleDeployment(opts, { name, paths, kernelSkillsPath }, deploySelected);
536
+ }
537
+
538
+ async function deploySelected(opts) {
530
539
  const {
531
540
  srcRoot,
532
541
  target,
@@ -637,7 +646,7 @@ export async function deploy(opts) {
637
646
  // #1548: rules on disk are inert unless referenced from opencode.json
638
647
  // instructions[]. Wire them so opencode actually loads them.
639
648
  try {
640
- mergeOpenCodeInstructions(target, opts);
649
+ await mergeOpenCodeInstructions(target, opts);
641
650
  } catch (err) {
642
651
  console.warn(`Warning: could not wire opencode.json instructions[]: ${err && err.message ? err.message : err}`);
643
652
  }
@@ -173,7 +173,7 @@ export async function postDeploy(targetDir, opts) {
173
173
  opts.createAgentsMd ||
174
174
  (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly)
175
175
  ) {
176
- createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
176
+ if (opts.contextFiles !== false) createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
177
177
  }
178
178
  }
179
179
 
@@ -128,7 +128,7 @@ export function createAgentsMd(target, srcRoot, dryRun) {
128
128
 
129
129
  export async function postDeploy(targetDir, opts) {
130
130
  if (opts.createAgentsMd || (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly)) {
131
- createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
131
+ if (opts.contextFiles !== false) createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
132
132
  }
133
133
  if (!opts.quiet && (opts.deployCommands || opts.deploySkills || opts.commandsOnly || opts.skillsOnly)) {
134
134
  console.log('Pi project resources are trust-gated; approve the project with `/trust` (restart required) or use `pi --approve` for a reviewed one-shot run.');
@@ -81,6 +81,10 @@ function prepareInChild({ job, attempt, sessionRoot, poolDescriptor, workerPath,
81
81
  let outcome;
82
82
  let killTimer;
83
83
  let timedOut = false;
84
+ let exited = false;
85
+ let disconnected = false;
86
+ let exitCode;
87
+ let exitSignal;
84
88
  const finish = () => {
85
89
  if (settled) return;
86
90
  settled = true;
@@ -107,19 +111,30 @@ function prepareInChild({ job, attempt, sessionRoot, poolDescriptor, workerPath,
107
111
  timer.unref?.();
108
112
  child.once('error', error => {
109
113
  // A spawn failure has no operating-system child to reap. Every error
110
- // after a pid is assigned still waits for the exit event below.
114
+ // after a pid is assigned still waits for exit and IPC disconnect below.
111
115
  if (!child.pid) { outcome = { error }; finish(); }
112
116
  else stop(error);
113
117
  });
114
- // Settle only after the operating system reports process exit. This keeps
115
- // every worker in activeChildren until it is confirmed gone, including workers
116
- // that send a response and retain an unexpected live handle.
117
- child.once('exit', (code, signal) => {
118
- if (outcome?.value && (code !== 0 || signal)) {
119
- outcome = { error: new Error(`Provider preparation worker exited ${signal || code || 'without status'} after responding for ${job.provider}`) };
118
+ // Exit confirms termination; disconnect confirms pending IPC messages have
119
+ // drained. Either event can arrive first. Keep workers active until both,
120
+ // including workers that respond and retain an unexpected live handle.
121
+ const finishAfterDisconnectAndExit = () => {
122
+ if (!exited || !disconnected) return;
123
+ if (outcome?.value && (exitCode !== 0 || exitSignal)) {
124
+ outcome = { error: new Error(`Provider preparation worker exited ${exitSignal || exitCode || 'without status'} after responding for ${job.provider}`) };
120
125
  }
121
- if (!outcome) outcome = { error: new Error(`${timedOut ? 'Provider preparation timed out' : `Provider preparation worker exited ${code ?? 'without status'}`} for ${job.provider}${stderrBytes ? `: ${Buffer.concat(stderr).toString('utf8').trim()}` : ''}`) };
126
+ if (!outcome) outcome = { error: new Error(`${timedOut ? 'Provider preparation timed out' : `Provider preparation worker exited ${exitCode ?? 'without status'}`} for ${job.provider}${stderrBytes ? `: ${Buffer.concat(stderr).toString('utf8').trim()}` : ''}`) };
122
127
  finish();
128
+ };
129
+ child.once('exit', (code, signal) => {
130
+ exited = true;
131
+ exitCode = code;
132
+ exitSignal = signal;
133
+ finishAfterDisconnectAndExit();
134
+ });
135
+ child.once('disconnect', () => {
136
+ disconnected = true;
137
+ finishAfterDisconnectAndExit();
123
138
  });
124
139
  child.once('message', response => {
125
140
  try {
@@ -137,7 +152,7 @@ function prepareInChild({ job, attempt, sessionRoot, poolDescriptor, workerPath,
137
152
  if (response.type !== 'prepared') throw new Error('Invalid provider preparation worker response type');
138
153
  outcome = { value: { detached: readPlan(response, expectedPlan), scratch, attempt } };
139
154
  // Closing the IPC channel lets the single-request worker exit normally;
140
- // the exit handler above confirms termination before exposing its plan.
155
+ // the exit/disconnect handlers confirm termination and IPC drainage.
141
156
  if (child.connected) { try { child.disconnect(); } catch {} }
142
157
  } catch (error) { stop(error); }
143
158
  });
@@ -200,6 +215,10 @@ export async function prepareProviderDeployments({
200
215
  removeSession();
201
216
  };
202
217
  const prepareOne = async (index, attempt = 0) => {
218
+ // Never start a worker once the session is closed: it would outlive
219
+ // cleanup, and anything it writes (e.g. the shared binding-index cache)
220
+ // would land after its owner removed it.
221
+ if (closed) throw new Error('Provider preparation session is closed');
203
222
  const raw = await prepareInChild({ job: jobs[index], attempt, sessionRoot, poolDescriptor, workerPath, workerEnv, activeChildren, timeoutMs });
204
223
  const plan = transaction.adopt(raw.detached, {
205
224
  scratch: raw.scratch,
@@ -212,6 +231,7 @@ export async function prepareProviderDeployments({
212
231
  try {
213
232
  await Promise.all(Array.from({ length: concurrency }, async () => {
214
233
  for (;;) {
234
+ if (closed) return;
215
235
  const index = next++;
216
236
  if (index >= jobs.length) return;
217
237
  prepared[index] = await prepareOne(index);