@aiwg/cli 2026.10.3 → 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 (279) hide show
  1. package/README.md +2 -2
  2. package/agentic/code/providers/model-capabilities.v1.json +96 -4
  3. package/bin/aiwg.mjs +50 -27
  4. package/dist/src/agents/grounding/knowledge-base.js +54 -6
  5. package/dist/src/artifacts/browser-export.js +6 -0
  6. package/dist/src/artifacts/checksum-manifest.js +1 -0
  7. package/dist/src/artifacts/citation-parser.js +173 -92
  8. package/dist/src/artifacts/citation-table-schema.js +59 -0
  9. package/dist/src/artifacts/cli.js +57 -18
  10. package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
  11. package/dist/src/artifacts/corpus-tools/vision-extract.js +2 -0
  12. package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
  13. package/dist/src/artifacts/corpus-views/renderers.js +3 -3
  14. package/dist/src/artifacts/discovery-eval.js +6 -4
  15. package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
  16. package/dist/src/artifacts/fortemi-core-sync.js +166 -40
  17. package/dist/src/artifacts/framework-capabilities.js +171 -0
  18. package/dist/src/artifacts/framework-index-paths.js +73 -0
  19. package/dist/src/artifacts/framework-source-digest.js +75 -0
  20. package/dist/src/artifacts/index-builder.js +285 -131
  21. package/dist/src/artifacts/index-files.js +132 -18
  22. package/dist/src/artifacts/index-preparation.js +65 -0
  23. package/dist/src/artifacts/index-refresh.js +576 -0
  24. package/dist/src/artifacts/index-worker.mjs +9 -0
  25. package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
  26. package/dist/src/artifacts/prebuilt-deployment.js +46 -0
  27. package/dist/src/artifacts/prebuilt-relations.js +80 -0
  28. package/dist/src/artifacts/query-engine.js +410 -88
  29. package/dist/src/artifacts/relations-builder.js +168 -0
  30. package/dist/src/artifacts/relations.js +148 -0
  31. package/dist/src/artifacts/stats.js +5 -2
  32. package/dist/src/artifacts/types.js +30 -10
  33. package/dist/src/artifacts/watcher.js +1 -1
  34. package/dist/src/auth/credential-store.js +2 -1
  35. package/dist/src/catalog/cli.d.mts +5 -0
  36. package/dist/src/channel/manager.d.mts +20 -0
  37. package/dist/src/channel/manager.mjs +19 -2
  38. package/dist/src/cli/command-log.js +2 -3
  39. package/dist/src/cli/handlers/artifacts.js +3 -0
  40. package/dist/src/cli/handlers/auth.js +3 -0
  41. package/dist/src/cli/handlers/decision.js +19 -12
  42. package/dist/src/cli/handlers/diagnose.js +4 -3
  43. package/dist/src/cli/handlers/effect.js +4 -2
  44. package/dist/src/cli/handlers/evidence.js +3 -0
  45. package/dist/src/cli/handlers/help.js +1 -0
  46. package/dist/src/cli/handlers/index.js +3 -1
  47. package/dist/src/cli/handlers/init.js +4 -1
  48. package/dist/src/cli/handlers/lint.js +5 -0
  49. package/dist/src/cli/handlers/models.js +104 -8
  50. package/dist/src/cli/handlers/ralph-launcher.js +2 -0
  51. package/dist/src/cli/handlers/refresh.js +12 -0
  52. package/dist/src/cli/handlers/resource-versions.js +3 -0
  53. package/dist/src/cli/handlers/rules.js +195 -0
  54. package/dist/src/cli/handlers/run.js +4 -0
  55. package/dist/src/cli/handlers/runtime-info.js +1 -2
  56. package/dist/src/cli/handlers/script-runner.js +3 -2
  57. package/dist/src/cli/handlers/session.js +19 -9
  58. package/dist/src/cli/handlers/sessions.js +98 -37
  59. package/dist/src/cli/handlers/setup-manifest.js +39 -44
  60. package/dist/src/cli/handlers/setup.js +41 -0
  61. package/dist/src/cli/handlers/steward.js +11 -0
  62. package/dist/src/cli/handlers/subcommands.js +57 -2
  63. package/dist/src/cli/handlers/uhp.js +3 -0
  64. package/dist/src/cli/handlers/use.js +294 -55
  65. package/dist/src/cli/handlers/utilities.js +26 -10
  66. package/dist/src/cli/handlers/version.js +8 -0
  67. package/dist/src/cli/router.js +15 -1
  68. package/dist/src/cli/services/deployment-verification.js +19 -9
  69. package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
  70. package/dist/src/cli/skill-usage.js +2 -3
  71. package/dist/src/config/aiwg-config.js +87 -37
  72. package/dist/src/config/cli.js +111 -5
  73. package/dist/src/config/decision-config.js +106 -0
  74. package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
  75. package/dist/src/config/gitignore.js +50 -0
  76. package/dist/src/config/index-graph-overrides.js +36 -0
  77. package/dist/src/config/project-artifacts-health.d.mts +37 -0
  78. package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
  79. package/dist/src/config/user-config-dir.d.mts +9 -0
  80. package/dist/src/config/user-config.js +2 -1
  81. package/dist/src/config/user-registry.js +23 -15
  82. package/dist/src/config/user-state.js +7 -0
  83. package/dist/src/decision/ask.js +203 -43
  84. package/dist/src/decision/context-live-qualification.js +2 -2
  85. package/dist/src/decision/driver.js +13 -8
  86. package/dist/src/decision/ensemble/aggregate.js +23 -10
  87. package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
  88. package/dist/src/decision/entry.js +2 -15
  89. package/dist/src/decision/graph-live-qualification.js +1 -1
  90. package/dist/src/decision/graph-run.js +9 -0
  91. package/dist/src/decision/heldout/collector.js +5 -13
  92. package/dist/src/decision/heldout/contract.js +30 -7
  93. package/dist/src/decision/jev-credentials.js +15 -1
  94. package/dist/src/decision/ledger.js +131 -28
  95. package/dist/src/decision/offload-activation.js +137 -0
  96. package/dist/src/decision/offload.js +550 -0
  97. package/dist/src/decision/qualification/load.js +4 -6
  98. package/dist/src/decision/savings.js +28 -0
  99. package/dist/src/effects/types.js +5 -1
  100. package/dist/src/effects/verifiers/git.js +2 -1
  101. package/dist/src/effects/verifiers/tracker.js +26 -14
  102. package/dist/src/extensions/commands/definitions.js +19 -0
  103. package/dist/src/extensions/project-local-remove.js +36 -1
  104. package/dist/src/gates/providers/loader.js +61 -17
  105. package/dist/src/installation/manager-command.d.mts +18 -0
  106. package/dist/src/installation/manager-command.mjs +14 -2
  107. package/dist/src/installation/manager.d.mts +49 -0
  108. package/dist/src/installation/manager.mjs +78 -3
  109. package/dist/src/issues/cli.js +4 -4
  110. package/dist/src/issues/local.js +24 -5
  111. package/dist/src/jobs/runner.js +1 -1
  112. package/dist/src/lint/cli.js +27 -1
  113. package/dist/src/lint/loader.js +2 -1
  114. package/dist/src/lint/reporters.js +25 -1
  115. package/dist/src/lint/rule-activation.js +43 -0
  116. package/dist/src/lint/runner.js +137 -62
  117. package/dist/src/mcp/adapters/codex-runtime.js +7 -1
  118. package/dist/src/mcp/claude-install.d.mts +4 -0
  119. package/dist/src/mcp/claude-install.mjs +41 -0
  120. package/dist/src/mcp/cli.d.mts +1 -0
  121. package/dist/src/mcp/cli.mjs +36 -11
  122. package/dist/src/mcp/config-file.d.mts +28 -0
  123. package/dist/src/mcp/config-layers.d.mts +36 -0
  124. package/dist/src/mcp/credentials.d.mts +51 -0
  125. package/dist/src/mcp/grok-build-config.d.mts +6 -0
  126. package/dist/src/mcp/grok-build-config.mjs +1 -1
  127. package/dist/src/mcp/helpers.mjs +3 -2
  128. package/dist/src/mcp/muse-native-config.d.mts +13 -0
  129. package/dist/src/mcp/muse-native-config.mjs +1 -0
  130. package/dist/src/mcp/omp-config.d.mts +4 -0
  131. package/dist/src/mcp/registry.js +3 -93
  132. package/dist/src/mcp/registry.mjs +3 -87
  133. package/dist/src/mcp/server-config.d.mts +3 -0
  134. package/dist/src/mcp/server-config.mjs +89 -0
  135. package/dist/src/mcp/server.mjs +37 -375
  136. package/dist/src/mcp/test-simple.mjs +2 -1
  137. package/dist/src/mcp/toml-editor.d.mts +4 -0
  138. package/dist/src/mcp/toml-string.d.mts +1 -0
  139. package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
  140. package/dist/src/mcp/tool-filters.d.mts +46 -0
  141. package/dist/src/mcp/tools/decision.mjs +12 -11
  142. package/dist/src/mcp/tools/discovery.mjs +62 -55
  143. package/dist/src/mcp/tools/orchestration.mjs +12 -2
  144. package/dist/src/mcp/tools/worker-invoke.mjs +1340 -23
  145. package/dist/src/mcp/tools/worker-shell-control.mjs +52 -21
  146. package/dist/src/mcp/tools/worker-stdin-runtime.mjs +3 -3
  147. package/dist/src/mission-protocol/codecs.js +8 -0
  148. package/dist/src/models/config-loader.js +7 -2
  149. package/dist/src/models/model-capabilities.v1.json +96 -4
  150. package/dist/src/models/model-discovery.js +76 -11
  151. package/dist/src/models/provider-policy.js +101 -7
  152. package/dist/src/models/qualification-digest.d.mts +2 -0
  153. package/dist/src/models/resolver.js +12 -10
  154. package/dist/src/models/worker-direct-readiness.js +65 -44
  155. package/dist/src/models/worker-dispatch-offer.js +3 -3
  156. package/dist/src/models/worker-health-readiness.js +16 -3
  157. package/dist/src/models/worker-installation.d.mts +39 -0
  158. package/dist/src/models/worker-installation.mjs +135 -28
  159. package/dist/src/process/bounded-child-process.d.mts +84 -0
  160. package/dist/src/process/bounded-child-process.mjs +43 -0
  161. package/dist/src/process/cli-command.d.mts +16 -0
  162. package/dist/src/process/signal-child.d.mts +6 -0
  163. package/dist/src/process/signal-child.mjs +7 -0
  164. package/dist/src/providers/deployed-skill-roots.js +20 -0
  165. package/dist/src/providers/grok-build-acp.js +3 -2
  166. package/dist/src/providers/grok-build-headless.js +12 -4
  167. package/dist/src/providers/grok-build-inspect.js +1 -0
  168. package/dist/src/providers/omp-agent.d.mts +8 -0
  169. package/dist/src/providers/omp-diagnostics.d.mts +1 -0
  170. package/dist/src/providers/omp-paths.d.mts +13 -0
  171. package/dist/src/providers/skill-ownership.d.mts +9 -0
  172. package/dist/src/providers/skill-ownership.mjs +88 -0
  173. package/dist/src/rules/activation.d.mts +21 -0
  174. package/dist/src/rules/activation.mjs +62 -0
  175. package/dist/src/rules/inline-budget.d.mts +26 -0
  176. package/dist/src/rules/inline-budget.mjs +66 -0
  177. package/dist/src/rules/inventory.js +129 -0
  178. package/dist/src/rules/pin-state.js +73 -0
  179. package/dist/src/rules/pins.d.mts +14 -0
  180. package/dist/src/rules/pins.mjs +112 -0
  181. package/dist/src/rules/rule-frontmatter.schema.json +197 -0
  182. package/dist/src/serve/mission-conductor.js +38 -12
  183. package/dist/src/serve/worker-invocation.js +30 -10
  184. package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
  185. package/dist/src/sessions/adapter-registry.js +23 -19
  186. package/dist/src/sessions/adapters/claude.js +39 -54
  187. package/dist/src/sessions/adapters/codex.js +82 -67
  188. package/dist/src/sessions/adapters/copilot.js +4 -4
  189. package/dist/src/sessions/adapters/cursor.js +40 -57
  190. package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
  191. package/dist/src/sessions/adapters/factory.js +31 -27
  192. package/dist/src/sessions/adapters/generic.js +10 -10
  193. package/dist/src/sessions/adapters/grok-build.js +11 -11
  194. package/dist/src/sessions/adapters/grokbot.js +24 -13
  195. package/dist/src/sessions/adapters/hermes.js +27 -29
  196. package/dist/src/sessions/adapters/muse-workspace-scan.js +31 -11
  197. package/dist/src/sessions/adapters/muse.js +150 -93
  198. package/dist/src/sessions/adapters/omp.js +28 -14
  199. package/dist/src/sessions/adapters/openclaw.js +89 -79
  200. package/dist/src/sessions/adapters/opencode.js +27 -24
  201. package/dist/src/sessions/adapters/openhuman.js +18 -60
  202. package/dist/src/sessions/adapters/pi.js +29 -14
  203. package/dist/src/sessions/adapters/warp.js +3 -3
  204. package/dist/src/sessions/adapters/windsurf.js +19 -48
  205. package/dist/src/sessions/batch-contracts.js +16 -8
  206. package/dist/src/sessions/batch-import.js +51 -11
  207. package/dist/src/sessions/contracts.js +40 -2
  208. package/dist/src/sessions/coverage-preflight.js +1 -1
  209. package/dist/src/sessions/export-plan.js +4 -3
  210. package/dist/src/sessions/import-exclusions.js +72 -0
  211. package/dist/src/sessions/import-lease.js +34 -18
  212. package/dist/src/sessions/import-limits.js +37 -0
  213. package/dist/src/sessions/importer.js +60 -38
  214. package/dist/src/sessions/lifecycle.js +45 -0
  215. package/dist/src/sessions/policy.js +133 -25
  216. package/dist/src/sessions/readers.js +106 -53
  217. package/dist/src/sessions/refresh.js +106 -0
  218. package/dist/src/sessions/repository.js +147 -52
  219. package/dist/src/sessions/workspace-discovery.js +221 -56
  220. package/dist/src/sessions/workspace-matching.js +107 -0
  221. package/dist/src/skills/importer.js +1 -0
  222. package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
  223. package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
  224. package/dist/src/smiths/context-pipeline/finalization.js +6 -5
  225. package/dist/src/smiths/context-pipeline/generator.js +21 -4
  226. package/dist/src/smiths/context-pipeline/parallelism-section.js +7 -15
  227. package/dist/src/smiths/mcpsmith/generator.js +1 -1
  228. package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
  229. package/dist/src/smiths/toolsmith/runtime-discovery.mjs +76 -18
  230. package/dist/src/storage/backends/fs.js +18 -76
  231. package/dist/src/storage/backends/obsidian.js +1 -0
  232. package/dist/src/tracker/forge-http.js +2 -1
  233. package/dist/src/update/checker.d.mts +2 -0
  234. package/dist/src/update/service.d.mts +22 -0
  235. package/dist/src/utils/contained-filesystem.d.mts +37 -0
  236. package/dist/src/utils/contained-filesystem.mjs +683 -0
  237. package/dist/src/utils/temporary-directory.js +36 -0
  238. package/dist/src/writing/example-generator.js +1 -1
  239. package/package.json +15 -2
  240. package/schemas/models/model-catalog.v1.schema.json +1 -1
  241. package/schemas/models/provider-model-capabilities.v1.schema.json +6 -0
  242. package/tools/_resolve-impl.mjs +13 -15
  243. package/tools/agents/deploy-agents.mjs +49 -21
  244. package/tools/agents/providers/base.mjs +104 -134
  245. package/tools/agents/providers/claude.mjs +8 -24
  246. package/tools/agents/providers/codex.mjs +18 -11
  247. package/tools/agents/providers/cursor.mjs +19 -18
  248. package/tools/agents/providers/grok-build.mjs +3 -1
  249. package/tools/agents/providers/hermes.mjs +57 -47
  250. package/tools/agents/providers/openclaw.mjs +9 -4
  251. package/tools/agents/providers/pi.mjs +5 -0
  252. package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
  253. package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
  254. package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
  255. package/tools/agents/providers/rule-delivery.mjs +1270 -0
  256. package/tools/agents/providers/warp.mjs +20 -26
  257. package/tools/cli/decision-offload-report.mjs +40 -0
  258. package/tools/cli/workspace-status.mjs +862 -0
  259. package/tools/plugin/package-plugins.mjs +186 -8
  260. package/tools/plugin/plugin-links.mjs +114 -0
  261. package/tools/providers/antigravity-transport.mjs +3 -1
  262. package/tools/providers/deepseek-harness-transport.mjs +6 -4
  263. package/tools/providers/omp-transport.mjs +4 -2
  264. package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
  265. package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
  266. package/tools/ralph-external/lib/omp-adapter.mjs +1 -1
  267. package/tools/ralph-external/lib/pi-adapter.mjs +0 -4
  268. package/tools/ralph-external/lib/provider-adapter.mjs +59 -1
  269. package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
  270. package/tools/ralph-external/lib/session-environment.mjs +28 -0
  271. package/tools/ralph-external/lib/systemd-client.mjs +49 -0
  272. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  273. package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
  274. package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
  275. package/tools/ralph-external/process-monitor.mjs +1017 -0
  276. package/tools/ralph-external/session-launcher.mjs +5057 -0
  277. package/tools/scripts/resource-preflight.mjs +541 -0
  278. package/tools/skills/deploy-skills-codex.mjs +2 -1
  279. package/vscode-extension/schemas/aiwg.config.v1.json +1194 -231
@@ -1,3 +1,4 @@
1
+ import { trackTemporaryDirectory } from '../../utils/temporary-directory.js';
1
2
  /**
2
3
  * Use Command Handler
3
4
  *
@@ -13,9 +14,12 @@ import fs from 'fs/promises';
13
14
  import path from 'path';
14
15
  import os from 'os';
15
16
  import { pathToFileURL } from 'node:url';
17
+ import { createHash, randomUUID } from 'node:crypto';
18
+ import { canDeploySkill, sameSkillOwner, extractFrameworkSlug } from '../../providers/skill-ownership.mjs';
16
19
  import { resolveOmpPaths } from '../../providers/omp-paths.mjs';
17
20
  import YAML from 'yaml';
18
21
  import { createScriptRunner } from './script-runner.js';
22
+ import { finalizePreparedProvider, prepareProviderDeployments } from '../services/provider-prepare-coordinator.js';
19
23
  import { getFrameworkRoot, getVersionInfo } from '../../channel/manager.mjs';
20
24
  import { getRegistry } from '../../extensions/registry.js';
21
25
  import { registerDeployedExtensions } from '../../extensions/deployment-registration.js';
@@ -39,6 +43,7 @@ import { detectScope, mirrorToUserScope, rejectOpenClawProjectScope, USER_SCOPE_
39
43
  import { maybeWarnProjectIsolation } from '../project-isolation/index.js';
40
44
  import { formatWorkspaceSignalPlan, includedBundleIds, resolveWorkspaceSignalPlan, writeWorkspaceSignalPlan, } from '../workspace-signals.js';
41
45
  import { getProviderArtifactPathStrings, getProviderDefinition, getProviderKernelSkillPath, normalizeProviderDefinitionId, } from '../../providers/provider-definitions.js';
46
+ import { deployedSkillRoots } from '../../providers/deployed-skill-roots.js';
42
47
  // Module-level guard so the iteration loops further down (which re-enter
43
48
  // execute() per framework/provider) don't re-emit the warning each pass.
44
49
  // Reset is not needed: a single CLI process is one user invocation.
@@ -47,12 +52,14 @@ let projectIsolationChecked = false;
47
52
  // collecting child-process output. The CLI is single-command-per-process;
48
53
  // recursive provider expansion shares this guard intentionally.
49
54
  let machineReadableUseDepth = 0;
55
+ // Providers whose complete project projection is covered by the transferable
56
+ // rule-delivery transaction. Other built-ins retain their serial deploy path.
57
+ const PREPARABLE_BUILTIN_PROVIDERS = new Set(['claude', 'codex', 'cursor', 'hermes', 'pi', 'warp']);
50
58
  // Context-pipeline: emits WORKSPACE.md + AIWG.md + provider adapters last.
51
59
  // for non-Claude providers per ADR-1 (.aiwg/architecture/adr-agents-md-aggregation.md).
52
60
  // Distinct from agentsmith (which creates subagent personas).
53
61
  import { generate as generateContextFiles, discoverDeployedArtifacts, } from '../../smiths/context-pipeline/index.js';
54
62
  import { verifyModelWrapperDeployment } from '../../models/wrapper-deployment.js';
55
- import { loadGraphIndexFile } from '../../artifacts/index-reader.js';
56
63
  import { aggregateUseDeploymentResult, buildDryRunUseResult, renderUseDeploymentResult, verifyProviderDeployment, } from '../services/deployment-verification.js';
57
64
  import { finalizeProviderTransformationReceipt, providerReceiptHasLocalSources, sourceVerificationsFromSignedWebRelease, } from '../../providers/transformation-receipt-integration.js';
58
65
  import { loadResourceTrustRootFile, resolveWebRelease, } from '../../resources/web-release.js';
@@ -246,7 +253,7 @@ const FRAMEWORK_DIR_MAP = {
246
253
  all: 'sdlc-complete',
247
254
  };
248
255
  /** Resolve actual framework directory name for a given user-facing name. */
249
- function resolveFrameworkDir(framework) {
256
+ export function resolveFrameworkDir(framework) {
250
257
  return FRAMEWORK_DIR_MAP[framework];
251
258
  }
252
259
  /**
@@ -397,6 +404,18 @@ export function addonPath(frameworkRoot, name) {
397
404
  const folderName = resolveAddonFolderName(name);
398
405
  return path.join(frameworkRoot, 'agentic/code/addons', folderName);
399
406
  }
407
+ /**
408
+ * Whether the provider's root deployment already collects every eligible
409
+ * addon for this mode. The caller still registers addon CLI contributions;
410
+ * this only suppresses redundant deploy-agents subprocesses.
411
+ */
412
+ export function mainDeploymentIncludesAddons(provider, selectedMode, providerDeployArgs) {
413
+ return (((provider === 'claude' || provider === 'pi')
414
+ && ['general', 'sdlc', 'both', 'all'].includes(selectedMode))
415
+ || (provider === 'codex' && selectedMode === 'all'))
416
+ && !providerDeployArgs.some(arg => arg === '--source' || arg.startsWith('--source='))
417
+ && providerDeployArgs.filter(arg => arg === '--mode').length === 1;
418
+ }
400
419
  /**
401
420
  * Resolve a selected addon's required addon dependencies in deterministic
402
421
  * dependency-first order. Optional dependencies remain descriptive and are
@@ -1047,17 +1066,11 @@ async function listBundleSkillNameCandidates(bundlePath) {
1047
1066
  return [];
1048
1067
  }
1049
1068
  }
1050
- async function countDeployedBundleSkills(bundlePath, target, provider, paths) {
1069
+ async function countDeployedBundleSkills(bundlePath, target, provider) {
1051
1070
  const skillCandidates = await listBundleSkillNameCandidates(bundlePath);
1052
1071
  if (skillCandidates.length === 0)
1053
1072
  return 0;
1054
- const candidateDirs = [
1055
- paths.skills,
1056
- getProviderKernelSkillsPath(provider),
1057
- ]
1058
- .filter(Boolean)
1059
- .map(dir => resolveDeployPath(target, dir));
1060
- const uniqueCandidateDirs = [...new Set(candidateDirs)];
1073
+ const uniqueCandidateDirs = deployedSkillRoots(target, provider);
1061
1074
  let count = 0;
1062
1075
  for (const names of skillCandidates) {
1063
1076
  let found = false;
@@ -1080,16 +1093,35 @@ async function countBundleDeployedArtifacts(bundlePath, target, provider) {
1080
1093
  return {
1081
1094
  agents: await countDeployedBundleFiles(bundlePath, 'agents', target, paths.agents, ['.md', '.toml']),
1082
1095
  commands: await countDeployedBundleFiles(bundlePath, 'commands', target, paths.commands, ['.md']),
1083
- skills: await countDeployedBundleSkills(bundlePath, target, provider, paths),
1096
+ skills: await countDeployedBundleSkills(bundlePath, target, provider),
1084
1097
  rules: await countDeployedBundleFiles(bundlePath, 'rules', target, paths.rules, ['.md', '.mdc']),
1085
1098
  };
1086
1099
  }
1087
1100
  const SKILL_SUPPORT_REFERENCE = /(?:^|[\s`('"\[])((?:templates|references|scripts|assets)\/[A-Za-z0-9._@/+\-]+)(?=$|[\s`)'"\],:;])/gm;
1088
1101
  /** Copy one support file, preserving its executable bit. */
1089
- async function copySkillSupportFile(source, destination) {
1102
+ async function copySkillSupportFile(source, destination, skillDir) {
1090
1103
  await fs.mkdir(path.dirname(destination), { recursive: true });
1091
1104
  await fs.copyFile(source, destination);
1092
1105
  await fs.chmod(destination, (await fs.stat(source)).mode & 0o777);
1106
+ // Extend the shared copier's receipt for bundle-root assets too. Adapters
1107
+ // without that receipt keep their own ownership and cleanup contract.
1108
+ if (!skillDir)
1109
+ return;
1110
+ const manifestPath = path.join(skillDir, '.aiwg-manifest.json');
1111
+ let manifest;
1112
+ try {
1113
+ manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
1114
+ }
1115
+ catch {
1116
+ return;
1117
+ }
1118
+ if (!manifest.skillSource || !manifest.managed?.['SKILL.md'])
1119
+ return;
1120
+ manifest.managed[path.relative(skillDir, destination)] = {
1121
+ ...manifest.managed['SKILL.md'],
1122
+ hash: `sha256:${createHash('sha256').update(await fs.readFile(destination)).digest('hex')}`,
1123
+ };
1124
+ await fs.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
1093
1125
  }
1094
1126
  /**
1095
1127
  * Materialize a directory-valued support-asset reference (#2503).
@@ -1099,7 +1131,7 @@ async function copySkillSupportFile(source, destination) {
1099
1131
  * file modes are preserved so script packs stay executable. Empty directories
1100
1132
  * are still created — a reference to an empty pack is odd but not an error.
1101
1133
  */
1102
- async function copySkillSupportTree(source, destination, sourceSkillMd, reference, deployFile) {
1134
+ async function copySkillSupportTree(source, destination, sourceSkillMd, reference, deployFile, skillDir) {
1103
1135
  await fs.mkdir(destination, { recursive: true });
1104
1136
  const label = reference.replace(/\/+$/, '');
1105
1137
  const entries = await fs.readdir(source, { withFileTypes: true });
@@ -1110,7 +1142,7 @@ async function copySkillSupportTree(source, destination, sourceSkillMd, referenc
1110
1142
  throw new Error(`unsafe skill support asset '${label}/${entry.name}' referenced by ${sourceSkillMd}: symbolic links are not deployed`);
1111
1143
  }
1112
1144
  if (entry.isDirectory()) {
1113
- await copySkillSupportTree(from, to, sourceSkillMd, `${label}/${entry.name}`, deployFile);
1145
+ await copySkillSupportTree(from, to, sourceSkillMd, `${label}/${entry.name}`, deployFile, skillDir);
1114
1146
  continue;
1115
1147
  }
1116
1148
  if (!entry.isFile())
@@ -1119,7 +1151,7 @@ async function copySkillSupportTree(source, destination, sourceSkillMd, referenc
1119
1151
  deployFile(from, to);
1120
1152
  continue;
1121
1153
  }
1122
- await copySkillSupportFile(from, to);
1154
+ await copySkillSupportFile(from, to, skillDir);
1123
1155
  }
1124
1156
  }
1125
1157
  /**
@@ -1140,12 +1172,9 @@ async function reconcileDeployedSkillAssets(bundlePath, target, provider, option
1140
1172
  catch {
1141
1173
  return;
1142
1174
  }
1143
- const paths = getProviderPaths(provider);
1144
- const kernelSkillsPath = getProviderKernelSkillsPath(provider);
1145
1175
  const deployRoots = provider === 'omp' && options.scope === 'user'
1146
1176
  ? [path.join(resolveOmpPaths({ cwd: target }).agentDir, 'skills')]
1147
- : [...new Set([paths.skills, kernelSkillsPath]
1148
- .filter((value) => Boolean(value)).map(value => resolveDeployPath(target, value)))];
1177
+ : deployedSkillRoots(target, provider);
1149
1178
  for (const skillName of skillDirs) {
1150
1179
  const sourceSkillDir = path.join(skillsRoot, skillName);
1151
1180
  const sourceSkillMd = path.join(sourceSkillDir, 'SKILL.md');
@@ -1156,7 +1185,35 @@ async function reconcileDeployedSkillAssets(bundlePath, target, provider, option
1156
1185
  catch {
1157
1186
  continue;
1158
1187
  }
1159
- if (options.skipUndeployed && !(await Promise.all(deployRoots.map(root => fileExists(path.join(root, skillName, 'SKILL.md'))))).some(Boolean))
1188
+ // Check each deployed tier independently: a foreign mirror must not block
1189
+ // support assets for a tier already owned by this source.
1190
+ const ownedRoots = [];
1191
+ for (const root of deployRoots) {
1192
+ const skillDir = path.join(root, skillName);
1193
+ try {
1194
+ const manifestPath = path.join(skillDir, '.aiwg-manifest.json');
1195
+ const receipt = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
1196
+ if (!canDeploySkill(receipt, sourceSkillDir, options))
1197
+ continue;
1198
+ if (!sameSkillOwner(receipt, sourceSkillDir)) {
1199
+ receipt.skillSource = path.resolve(sourceSkillDir);
1200
+ const slug = extractFrameworkSlug(sourceSkillMd);
1201
+ for (const record of Object.values(receipt.managed ?? {})) {
1202
+ if (slug)
1203
+ record.frameworkSlug = slug;
1204
+ else
1205
+ delete record.frameworkSlug;
1206
+ }
1207
+ await fs.writeFile(manifestPath, `${JSON.stringify(receipt, null, 2)}\n`);
1208
+ }
1209
+ }
1210
+ catch { /* adapters without shared ownership receipts keep their own contract */ }
1211
+ if (await fileExists(path.join(skillDir, 'SKILL.md')))
1212
+ ownedRoots.push(root);
1213
+ }
1214
+ if (ownedRoots.length === 0)
1215
+ continue;
1216
+ if (options.skipUndeployed && !(await Promise.all(ownedRoots.map(root => fileExists(path.join(root, skillName, 'SKILL.md'))))).some(Boolean))
1160
1217
  continue;
1161
1218
  const frontmatter = content.match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1] ?? '';
1162
1219
  const declaredEntrypoint = frontmatter
@@ -1199,7 +1256,7 @@ async function reconcileDeployedSkillAssets(bundlePath, target, provider, option
1199
1256
  throw new Error(`skill entrypoint '${relative}' in ${sourceSkillMd} resolves to a directory; an entrypoint must be a file`);
1200
1257
  }
1201
1258
  let deployedSkillRoot;
1202
- for (const root of deployRoots) {
1259
+ for (const root of ownedRoots) {
1203
1260
  // The deployer may select the bulk or kernel tier; use the tier that
1204
1261
  // actually contains this skill's transformed SKILL.md.
1205
1262
  if (await fileExists(path.join(root, skillName, 'SKILL.md'))) {
@@ -1217,14 +1274,14 @@ async function reconcileDeployedSkillAssets(bundlePath, target, provider, option
1217
1274
  })()
1218
1275
  : null;
1219
1276
  if (sourceIsDirectory) {
1220
- await copySkillSupportTree(source, destination, sourceSkillMd, relative, deployFile);
1277
+ await copySkillSupportTree(source, destination, sourceSkillMd, relative, deployFile, path.join(deployedSkillRoot, skillName));
1221
1278
  continue;
1222
1279
  }
1223
1280
  if (deployFile) {
1224
1281
  deployFile(source, destination);
1225
1282
  continue;
1226
1283
  }
1227
- await copySkillSupportFile(source, destination);
1284
+ await copySkillSupportFile(source, destination, path.join(deployedSkillRoot, skillName));
1228
1285
  }
1229
1286
  }
1230
1287
  }
@@ -1297,6 +1354,8 @@ async function deployOneProjectLocalBundle(opts) {
1297
1354
  ...modelArgs,
1298
1355
  ];
1299
1356
  args.push(...collectUseScopeDeployArgs(ctx.args));
1357
+ if (ctx.args.includes('--force'))
1358
+ args.push('--force');
1300
1359
  if (dryRun)
1301
1360
  args.push('--dry-run');
1302
1361
  if (verbose)
@@ -1322,7 +1381,7 @@ async function deployOneProjectLocalBundle(opts) {
1322
1381
  exitCode = result.exitCode;
1323
1382
  if (exitCode === 0 && !dryRun) {
1324
1383
  try {
1325
- await reconcileDeployedSkillAssets(bundle.artifactPath, target, provider);
1384
+ await reconcileDeployedSkillAssets(bundle.artifactPath, target, provider, { force: ctx.args.includes('--force') });
1326
1385
  }
1327
1386
  catch (error) {
1328
1387
  ui.warn(`Project-local skill asset deployment failed for '${bundle.id}': ${error.message}`);
@@ -1973,18 +2032,30 @@ async function generateGlobalProjectContext(opts) {
1973
2032
  },
1974
2033
  });
1975
2034
  }
2035
+ /** Receipt reuse applies to complete packages; selected partial sources still need an actual build. */
2036
+ async function reconcileSelectedFrameworkSource(root) {
2037
+ const { refreshFrameworkCapabilities, resolveFrameworkCorpusRoot } = await import('../../artifacts/framework-capabilities.js');
2038
+ if (resolveFrameworkCorpusRoot(root)) {
2039
+ const { loadPrebuiltDeploymentIndex } = await import('../../artifacts/prebuilt-deployment.js');
2040
+ if (loadPrebuiltDeploymentIndex(root, { strictRoot: true }))
2041
+ return;
2042
+ await refreshFrameworkCapabilities(root, true, { force: true });
2043
+ return;
2044
+ }
2045
+ const { buildIndex } = await import('../../artifacts/index-builder.js');
2046
+ await buildIndex(root, { graph: 'framework', explicit: false });
2047
+ const { syncFortemiCoreIndex } = await import('../../artifacts/fortemi-core-sync.js');
2048
+ syncFortemiCoreIndex(root, { graph: 'framework' });
2049
+ }
1976
2050
  async function ensurePostDeployPhases(opts) {
1977
- const currentIndex = loadGraphIndexFile(opts.frameworkRoot, 'metadata.json', 'framework');
1978
- const builtAt = currentIndex ? Date.parse(currentIndex.builtAt) : Number.NaN;
1979
- const startedAt = Date.parse(opts.invocationStartedAt);
1980
- if (!Number.isFinite(builtAt) || builtAt + 2_000 < startedAt) {
1981
- try {
1982
- const { buildIndex } = await import('../../artifacts/index-builder.js');
1983
- await buildIndex(opts.frameworkRoot, { graph: 'framework', explicit: false });
1984
- }
1985
- catch {
1986
- // The shared verifier reports the index failure with stable remediation.
1987
- }
2051
+ // Validate source files once after deployment, including uncommitted edits
2052
+ // that the cheap HEAD/manifest receipt intentionally cannot detect. Earlier
2053
+ // deployment/query phases can reuse that receipt instead of rescanning.
2054
+ try {
2055
+ await reconcileSelectedFrameworkSource(opts.frameworkRoot);
2056
+ }
2057
+ catch {
2058
+ // The shared verifier reports the index failure with stable remediation.
1988
2059
  }
1989
2060
  // The Fortemi export is the default discovery backend. Rebuilding only the
1990
2061
  // source graph makes any existing export stale, so every successful use
@@ -1992,8 +2063,9 @@ async function ensurePostDeployPhases(opts) {
1992
2063
  // materializes a fresh-install cache without requiring a manual index sync.
1993
2064
  try {
1994
2065
  const { getFortemiCoreSyncStatus, syncFortemiCoreIndex, } = await import('../../artifacts/fortemi-core-sync.js');
2066
+ const { loadPrebuiltDeploymentIndex } = await import('../../artifacts/prebuilt-deployment.js');
1995
2067
  const status = getFortemiCoreSyncStatus(opts.frameworkRoot, 'framework');
1996
- if (!status.built || status.stale) {
2068
+ if (!loadPrebuiltDeploymentIndex(opts.frameworkRoot, { strictRoot: true }) && (!status.built || status.stale)) {
1997
2069
  syncFortemiCoreIndex(opts.frameworkRoot, { graph: 'framework' });
1998
2070
  }
1999
2071
  }
@@ -2189,6 +2261,55 @@ async function deployOmpUserSource(opts) {
2189
2261
  counts: { agents: entries.agents.length, commands: entries.commands.length,
2190
2262
  skills: entries.skills.length, rules: entries.rules.length }, entries });
2191
2263
  }
2264
+ /** Record native home writes without mirroring or changing user-scope removal roots. */
2265
+ async function recordNativeAddonDeploy(bundlePath, target, provider, bundle) {
2266
+ const userPaths = USER_SCOPE_PATHS[provider];
2267
+ const paths = getProviderPaths(provider);
2268
+ const entries = {
2269
+ agents: [], commands: [], skills: [], rules: [],
2270
+ };
2271
+ for (const names of await listBundleSkillNameCandidates(bundlePath)) {
2272
+ for (const root of deployedSkillRoots(target, provider)) {
2273
+ let name;
2274
+ for (const candidate of names) {
2275
+ if (await fileExists(path.join(root, candidate, 'SKILL.md'))) {
2276
+ name = candidate;
2277
+ break;
2278
+ }
2279
+ }
2280
+ if (!name)
2281
+ continue;
2282
+ try {
2283
+ const receipt = JSON.parse(await fs.readFile(path.join(root, name, '.aiwg-manifest.json'), 'utf8'));
2284
+ const sourceDir = path.join(bundlePath, 'skills', names[names.length - 1]);
2285
+ if (!sameSkillOwner(receipt, sourceDir))
2286
+ continue;
2287
+ }
2288
+ catch { /* legacy adapters may not write a shared ownership receipt */ }
2289
+ entries.skills.push(path.relative(userPaths.skills, path.join(root, name)));
2290
+ break;
2291
+ }
2292
+ }
2293
+ for (const kind of ['agents', 'commands', 'rules']) {
2294
+ if (!paths[kind] || !userPaths[kind])
2295
+ continue;
2296
+ for (const stem of await listBundleMdStems(bundlePath, kind)) {
2297
+ const filename = `${stem}.md`;
2298
+ const destination = path.join(resolveDeployPath(target, paths[kind]), filename);
2299
+ if (await fileExists(destination))
2300
+ entries[kind].push(path.relative(userPaths[kind], destination));
2301
+ }
2302
+ }
2303
+ const manifestPath = path.join(bundlePath, 'manifest.json');
2304
+ const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
2305
+ const { recordUserDeploy } = await import('../../config/user-registry.js');
2306
+ await recordUserDeploy({
2307
+ framework: bundle, provider, version: manifest.version ?? (await getVersionInfo()).version,
2308
+ source: 'bundled', manifestHash: await hashManifest(manifestPath), entries,
2309
+ counts: { agents: entries.agents.length, commands: entries.commands.length,
2310
+ skills: entries.skills.length, rules: entries.rules.length },
2311
+ });
2312
+ }
2192
2313
  async function mirrorProjectLocalBundleToUserScope(opts) {
2193
2314
  const paths = getProviderPaths(opts.provider);
2194
2315
  const resolveProjectPath = (value) => !value ? '' : path.isAbsolute(value) ? value : path.join(opts.target, value);
@@ -2269,6 +2390,7 @@ export class UseHandler {
2269
2390
  category = 'framework';
2270
2391
  aliases = [];
2271
2392
  orchestrationDepth = 0;
2393
+ preparedProviderContinuations = new Set();
2272
2394
  async help() {
2273
2395
  return { exitCode: 0, message: USE_HELP, rawOutput: true };
2274
2396
  }
@@ -2281,12 +2403,24 @@ export class UseHandler {
2281
2403
  || ctx.args.includes('--workspace-signals');
2282
2404
  if (bypassOrchestration)
2283
2405
  return this.executeCore(ctx);
2406
+ // Child deployers share one source-index snapshot for this invocation. Each
2407
+ // addon still resolves and validates its bindings through the common query
2408
+ // engine, without rebuilding the entire corpus on every additive pass.
2409
+ const previousBindingCache = process.env.AIWG_RULE_BINDING_INDEX_CACHE;
2410
+ const bindingCache = previousBindingCache || await fs.mkdtemp(path.join(os.tmpdir(), 'aiwg-use-bindings-'));
2411
+ const removeBindingCache = previousBindingCache ? () => { } : trackTemporaryDirectory(bindingCache);
2412
+ process.env.AIWG_RULE_BINDING_INDEX_CACHE = bindingCache;
2284
2413
  this.orchestrationDepth += 1;
2285
2414
  try {
2286
2415
  return await this.executeOrchestrated(ctx, requestedBundle);
2287
2416
  }
2288
2417
  finally {
2289
2418
  this.orchestrationDepth -= 1;
2419
+ if (previousBindingCache === undefined)
2420
+ delete process.env.AIWG_RULE_BINDING_INDEX_CACHE;
2421
+ else
2422
+ process.env.AIWG_RULE_BINDING_INDEX_CACHE = previousBindingCache;
2423
+ removeBindingCache();
2290
2424
  }
2291
2425
  }
2292
2426
  async executeOrchestrated(ctx, requestedBundle) {
@@ -2362,7 +2496,6 @@ export class UseHandler {
2362
2496
  projectPath: projectDir,
2363
2497
  provider,
2364
2498
  args: remainingArgs,
2365
- invocationStartedAt: startedAt,
2366
2499
  });
2367
2500
  }
2368
2501
  }
@@ -2982,6 +3115,8 @@ export class UseHandler {
2982
3115
  }
2983
3116
  const runner = createScriptRunner(frameworkRoot);
2984
3117
  const addonBaseArgs = ['--deploy-commands', '--deploy-skills', '--deploy-rules'];
3118
+ if (remainingArgs.includes('--allow-over-budget'))
3119
+ addonBaseArgs.push('--allow-over-budget');
2985
3120
  if (addonScope === 'user')
2986
3121
  addonBaseArgs.push('--scope', 'user');
2987
3122
  // An explicitly selected upstream addon must be self-contained in the
@@ -3001,6 +3136,8 @@ export class UseHandler {
3001
3136
  }
3002
3137
  if (dryRunAddon)
3003
3138
  addonBaseArgs.push('--dry-run');
3139
+ if (remainingArgs.includes('--force'))
3140
+ addonBaseArgs.push('--force');
3004
3141
  const kind = isExtension ? 'extension' : 'addon';
3005
3142
  const activationOrder = isAddon
3006
3143
  ? await resolveRequiredAddonActivationOrder(frameworkRoot, framework)
@@ -3023,7 +3160,7 @@ export class UseHandler {
3023
3160
  }
3024
3161
  if (!dryRunAddon) {
3025
3162
  try {
3026
- await reconcileDeployedSkillAssets(dependencySource, target, provider, { strictReferences: false });
3163
+ await reconcileDeployedSkillAssets(dependencySource, target, provider, { strictReferences: false, force: remainingArgs.includes('--force') });
3027
3164
  }
3028
3165
  catch (error) {
3029
3166
  return {
@@ -3065,7 +3202,7 @@ export class UseHandler {
3065
3202
  }
3066
3203
  if (!dryRunAddon) {
3067
3204
  try {
3068
- await reconcileDeployedSkillAssets(addonSource, target, provider, { strictReferences: false });
3205
+ await reconcileDeployedSkillAssets(addonSource, target, provider, { strictReferences: false, force: remainingArgs.includes('--force') });
3069
3206
  }
3070
3207
  catch (error) {
3071
3208
  return {
@@ -3118,6 +3255,14 @@ export class UseHandler {
3118
3255
  message: `Failed to register CLI commands: ${error instanceof Error ? error.message : String(error)}`,
3119
3256
  };
3120
3257
  }
3258
+ if (!dryRunAddon && (provider === 'openclaw' || (provider === 'grokbot' && addonScope === 'user'))) {
3259
+ try {
3260
+ await recordNativeAddonDeploy(addonSource, target, provider, framework);
3261
+ }
3262
+ catch (error) {
3263
+ return { exitCode: 1, message: `Addon user registry update failed: ${error instanceof Error ? error.message : String(error)}` };
3264
+ }
3265
+ }
3121
3266
  // Persist the same lifecycle record frameworks and project-local bundles
3122
3267
  // receive so status, refresh, doctor, and remove can account for this
3123
3268
  // upstream addon and every provider artifact it actually deployed.
@@ -3240,6 +3385,16 @@ export class UseHandler {
3240
3385
  const force = remainingArgs.includes('--force');
3241
3386
  const skipConflicts = remainingArgs.includes('--skip-conflicts');
3242
3387
  const explicitHarnessAgentSelectors = parseOpenHumanHarnessAgentSelector(remainingArgs);
3388
+ const preparedFlag = '--aiwg-provider-main-prepared';
3389
+ const preparedFlagIndex = remainingArgs.indexOf(preparedFlag);
3390
+ const preparedCapability = preparedFlagIndex >= 0 ? remainingArgs[preparedFlagIndex + 1] : undefined;
3391
+ let mainProviderPrepared = false;
3392
+ if (preparedFlagIndex >= 0) {
3393
+ if (!preparedCapability || !this.preparedProviderContinuations.delete(preparedCapability)) {
3394
+ return { exitCode: 1, message: 'Invalid prepared-provider continuation capability.' };
3395
+ }
3396
+ mainProviderPrepared = true;
3397
+ }
3243
3398
  // PUW-027 (#1128): --scope user|project per ADR-4. Default project.
3244
3399
  // #1156 Phase 1: --user is a shorthand for --scope user.
3245
3400
  let scope;
@@ -3264,7 +3419,7 @@ export class UseHandler {
3264
3419
  }
3265
3420
  if (scope === 'user' && !deployArgs.includes('--scope'))
3266
3421
  deployArgs.push('--scope', 'user');
3267
- const filteredArgs = deployArgs.filter(a => a !== '--no-utils' && a !== '--no-project-local' && a !== '--ci-hooks-enabled' && a !== '--force' && a !== '--skip-conflicts' && a !== '--no-harness-agents');
3422
+ const filteredArgs = removeFlagWithOptionalValue(deployArgs, preparedFlag).filter(a => a !== '--no-utils' && a !== '--no-project-local' && a !== '--ci-hooks-enabled' && a !== '--skip-conflicts' && a !== '--no-harness-agents');
3268
3423
  const deployFilteredArgs = removeFlagWithOptionalValue(filteredArgs, '--harness-agents');
3269
3424
  // Pass --quiet to suppress deploy-agents.mjs header/footer in default mode (#460)
3270
3425
  // Human dry-run remains verbose; machine-readable dry-run captures the
@@ -3289,8 +3444,70 @@ export class UseHandler {
3289
3444
  ui.warn("No .aiwg/aiwg.config found. Run 'aiwg init', then ask your AIWG agent to configure this project properly.");
3290
3445
  }
3291
3446
  }
3292
- // Multi-provider: loop over providers, deploying to each in sequence
3447
+ const targetIdx = remainingArgs.findIndex(a => a === '--target');
3448
+ const target = targetIdx >= 0 && remainingArgs[targetIdx + 1] ? remainingArgs[targetIdx + 1] : process.cwd();
3449
+ // Multi-provider: prepare built-in project-scope projections in at most two
3450
+ // subprocesses, then preserve the existing provider/addon commit order.
3451
+ // User-scope, dry-run, harness-special and project-local adapters retain the
3452
+ // established serial path because their lifecycle is not stage-only.
3293
3453
  if (providers.length > 1) {
3454
+ const preparedJobs = [];
3455
+ let canPrepareConcurrently = !dryRun && scope === 'project' && explicitHarnessAgentSelectors.length === 0;
3456
+ for (const [order, requested] of providers.entries()) {
3457
+ const local = await resolveProjectLocalProviderAdapter(projectDir, requested);
3458
+ if (local.requestedProvider) {
3459
+ canPrepareConcurrently = false;
3460
+ break;
3461
+ }
3462
+ const unsupported = unsupportedProviderMessage(requested);
3463
+ if (unsupported)
3464
+ return { exitCode: 1, message: unsupported };
3465
+ const resolved = resolveBuiltInProviderForUse(local.provider);
3466
+ if (!PREPARABLE_BUILTIN_PROVIDERS.has(resolved.provider)) {
3467
+ canPrepareConcurrently = false;
3468
+ break;
3469
+ }
3470
+ const args = withProviderOverride([...deployFilteredArgs], resolved.provider);
3471
+ if (framework === 'all' && !['pi', 'omp'].includes(resolved.provider)
3472
+ && !remainingArgs.includes('--copy-all') && !remainingArgs.includes('--copy-standard-skills'))
3473
+ args.push('--kernel-only');
3474
+ preparedJobs.push({ order, provider: resolved.provider, target: path.resolve(target), args });
3475
+ }
3476
+ if (canPrepareConcurrently && preparedJobs.length === providers.length) {
3477
+ if (!skipConflicts) {
3478
+ for (const job of preparedJobs) {
3479
+ const canDeploy = await runPreDeployCollisionCheck({
3480
+ frameworkRoot, framework, target, provider: job.provider, force, skipConflicts, verbose,
3481
+ });
3482
+ if (!canDeploy)
3483
+ return { exitCode: 1, message: 'Deployment blocked due to name collisions. See above for details.' };
3484
+ }
3485
+ }
3486
+ let session;
3487
+ try {
3488
+ session = await prepareProviderDeployments(frameworkRoot, preparedJobs);
3489
+ for (const [order, requested] of providers.entries()) {
3490
+ await session.commit(order);
3491
+ const capability = randomUUID();
3492
+ this.preparedProviderContinuations.add(capability);
3493
+ try {
3494
+ const result = await this.execute({ ...ctx, args: [framework, '--provider', requested, preparedFlag, capability, ...remainingArgs] });
3495
+ if (result.exitCode !== 0)
3496
+ return result;
3497
+ }
3498
+ finally {
3499
+ this.preparedProviderContinuations.delete(capability);
3500
+ }
3501
+ }
3502
+ return { exitCode: 0 };
3503
+ }
3504
+ catch (error) {
3505
+ return { exitCode: 1, message: `Concurrent provider preparation failed: ${error instanceof Error ? error.message : String(error)}` };
3506
+ }
3507
+ finally {
3508
+ await session?.dispose();
3509
+ }
3510
+ }
3294
3511
  for (const p of providers) {
3295
3512
  const result = await this.execute({ ...ctx, args: [framework, '--provider', p, ...remainingArgs] });
3296
3513
  if (result.exitCode !== 0)
@@ -3322,8 +3539,6 @@ export class UseHandler {
3322
3539
  && !remainingArgs.includes('--copy-standard-skills');
3323
3540
  if (bulkKernelOnly)
3324
3541
  providerDeployArgs.push('--kernel-only');
3325
- const targetIdx = remainingArgs.findIndex(a => a === '--target');
3326
- const target = targetIdx >= 0 && remainingArgs[targetIdx + 1] ? remainingArgs[targetIdx + 1] : process.cwd();
3327
3542
  if ((verbose || dryRun) && projectLocalProviderResolution.requestedProvider) {
3328
3543
  ui.dim(` project-local provider '${projectLocalProviderResolution.requestedProvider}' extends '${provider}'`);
3329
3544
  }
@@ -3412,7 +3627,19 @@ export class UseHandler {
3412
3627
  ui.blank();
3413
3628
  }
3414
3629
  const runner = createScriptRunner(ctx.frameworkRoot);
3415
- const mainResult = await runner.run('tools/agents/deploy-agents.mjs', providerDeployArgs, captureOpts);
3630
+ let mainResult;
3631
+ if (mainProviderPrepared) {
3632
+ try {
3633
+ await finalizePreparedProvider(frameworkRoot, providerDeployArgs);
3634
+ mainResult = { exitCode: 0 };
3635
+ }
3636
+ catch (error) {
3637
+ mainResult = { exitCode: 1, message: `Prepared provider finalization failed: ${error instanceof Error ? error.message : String(error)}` };
3638
+ }
3639
+ }
3640
+ else {
3641
+ mainResult = await runner.run('tools/agents/deploy-agents.mjs', providerDeployArgs, captureOpts);
3642
+ }
3416
3643
  if (mainResult.exitCode !== 0) {
3417
3644
  return mainResult;
3418
3645
  }
@@ -3441,6 +3668,8 @@ export class UseHandler {
3441
3668
  }
3442
3669
  // Build common args for addon deployments (inherit provider and target)
3443
3670
  const addonBaseArgs = ['--deploy-commands', '--deploy-skills', '--deploy-rules'];
3671
+ if (remainingArgs.includes('--allow-over-budget'))
3672
+ addonBaseArgs.push('--allow-over-budget');
3444
3673
  if (scope === 'user')
3445
3674
  addonBaseArgs.push('--scope', 'user');
3446
3675
  if (bulkKernelOnly)
@@ -3462,6 +3691,12 @@ export class UseHandler {
3462
3691
  // Deploy all addons (excluding disallow list) unless --no-utils
3463
3692
  if (!skipUtils) {
3464
3693
  const allAddons = await getAllAddons(frameworkRoot);
3694
+ // These root collectors already deploy every eligible addon. Re-staging
3695
+ // the entire deployment per addon duplicates that work. Codex's skills
3696
+ // helper includes addons only in all mode; other modes retain their pass.
3697
+ // CLI contribution registration below still runs for every addon.
3698
+ const selectedMode = MODE_MAP[framework];
3699
+ const mainIncludesAddons = mainDeploymentIncludesAddons(provider, selectedMode, providerDeployArgs);
3465
3700
  for (const addon of allAddons) {
3466
3701
  if (verbose) {
3467
3702
  console.log('');
@@ -3471,9 +3706,10 @@ export class UseHandler {
3471
3706
  const addonArgs = quiet
3472
3707
  ? ['--quiet', '--source', source, ...addonBaseArgs]
3473
3708
  : ['--source', source, ...addonBaseArgs];
3474
- const result = await runner.run('tools/agents/deploy-agents.mjs', addonArgs, captureOpts);
3475
- if (result.exitCode !== 0) {
3476
- return result;
3709
+ if (!mainIncludesAddons) {
3710
+ const result = await runner.run('tools/agents/deploy-agents.mjs', addonArgs, captureOpts);
3711
+ if (result.exitCode !== 0)
3712
+ return result;
3477
3713
  }
3478
3714
  try {
3479
3715
  await registerSourceCliCommands({
@@ -3690,7 +3926,14 @@ export class UseHandler {
3690
3926
  // progress through; otherwise we show a single-line spinner-
3691
3927
  // style message and capture the noisy stat lines.
3692
3928
  ui.blank();
3693
- ui.info('Building capability index…');
3929
+ const { loadPrebuiltDeploymentIndex } = await import('../../artifacts/prebuilt-deployment.js');
3930
+ const prebuilt = loadPrebuiltDeploymentIndex(aiwgRootForIndex, { strictRoot: true });
3931
+ ui.info(prebuilt ? 'Validating packaged capability index…' : 'Building capability index…');
3932
+ if (!prebuilt && await fs.access(path.join(aiwgRootForIndex, 'prebuilt', 'framework-relations', 'manifest.json')).then(() => true).catch(() => false)) {
3933
+ const { selectPrebuiltRelations } = await import('../../artifacts/relations.js');
3934
+ const reason = selectPrebuiltRelations(aiwgRootForIndex).reason ?? 'packaged search index is missing, stale, or does not match the source';
3935
+ ui.dim(` Packaged index unavailable: ${reason}.`);
3936
+ }
3694
3937
  ui.dim(' Indexing operational assets for agent-side lookup.');
3695
3938
  const indexStart = Date.now();
3696
3939
  // Capture buildIndex's own console.log noise unless verbose
@@ -3698,13 +3941,9 @@ export class UseHandler {
3698
3941
  if (!verbose)
3699
3942
  console.log = () => { };
3700
3943
  try {
3701
- const { buildIndex } = await import('../../artifacts/index-builder.js');
3702
- // Build against AIWG_ROOT so stored paths resolve from any
3703
- // project (#1217). The output index location is XDG-shared
3704
- // regardless of build cwd.
3705
- await buildIndex(aiwgRootForIndex, { graph: 'framework', explicit: false });
3706
- const { syncFortemiCoreIndex } = await import('../../artifacts/fortemi-core-sync.js');
3707
- syncFortemiCoreIndex(aiwgRootForIndex, { graph: 'framework' });
3944
+ // Validate uncommitted sources once and publish the receipt so
3945
+ // verification/discovery do not immediately scan the corpus again.
3946
+ await reconcileSelectedFrameworkSource(aiwgRootForIndex);
3708
3947
  console.log = origLog;
3709
3948
  const indexElapsedSec = ((Date.now() - indexStart) / 1000).toFixed(1);
3710
3949
  ui.success(`Capability index ready (${indexElapsedSec}s).`);