@aiwg/cli 2026.10.5 → 2026.10.7

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 (263) 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 +7 -3
  6. package/dist/src/a2a/agent-card.js +11 -0
  7. package/dist/src/api/index.d.ts +1 -0
  8. package/dist/src/api/index.js +1 -0
  9. package/dist/src/artifacts/browser-export.js +1 -0
  10. package/dist/src/artifacts/citation-parser.js +8 -1
  11. package/dist/src/artifacts/cli.js +57 -6
  12. package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
  13. package/dist/src/artifacts/fortemi-core-sync.js +26 -8
  14. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/contract.json +103 -0
  15. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-config.schema.json +212 -0
  16. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-set.schema.json +240 -0
  17. package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-manifest.schema.json +451 -0
  18. package/dist/src/artifacts/fortemi-shard-export.js +284 -0
  19. package/dist/src/artifacts/graph-query.js +18 -8
  20. package/dist/src/artifacts/index-adapters.js +339 -0
  21. package/dist/src/artifacts/index-builder.js +143 -14
  22. package/dist/src/artifacts/index-files.js +15 -4
  23. package/dist/src/artifacts/index-preparation.js +2 -0
  24. package/dist/src/artifacts/index-reader.js +44 -0
  25. package/dist/src/artifacts/index-refresh.js +114 -55
  26. package/dist/src/artifacts/index-status.js +20 -5
  27. package/dist/src/artifacts/memory-maintenance.js +503 -0
  28. package/dist/src/artifacts/prebuilt-relations.js +3 -1
  29. package/dist/src/artifacts/query-engine.js +263 -108
  30. package/dist/src/artifacts/relations-builder.js +2 -2
  31. package/dist/src/artifacts/source-graph.js +2 -2
  32. package/dist/src/artifacts/types.js +9 -1
  33. package/dist/src/auth/client.js +5 -1
  34. package/dist/src/auth/credential-store.js +5 -1
  35. package/dist/src/auth/sensitive-input.js +151 -0
  36. package/dist/src/channel/manager.mjs +3 -0
  37. package/dist/src/cli/handlers/agentcard.js +47 -25
  38. package/dist/src/cli/handlers/auth.js +22 -2
  39. package/dist/src/cli/handlers/decision.js +22 -3
  40. package/dist/src/cli/handlers/effect.js +4 -84
  41. package/dist/src/cli/handlers/guided-setup.js +470 -0
  42. package/dist/src/cli/handlers/help.js +2 -2
  43. package/dist/src/cli/handlers/housekeeper.js +1110 -0
  44. package/dist/src/cli/handlers/index.js +4 -2
  45. package/dist/src/cli/handlers/init.js +41 -6
  46. package/dist/src/cli/handlers/install.js +6 -0
  47. package/dist/src/cli/handlers/local-executor.js +5 -3
  48. package/dist/src/cli/handlers/marketplace.js +15 -4
  49. package/dist/src/cli/handlers/mc.js +509 -53
  50. package/dist/src/cli/handlers/models.js +32 -2
  51. package/dist/src/cli/handlers/ralph-launcher.js +76 -4
  52. package/dist/src/cli/handlers/rules.js +1 -1
  53. package/dist/src/cli/handlers/script-runner.js +73 -2
  54. package/dist/src/cli/handlers/serve.js +5 -3
  55. package/dist/src/cli/handlers/sessions.js +1 -0
  56. package/dist/src/cli/handlers/setup.js +432 -1
  57. package/dist/src/cli/handlers/skill-lint.js +1 -1
  58. package/dist/src/cli/handlers/subcommands.js +118 -8
  59. package/dist/src/cli/handlers/use.js +335 -107
  60. package/dist/src/cli/handlers/workspace.js +3 -1
  61. package/dist/src/cli/prompt-utils.js +81 -0
  62. package/dist/src/cli/router.js +16 -1
  63. package/dist/src/config/aiwg-config.js +42 -0
  64. package/dist/src/config/cli.js +7 -3
  65. package/dist/src/config/decision-config.js +14 -1
  66. package/dist/src/config/gitignore.js +4 -0
  67. package/dist/src/config/native-sandbox-warnings.js +25 -0
  68. package/dist/src/config/workspace.js +2 -1
  69. package/dist/src/contributors/validation.js +6 -5
  70. package/dist/src/decision/adapters/jev.js +20 -31
  71. package/dist/src/decision/admission.js +7 -3
  72. package/dist/src/decision/ask.js +6 -1
  73. package/dist/src/decision/benchmark.js +482 -0
  74. package/dist/src/decision/ledger.js +22 -3
  75. package/dist/src/decision/pricing.js +147 -0
  76. package/dist/src/decision/qualification/gate-evidence.js +23 -18
  77. package/dist/src/decision/qualification/load-staged.js +576 -0
  78. package/dist/src/decision/qualification/load.js +109 -33
  79. package/dist/src/decision/qualification/runner.js +12 -5
  80. package/dist/src/decision/review/service.js +6 -4
  81. package/dist/src/decision/review/validate.js +23 -2
  82. package/dist/src/decision/savings.js +8 -3
  83. package/dist/src/discovery/index.js +492 -0
  84. package/dist/src/discovery/interview.js +238 -0
  85. package/dist/src/discovery/plan-apply.js +567 -0
  86. package/dist/src/discovery/plan-store.js +171 -0
  87. package/dist/src/discovery/plan-types.js +2 -0
  88. package/dist/src/discovery/plan-validation.js +139 -0
  89. package/dist/src/discovery/types.js +2 -0
  90. package/dist/src/effects/host.js +91 -0
  91. package/dist/src/extensions/commands/definitions.js +49 -9
  92. package/dist/src/extensions/manifest.js +71 -44
  93. package/dist/src/extensions/project-local-discovery.js +1 -1
  94. package/dist/src/extensions/project-local-gitignore.js +2 -0
  95. package/dist/src/extensions/project-quickref.js +18 -17
  96. package/dist/src/extensions/validation.js +32 -29
  97. package/dist/src/housekeeper/daemon-config.js +148 -0
  98. package/dist/src/housekeeper/ipc.js +84 -0
  99. package/dist/src/housekeeper/lifecycle.js +148 -0
  100. package/dist/src/housekeeper/platform.js +35 -0
  101. package/dist/src/housekeeper/status.js +70 -0
  102. package/dist/src/housekeeper/units.js +114 -0
  103. package/dist/src/issues/cli.js +16 -5
  104. package/dist/src/issues/live.js +44 -12
  105. package/dist/src/jobs/flow.js +22 -21
  106. package/dist/src/lint/rule-activation.js +20 -5
  107. package/dist/src/lint/runner.js +1 -1
  108. package/dist/src/marketplace/exchange.js +18 -6
  109. package/dist/src/marketplace/provenance.js +3 -2
  110. package/dist/src/mcp/adapters/codex-runtime.js +46 -76
  111. package/dist/src/mcp/cli.mjs +22 -96
  112. package/dist/src/mcp/config-file.mjs +6 -2
  113. package/dist/src/mcp/config-layers.mjs +23 -7
  114. package/dist/src/mcp/grok-build-config.mjs +2 -1
  115. package/dist/src/mcp/muse-native-config.mjs +2 -1
  116. package/dist/src/mcp/profiles.js +18 -31
  117. package/dist/src/mcp/profiles.mjs +18 -32
  118. package/dist/src/mcp/registry.js +7 -27
  119. package/dist/src/mcp/registry.mjs +7 -28
  120. package/dist/src/mcp/server.mjs +34 -1
  121. package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
  122. package/dist/src/mcp/tools/command-run.mjs +3 -2
  123. package/dist/src/mcp/tools/decision.mjs +49 -48
  124. package/dist/src/mcp/tools/discovery.mjs +46 -21
  125. package/dist/src/mcp/tools/orchestration.mjs +22 -22
  126. package/dist/src/mcp/tools/subsystems.mjs +9 -8
  127. package/dist/src/mcp/tools/worker-invoke.mjs +30 -6
  128. package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
  129. package/dist/src/memory/audit.js +719 -0
  130. package/dist/src/memory/canonical-context.js +392 -13
  131. package/dist/src/memory/canonical-maintenance.js +95 -0
  132. package/dist/src/memory/cli-result.js +22 -0
  133. package/dist/src/memory/cli.js +176 -0
  134. package/dist/src/memory/context-pack.js +57 -6
  135. package/dist/src/memory/cost.js +512 -0
  136. package/dist/src/memory/firewall-classification.d.mts +7 -0
  137. package/dist/src/memory/firewall-classification.mjs +32 -0
  138. package/dist/src/memory/index.js +8 -0
  139. package/dist/src/memory/line-maintenance.js +68 -0
  140. package/dist/src/memory/maintenance-cli.js +286 -0
  141. package/dist/src/memory/maintenance-contract.js +136 -0
  142. package/dist/src/memory/maintenance-index.js +18 -0
  143. package/dist/src/memory/maintenance-owner.js +2 -0
  144. package/dist/src/memory/maintenance-record.js +138 -0
  145. package/dist/src/memory/maintenance.js +254 -0
  146. package/dist/src/memory/project-registry.js +2 -1
  147. package/dist/src/memory/provider-memory-adapter.js +154 -0
  148. package/dist/src/memory/recommend-cli.js +83 -0
  149. package/dist/src/memory/recommend.js +269 -0
  150. package/dist/src/memory/scheduled.js +81 -0
  151. package/dist/src/memory/taxonomy.js +44 -0
  152. package/dist/src/mission-protocol/codecs.js +19 -9
  153. package/dist/src/mission-protocol/worker-status.js +91 -1
  154. package/dist/src/models/config-loader.js +11 -1
  155. package/dist/src/models/model-capabilities.v1.json +74 -50
  156. package/dist/src/models/provider-policy.js +125 -62
  157. package/dist/src/models/resolver.js +45 -8
  158. package/dist/src/models/worker-installation.d.mts +8 -1
  159. package/dist/src/models/worker-installation.mjs +231 -38
  160. package/dist/src/models/wrapper-route.js +1 -1
  161. package/dist/src/output-modes/registry.js +8 -7
  162. package/dist/src/packages/adapters/git.js +99 -23
  163. package/dist/src/packages/adapters/gitea.js +8 -27
  164. package/dist/src/packages/adapters/github.js +7 -25
  165. package/dist/src/packages/registry.js +4 -4
  166. package/dist/src/plugin/metadata-validator.js +1 -1
  167. package/dist/src/process/cli-command.d.mts +5 -0
  168. package/dist/src/process/cli-command.mjs +42 -0
  169. package/dist/src/providers/deploy-version.d.mts +1 -0
  170. package/dist/src/providers/deploy-version.mjs +17 -0
  171. package/dist/src/providers/provider-definitions.js +19 -16
  172. package/dist/src/providers/skill-ownership.d.mts +11 -2
  173. package/dist/src/providers/skill-ownership.mjs +35 -17
  174. package/dist/src/rules/activation.d.mts +11 -2
  175. package/dist/src/rules/activation.mjs +82 -6
  176. package/dist/src/rules/inventory.js +1 -1
  177. package/dist/src/rules/rule-frontmatter.schema.json +2 -0
  178. package/dist/src/schema/zod-validation.d.mts +6 -0
  179. package/dist/src/schema/zod-validation.mjs +50 -0
  180. package/dist/src/serve/executor-registry.js +297 -20
  181. package/dist/src/serve/executor-token.d.mts +1 -0
  182. package/dist/src/serve/executor-token.mjs +8 -0
  183. package/dist/src/serve/shared-host-scheduler.js +1102 -31
  184. package/dist/src/serve/worker-invocation.js +124 -15
  185. package/dist/src/sessions/adapters/claude.js +19 -18
  186. package/dist/src/sessions/adapters/codex.js +10 -9
  187. package/dist/src/sessions/adapters/copilot.js +14 -13
  188. package/dist/src/sessions/adapters/cursor.js +19 -18
  189. package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
  190. package/dist/src/sessions/adapters/factory.js +11 -10
  191. package/dist/src/sessions/adapters/generic.js +32 -23
  192. package/dist/src/sessions/adapters/grokbot.js +35 -35
  193. package/dist/src/sessions/adapters/hermes.js +20 -19
  194. package/dist/src/sessions/adapters/muse.js +50 -49
  195. package/dist/src/sessions/adapters/omp.js +5 -4
  196. package/dist/src/sessions/adapters/openclaw.js +30 -29
  197. package/dist/src/sessions/adapters/opencode.js +26 -26
  198. package/dist/src/sessions/adapters/openhuman.js +24 -23
  199. package/dist/src/sessions/adapters/pi.js +5 -4
  200. package/dist/src/sessions/adapters/windsurf.js +8 -8
  201. package/dist/src/sessions/analytics.js +10 -9
  202. package/dist/src/sessions/candidates.js +7 -6
  203. package/dist/src/sessions/contracts.js +63 -53
  204. package/dist/src/sessions/output-registration.js +11 -10
  205. package/dist/src/sessions/workspace-discovery.js +3 -4
  206. package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
  207. package/dist/src/smiths/context-pipeline/claude-hook.js +46 -10
  208. package/dist/src/smiths/context-pipeline/context-file-safety.js +330 -9
  209. package/dist/src/smiths/context-pipeline/finalization.js +3 -2
  210. package/dist/src/smiths/context-pipeline/generator.js +7 -19
  211. package/dist/src/smiths/context-pipeline/legacy-inject.js +3 -10
  212. package/dist/src/smiths/context-pipeline/managed-hook.js +5 -5
  213. package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
  214. package/dist/src/smiths/context-pipeline/workspace-context.js +110 -22
  215. package/dist/src/tracker/project-inputs.js +2 -0
  216. package/dist/src/update/checker.d.mts +4 -0
  217. package/dist/src/update/checker.mjs +14 -0
  218. package/dist/src/update/notifier.mjs +2 -4
  219. package/dist/src/writing/exemplar-selection.js +6 -6
  220. package/dist/src/writing/voice-evaluation.js +24 -23
  221. package/dist/src/writing/writer-migration.js +14 -13
  222. package/dist/src/writing/writer-profile.js +19 -18
  223. package/dist/src/writing/writing-brief.js +18 -17
  224. package/dist/src/writing/writing-receipt.js +47 -46
  225. package/package.json +5 -2
  226. package/schemas/decision/DecisionReview.schema.json +78 -1
  227. package/schemas/mission-v1.schema.json +3 -0
  228. package/tools/agents/deploy-agents.mjs +67 -39
  229. package/tools/agents/providers/antigravity.mjs +6 -1
  230. package/tools/agents/providers/base.mjs +24 -14
  231. package/tools/agents/providers/claude.mjs +6 -3
  232. package/tools/agents/providers/codex.mjs +54 -57
  233. package/tools/agents/providers/context-write.mjs +28 -0
  234. package/tools/agents/providers/copilot.mjs +13 -4
  235. package/tools/agents/providers/cursor.mjs +1 -1
  236. package/tools/agents/providers/deepseek-harness.mjs +1 -1
  237. package/tools/agents/providers/factory.mjs +7 -1
  238. package/tools/agents/providers/grok-build.mjs +18 -2
  239. package/tools/agents/providers/grokbot.mjs +1 -1
  240. package/tools/agents/providers/hermes.mjs +12 -15
  241. package/tools/agents/providers/muse-hooks.mjs +21 -14
  242. package/tools/agents/providers/muse.mjs +7 -2
  243. package/tools/agents/providers/omp.mjs +31 -5
  244. package/tools/agents/providers/opencode.mjs +14 -5
  245. package/tools/agents/providers/openhuman.mjs +1 -1
  246. package/tools/agents/providers/pi.mjs +1 -1
  247. package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
  248. package/tools/agents/providers/rule-delivery.mjs +289 -80
  249. package/tools/agents/providers/warp.mjs +4 -1
  250. package/tools/agents/providers/windsurf.mjs +13 -3
  251. package/tools/cli/workspace-status.mjs +5 -0
  252. package/tools/commands/deploy-prompts-codex.mjs +11 -8
  253. package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
  254. package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +26 -0
  255. package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +7 -1
  256. package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
  257. package/tools/ralph-external/lib/recovery-probe.mjs +14 -4
  258. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  259. package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
  260. package/tools/ralph-external/process-monitor.mjs +49 -8
  261. package/tools/ralph-external/session-launcher.mjs +405 -35
  262. package/tools/skills/deploy-skills-codex.mjs +11 -7
  263. package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
@@ -1,13 +1,29 @@
1
1
  import { boundedSpawnSync } from '../../process/bounded-child-process.mjs';
2
+ import { helperEnvironment, HELPER_ENV_ALLOWLIST } from '../../process/cli-command.mjs';
3
+ import { readPrivateValueFile } from '../../auth/sensitive-input.js';
4
+ import { setupJev } from '../../decision/driver.js';
2
5
  import { existsSync } from 'fs';
3
6
  import { emptyConfig, FORCE_PUSH_POLICY_ALIAS_NOTE, normalizeForcePushPolicy as normalizeForcePushPolicyShared, getConfigPath, getProjectDir, readAiwgConfig, resolveRemoteProvider, VALID_PROVIDERS, writeAiwgConfig, } from '../../config/aiwg-config.js';
4
7
  import { AiwgError, EXIT_CODES } from '../errors.js';
5
- import { askChoice, askConsent, askString, askYesNo, createPromptInterface } from '../prompt-utils.js';
8
+ import { askChoice, askConsent, askString, askYesNo, createPromptInterface, createSecretPromptInterface } from '../prompt-utils.js';
6
9
  import * as ui from '../ui.js';
10
+ import { join } from 'node:path';
11
+ import { validateJevOptions } from './guided-setup.js';
12
+ import { validateParallelismConfig } from '../../config/aiwg-config.js';
13
+ import { readFile } from 'node:fs/promises';
14
+ import { discoverInventory } from '../../discovery/index.js';
15
+ import { applyGuidedPlan, configPathFor, credentialReferenceFor, defaultPlanReviewIO, projectRootForWorkspace, renderHumanReview, reviewGuidedPlan, } from '../../discovery/plan-apply.js';
16
+ import { readSetupPlan, writeSetupPlan } from '../../discovery/plan-store.js';
17
+ import { workspaceSlug } from '../../discovery/interview.js';
18
+ import { registerProjectMemory } from '../../memory/project-registry.js';
19
+ import { verifyProviderDeployment } from '../services/deployment-verification.js';
7
20
  import { projectAiwgPath } from '../../config/project-artifacts.js';
21
+ import { useHandler } from './use.js';
8
22
  import { normalizeProviderDefinitionId } from '../../providers/provider-definitions.js';
9
23
  import { isInteractive } from '../env.js';
10
24
  import { requireFlagValue as strictFlagValue, MissingFlagValueError } from '../flag-parsing.js';
25
+ import { parseGuidedSetupFlags, runGuidedSetup } from './guided-setup.js';
26
+ import { DEFAULT_SCRIPTS, parseInitArgInputs } from './init.js';
11
27
  import { detectInstalledWorkerClis, evaluateWorkerDispatchOffer, workerDispatchOfferHintWithArg, workerDispatchOfferQuestion, WORKER_DISPATCH_ARG_VALUES, } from '../../models/worker-dispatch-offer.js';
12
28
  const DELIVERY_MODES = ['pr-required', 'feature-branch', 'direct'];
13
29
  const FORCE_PUSH_POLICIES = ['never', 'own-branch-only', 'allowed'];
@@ -120,6 +136,7 @@ export function parseSetupProjectOptions(ctx) {
120
136
  }
121
137
  export function detectGitRemotes(projectDir) {
122
138
  const result = boundedSpawnSync('git', ['-C', projectDir, 'remote', '-v'], 'quick', {
139
+ env: helperEnvironment(),
123
140
  encoding: 'utf-8',
124
141
  stdio: ['ignore', 'pipe', 'ignore'],
125
142
  });
@@ -143,6 +160,7 @@ export function detectGitRemotes(projectDir) {
143
160
  }
144
161
  function detectDefaultBranch(projectDir) {
145
162
  const symbolic = boundedSpawnSync('git', ['-C', projectDir, 'symbolic-ref', '--quiet', '--short', 'refs/remotes/origin/HEAD'], 'quick', {
163
+ env: helperEnvironment(),
146
164
  encoding: 'utf-8',
147
165
  stdio: ['ignore', 'pipe', 'ignore'],
148
166
  });
@@ -150,6 +168,7 @@ function detectDefaultBranch(projectDir) {
150
168
  if (symbolic.status === 0 && fromOrigin)
151
169
  return fromOrigin;
152
170
  const branch = boundedSpawnSync('git', ['-C', projectDir, 'branch', '--show-current'], 'quick', {
171
+ env: helperEnvironment(),
153
172
  encoding: 'utf-8',
154
173
  stdio: ['ignore', 'pipe', 'ignore'],
155
174
  });
@@ -157,6 +176,7 @@ function detectDefaultBranch(projectDir) {
157
176
  }
158
177
  function gitConfig(projectDir, key) {
159
178
  const result = boundedSpawnSync('git', ['-C', projectDir, 'config', '--get', key], 'quick', {
179
+ env: helperEnvironment(),
160
180
  encoding: 'utf-8',
161
181
  stdio: ['ignore', 'pipe', 'ignore'],
162
182
  });
@@ -470,6 +490,310 @@ function printPlan(plan) {
470
490
  ui.warn(warning);
471
491
  }
472
492
  }
493
+ // ---------------------------------------------------------------------------
494
+ // Guided plan review and apply (#3449 A4).
495
+ //
496
+ // `--review` renders a saved guided plan per workspace and provider without
497
+ // writing anything. `--apply` executes `remainingPlanActions` in dependency
498
+ // order through the existing owners: project policy through
499
+ // `buildSetupProjectPlan` + `writeAiwgConfig` (the setup/init config owners),
500
+ // framework deployment through the `use` handler (consuming its
501
+ // `aiwg.use.result.v1` verification), and project registration through the
502
+ // project registry owner. Nothing here re-implements those paths.
503
+ // ---------------------------------------------------------------------------
504
+ /** Legacy policy flags: when any is present, `--dry-run` keeps its legacy preview meaning. */
505
+ const LEGACY_SETUP_POLICY_FLAGS = [
506
+ '--primary', '--issue-tracker', '--customer-issue-tracker', '--ci',
507
+ '--issue-provider', '--customer-issue-provider', '--delivery-mode', '--default-branch',
508
+ '--require-ci-green', '--auto-close-issues', '--issue-comment-on-cycle', '--force-push-policy',
509
+ '--require-signed-commits', '--committer-name', '--committer-email', '--signing-format',
510
+ '--signing-key', '--signing-enforce', '--tracker-actor-login', '--tracker-actor-via',
511
+ '--customer-tracker-actor-login', '--customer-tracker-actor-via', '--worker-dispatch', '--providers',
512
+ ];
513
+ function hasLegacySetupPolicyFlags(args) {
514
+ return LEGACY_SETUP_POLICY_FLAGS.some(flag => args.includes(flag) || args.some(arg => arg.startsWith(`${flag}=`)));
515
+ }
516
+ const GUIDED_INTENT_FRAMEWORK = {
517
+ code: 'sdlc', docs: 'writing', ops: 'ops', mixed: 'sdlc',
518
+ };
519
+ function guidedAnswer(plan, workspace, block, topic, provider = 'shared') {
520
+ const projectRoot = projectRootForWorkspace(plan, workspace) ?? workspace;
521
+ return plan.answers[`${block}.${topic}.ws-${workspaceSlug(projectRoot)}.${provider}`]?.value;
522
+ }
523
+ function guidedProviders(plan, workspace) {
524
+ const projectRoot = projectRootForWorkspace(plan, workspace) ?? workspace;
525
+ const prefix = `tools.provider.ws-${workspaceSlug(projectRoot)}.`;
526
+ return Object.entries(plan.answers)
527
+ .filter(([id, answer]) => id.startsWith(prefix) && answer.value === true)
528
+ .map(([id]) => id.slice(prefix.length))
529
+ .sort();
530
+ }
531
+ async function writeGuidedProjectConfig(plan, action) {
532
+ const asRecord = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : {};
533
+ const delivery = asRecord(guidedAnswer(plan, action.workspace, 'capabilities', 'delivery'));
534
+ const signing = guidedAnswer(plan, action.workspace, 'capabilities', 'signing');
535
+ const tracker = asRecord(guidedAnswer(plan, action.workspace, 'capabilities', 'tracker'));
536
+ const team = guidedAnswer(plan, action.workspace, 'intent', 'team');
537
+ const string = (value) => typeof value === 'string' ? value : undefined;
538
+ const boolean = (value) => typeof value === 'boolean' ? value : undefined;
539
+ const built = await buildSetupProjectPlan({
540
+ projectDir: action.workspace,
541
+ providers: guidedProviders(plan, action.workspace),
542
+ ...(string(delivery.mode) ? { deliveryMode: string(delivery.mode) } : {}),
543
+ ...(string(delivery.default_branch) ? { defaultBranch: string(delivery.default_branch) } : {}),
544
+ ...(boolean(delivery.require_ci_green) ? { requireCiGreen: boolean(delivery.require_ci_green) } : {}),
545
+ ...(boolean(delivery.auto_close_issues) ? { autoCloseIssues: boolean(delivery.auto_close_issues) } : {}),
546
+ ...(boolean(delivery.issue_comment_on_cycle) ? { issueCommentOnCycle: boolean(delivery.issue_comment_on_cycle) } : {}),
547
+ ...(!delivery.force_push_policy && team === 'shared' ? { forcePushPolicy: 'never' } : {}),
548
+ ...(string(delivery.force_push_policy) ? { forcePushPolicy: string(delivery.force_push_policy) } : {}),
549
+ ...(signing === false ? { requireSignedCommits: false } : {}),
550
+ ...(typeof signing?.required === 'boolean'
551
+ ? { requireSignedCommits: signing.required } : {}),
552
+ ...(string(signing?.format) ? { signingFormat: string(signing.format) } : {}),
553
+ ...(string(signing?.key) ? { signingKey: string(signing.key) } : {}),
554
+ ...(string(signing?.enforce) ? { signingEnforce: string(signing.enforce) } : {}),
555
+ ...(string(tracker.primary) ? { primary: string(tracker.primary) } : {}),
556
+ ...(string(tracker.issue_tracker) ? { issueTracker: string(tracker.issue_tracker) } : {}),
557
+ ...(string(tracker.issue_provider) ? { issueProvider: string(tracker.issue_provider) } : {}),
558
+ ...(string(tracker.customer_issue_tracker) ? { customerIssueTracker: string(tracker.customer_issue_tracker) } : {}),
559
+ ...(string(tracker.customer_issue_provider) ? { customerIssueProvider: string(tracker.customer_issue_provider) } : {}),
560
+ ...(string(tracker.ci) ? { ci: string(tracker.ci) } : {}),
561
+ ...(string(tracker.tracker_actor_login) ? { trackerActorLogin: string(tracker.tracker_actor_login) } : {}),
562
+ ...(string(tracker.tracker_actor_via) ? { trackerActorVia: string(tracker.tracker_actor_via) } : {}),
563
+ ...(string(tracker.customer_tracker_actor_login) ? { customerTrackerActorLogin: string(tracker.customer_tracker_actor_login) } : {}),
564
+ ...(string(tracker.customer_tracker_actor_via) ? { customerTrackerActorVia: string(tracker.customer_tracker_actor_via) } : {}),
565
+ });
566
+ // Interview script answers merge on top of the preserved config: init owns
567
+ // the default-script set, setup owns the policy merge above.
568
+ const scripts = asRecord(guidedAnswer(plan, action.workspace, 'tools', 'scripts'));
569
+ let next = built.next;
570
+ if (Object.keys(scripts).length > 0) {
571
+ const merged = { ...(next.scripts ?? {}) };
572
+ if (scripts.defaultScripts === true) {
573
+ for (const [name, command] of Object.entries(DEFAULT_SCRIPTS)) {
574
+ if (!merged[name])
575
+ merged[name] = command;
576
+ }
577
+ }
578
+ const custom = scripts.scripts;
579
+ if (custom && typeof custom === 'object' && !Array.isArray(custom))
580
+ Object.assign(merged, custom);
581
+ next = { ...next, scripts: merged };
582
+ }
583
+ await writeAiwgConfig(action.workspace, next);
584
+ return `merged guided policy into ${getConfigPath(action.workspace)}`;
585
+ }
586
+ // configure-provider writes no provider files: provider config files belong
587
+ // to the existing deployment owner (`aiwg use`, the `deploy-framework`
588
+ // action), which `PLAN_APPLY_KIND_ORDER` runs after every
589
+ // configure-provider. An existing file is user-authored and left untouched
590
+ // (applied, preserved); a missing one defers to deploy-framework. The
591
+ // credential reference was already resolved at apply time by the apply engine
592
+ // and is never written anywhere.
593
+ async function writeGuidedProviderConfig(plan, action, configPath) {
594
+ if (!configPath)
595
+ throw new Error(`Cannot apply '${action.id}': no provider config path was recorded for ${action.provider}.`);
596
+ try {
597
+ await readFile(configPath, 'utf8');
598
+ return `preserved existing provider file ${configPath} (left untouched)`;
599
+ }
600
+ catch (error) {
601
+ if (error?.code !== 'ENOENT')
602
+ throw error;
603
+ }
604
+ const deploy = plan.actions.find(other => other.workspace === action.workspace &&
605
+ other.provider === action.provider && other.kind === 'deploy-framework');
606
+ const owner = deploy ? `'${deploy.id}'` : 'deploy-framework';
607
+ return `provider files for ${action.provider} in ${action.workspace} are owned by ${owner}; nothing written`;
608
+ }
609
+ async function verifyGuidedProvider(plan, fresh, action, reference) {
610
+ const executable = action.dependsOn.find(fact => fact.kind === 'tool')?.executable ?? action.provider;
611
+ const tool = fresh.tools.find(entry => entry.executable === executable);
612
+ if (!tool || tool.installed !== 'yes') {
613
+ throw new Error(`Provider tool '${executable}' is not installed; install it and re-run discovery before verifying '${action.id}'.`);
614
+ }
615
+ const configPath = action.dependsOn.find(fact => fact.kind === 'path')?.path
616
+ ?? configPathFor(plan, action.workspace, action.provider);
617
+ let configNote = 'no config path recorded';
618
+ if (configPath) {
619
+ try {
620
+ await readFile(configPath, 'utf8');
621
+ configNote = `config present at ${configPath}`;
622
+ }
623
+ catch {
624
+ configNote = `config missing at ${configPath}`;
625
+ }
626
+ }
627
+ const version = tool.version ? `version ${tool.version}` : 'version unknown';
628
+ // Hyphenated wording: receipt messages persist through the plan store,
629
+ // whose redaction gate rejects `credential <value>` phrasing.
630
+ const credential = reference ? `credential-ref ${reference.source}:${reference.name} readable at apply time` : 'no credential-reference recorded';
631
+ return `verified ${action.provider} (${executable} installed, ${version}; ${configNote}; ${credential}; read-back only)`;
632
+ }
633
+ async function deployGuidedFramework(plan, action, frameworkRoot, signal) {
634
+ const intent = guidedAnswer(plan, action.workspace, 'intent', 'use');
635
+ const framework = GUIDED_INTENT_FRAMEWORK[typeof intent === 'string' ? intent : 'code'] ?? 'sdlc';
636
+ const args = [framework, '--provider', action.provider, ...(action.scope === 'user' ? ['--scope', 'user'] : [])];
637
+ const deployed = await useHandler.execute({ cwd: action.workspace, args, rawArgs: args, frameworkRoot, dryRun: false, signal });
638
+ if (deployed.exitCode !== 0) {
639
+ throw new Error(`aiwg use ${framework} --provider ${action.provider} failed${deployed.message ? `: ${deployed.message}` : ` (exit ${deployed.exitCode})`}.`);
640
+ }
641
+ // Consume the aiwg.use.result.v1 verification for this provider and scope.
642
+ const verification = await verifyProviderDeployment({
643
+ projectRoot: action.workspace,
644
+ frameworkRoot,
645
+ provider: action.provider,
646
+ scope: action.scope,
647
+ requestedBundles: [framework],
648
+ });
649
+ const blocking = verification.findings.filter(finding => finding.severity === 'blocking');
650
+ if (verification.outcome === 'failed' || blocking.length > 0) {
651
+ throw new Error(`Deployment verification failed for ${action.provider}: ${blocking[0]?.message ?? verification.outcome}.`);
652
+ }
653
+ return `deployed ${framework} for ${action.provider} (verification: ${verification.outcome})`;
654
+ }
655
+ function defaultGuidedApplyIO(plan, fresh, ctx, projectDir, frameworkRoot, canPrompt) {
656
+ return {
657
+ ...defaultPlanReviewIO(),
658
+ readEnv: name => process.env[name],
659
+ // Headless apply can consume redirected stdin. Interactive apply uses the prompt below.
660
+ ...(!canPrompt ? { readStdinCredential: async () => {
661
+ const chunks = [];
662
+ for await (const chunk of process.stdin)
663
+ chunks.push(Buffer.from(chunk));
664
+ return Buffer.concat(chunks).toString('utf8');
665
+ } } : {}),
666
+ readCredentialFile: async (path) => readPrivateValueFile(path, '--credential'),
667
+ // stdin-at-apply prompts for the value without echoing it anywhere: the
668
+ // label names the consumer only, and the value never reaches output.
669
+ ...(canPrompt ? { promptCredential: async (label) => {
670
+ const rl = createSecretPromptInterface();
671
+ try {
672
+ process.stdout.write(label);
673
+ return await askString(rl, '', '', ctx.signal);
674
+ }
675
+ finally {
676
+ rl.close();
677
+ }
678
+ } } : {}),
679
+ now: () => new Date().toISOString(),
680
+ save: async (next) => {
681
+ await writeSetupPlan(projectDir, next);
682
+ },
683
+ owners: {
684
+ configureJev: async ({ action, token, options }) => {
685
+ if (options != null)
686
+ validateJevOptions(options);
687
+ const settings = (options ?? {});
688
+ // Invoke the existing owner directly. spawnSync's input option is
689
+ // rendered by NODE_DEBUG=child_process before the child can read it.
690
+ const result = await setupJev({
691
+ token,
692
+ ...(typeof settings.region === 'string' ? { region: settings.region } : {}),
693
+ ...(typeof settings.endpoint === 'string' ? { endpoint: settings.endpoint } : {}),
694
+ verify: settings.verify === true,
695
+ remove: settings.remove === true,
696
+ }, { env: process.env, cwd: action.workspace });
697
+ if (settings.verify === true && settings.remove !== true && result.verified !== true) {
698
+ throw new Error('Jev verification incomplete.');
699
+ }
700
+ },
701
+ configureWorkerDispatch: async ({ action }) => {
702
+ const built = await buildSetupProjectPlan({ projectDir: action.workspace, workerDispatchChoice: 'enable' });
703
+ const settings = guidedAnswer(plan, action.workspace, 'capabilities', 'worker-config');
704
+ let next = built.next;
705
+ if (settings && typeof settings === 'object' && !Array.isArray(settings)) {
706
+ if (Object.keys(settings).some(key => !['clis', 'groups', 'admission', 'budgets'].includes(key)))
707
+ throw new Error('Invalid worker settings.');
708
+ next = { ...next, parallelism: { ...next.parallelism, ...settings } };
709
+ }
710
+ if (validateParallelismConfig(next.parallelism).length)
711
+ throw new Error('Invalid worker settings.');
712
+ await writeAiwgConfig(action.workspace, next);
713
+ const child = boundedSpawnSync(process.execPath, [join(frameworkRoot, 'bin', 'aiwg.mjs'),
714
+ 'doctor', '--probe-workers', '--qualify', '--yes', '--json'], 'long', {
715
+ cwd: action.workspace, env: helperEnvironment(process.env, [...HELPER_ENV_ALLOWLIST,
716
+ 'AIWG_ROOT', 'AIWG_HOME', 'AIWG_CONFIG', 'XDG_CONFIG_HOME', 'XDG_DATA_HOME',
717
+ 'AIWG_ARTIFACTS_PATH', 'AIWG_PROJECT_ARTIFACTS_PATH', 'AIWG_PROJECT_AIWG_DIR',
718
+ 'AIWG_PROJECT_MEMORY_HOME', 'NO_UPDATE_NOTIFIER', 'NO_COLOR', 'CI']), encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], maxBuffer: 1024 * 1024,
719
+ });
720
+ if (child.error || child.status !== 0)
721
+ throw new Error('Worker qualification failed.');
722
+ const report = JSON.parse(child.stdout);
723
+ if (report.qualification?.status !== 'recorded' || !report.qualification?.results?.length || report.qualification.results.some((row) => row.status !== 'qualified'))
724
+ throw new Error('Worker qualification incomplete.');
725
+ },
726
+ configureProvider: async ({ action, configPath }) => writeGuidedProviderConfig(plan, action, configPath),
727
+ verifyProvider: async ({ action }) => verifyGuidedProvider(plan, fresh, action, credentialReferenceFor(plan, action.workspace, action.provider)),
728
+ writeProjectConfig: async ({ action }) => writeGuidedProjectConfig(plan, action),
729
+ deployFramework: async ({ action }) => deployGuidedFramework(plan, action, frameworkRoot, ctx.signal),
730
+ registerProject: async ({ action }) => {
731
+ const entry = await registerProjectMemory({ workspaceRoot: action.workspace });
732
+ return `registered project '${entry.id}'`;
733
+ },
734
+ recordDecline: async ({ action }) => {
735
+ const built = await buildSetupProjectPlan({ projectDir: action.workspace, workerDispatchChoice: 'decline' });
736
+ await writeAiwgConfig(action.workspace, built.next);
737
+ return `recorded worker-dispatch decline in ${getConfigPath(action.workspace)}`;
738
+ },
739
+ },
740
+ };
741
+ }
742
+ async function loadGuidedPlan(projectDir, planId) {
743
+ const fresh = await discoverInventory({ workspaceRoot: projectDir });
744
+ const workspaceRoot = fresh.projects.find(project => project.sources.includes('workspace'))?.root ?? projectDir;
745
+ const id = planId ?? `setup-${workspaceSlug(workspaceRoot)}`;
746
+ let plan;
747
+ try {
748
+ plan = await readSetupPlan(projectDir, id);
749
+ }
750
+ catch {
751
+ throw new AiwgError({
752
+ code: 'ERR_SETUP_PLAN_NOT_FOUND',
753
+ message: `No guided setup plan '${id}' for ${projectDir}.`,
754
+ hint: 'Record one first with `aiwg setup --scope project|user` (or `aiwg init --scope ...`).',
755
+ exitCode: EXIT_CODES.GENERAL,
756
+ });
757
+ }
758
+ return { plan, fresh };
759
+ }
760
+ async function runGuidedReview(_ctx, projectDir, planId, json) {
761
+ const { plan, fresh } = await loadGuidedPlan(projectDir, planId);
762
+ // Review is read-only: findings come from revalidation plus filesystem
763
+ // reads, and nothing here writes (not even receipts).
764
+ const review = await reviewGuidedPlan(plan, fresh, defaultPlanReviewIO());
765
+ if (json)
766
+ return { exitCode: 0, rawOutput: true, message: JSON.stringify(review, null, 2) };
767
+ return { exitCode: 0, message: renderHumanReview(review) };
768
+ }
769
+ async function runGuidedApply(ctx, projectDir, planId, options) {
770
+ const { plan, fresh } = await loadGuidedPlan(projectDir, planId);
771
+ // The existing --yes/confirmation gate and TTY rules: a write that can
772
+ // never be confirmed is refused before any owner runs.
773
+ if (!options.yes && !options.canPrompt) {
774
+ throw new AiwgError({
775
+ code: 'ERR_NON_INTERACTIVE_CONFIRMATION_REQUIRED',
776
+ message: 'Refusing to apply the guided setup plan in a non-interactive context without --yes.',
777
+ hint: 'Re-run with `aiwg setup --apply --yes` or use `--review`/`--dry-run` to preview only.',
778
+ exitCode: EXIT_CODES.USAGE,
779
+ });
780
+ }
781
+ if (!options.yes && options.canPrompt) {
782
+ const rl = createPromptInterface();
783
+ try {
784
+ const confirmed = await askYesNo(rl, `Apply the guided setup plan '${plan.id}'? [y/N]: `, false, ctx.signal);
785
+ if (!confirmed)
786
+ return { exitCode: 0, message: 'Guided setup apply cancelled.' };
787
+ }
788
+ finally {
789
+ rl.close();
790
+ }
791
+ }
792
+ const { result } = await applyGuidedPlan(plan, fresh, defaultGuidedApplyIO(plan, fresh, ctx, projectDir, options.frameworkRoot, options.canPrompt));
793
+ if (options.json)
794
+ return { exitCode: result.exitCode, rawOutput: true, message: JSON.stringify(result, null, 2) };
795
+ return { exitCode: result.exitCode, message: result.message };
796
+ }
473
797
  export const setupHandler = {
474
798
  id: 'setup',
475
799
  name: 'Setup',
@@ -484,8 +808,21 @@ export const setupHandler = {
484
808
 
485
809
  Options:
486
810
  --target <dir> Project directory
811
+ --scope project|user Record guided plan only (no config writes)
812
+ --force Recreate guided interview answers
813
+ --workspace <root> Observed workspace to configure (repeatable)
814
+ --monorepo root|package Monorepo target selection
815
+ --package <root> Observed package root (with --monorepo package)
816
+ --scan-roots <dir> Opt in to bounded discovery (repeatable)
817
+ --intent code|docs|ops|mixed Workspace usage intent
818
+ --jev enable|decline|defer Optional external decision service (default off)
819
+ --region <r> --endpoint <url> --verify --remove --token-stdin Existing Jev options
820
+ --credential <provider>=stdin|file:PATH|store:NAME|env:NAME Credential reference only
487
821
  --yes Confirm writes without prompting
488
822
  --dry-run Preview the setup plan
823
+ --review Render the saved guided plan per workspace/provider (writes nothing)
824
+ --apply Apply the saved guided plan through the existing owners
825
+ --plan <id> Guided plan ID (default: setup plan for the target directory)
489
826
  --non-interactive Disable prompts
490
827
  --json Emit the plan as JSON
491
828
  --primary <remote> Primary repository remote
@@ -524,12 +861,106 @@ Options:
524
861
  };
525
862
  }
526
863
  const args = subcommand === 'project' ? ctx.args.slice(1) : ctx.args;
864
+ let guidedFlags;
865
+ try {
866
+ guidedFlags = parseGuidedSetupFlags(args, 'setup');
867
+ }
868
+ catch (error) {
869
+ throw new AiwgError({ code: 'ERR_INVALID_VALUE', exitCode: EXIT_CODES.USAGE,
870
+ message: error instanceof Error ? error.message : String(error) });
871
+ }
527
872
  const options = parseSetupProjectOptions({ ...ctx, args });
528
873
  // #3062 review item 12: the one shared interactive decision (TTY, TERM,
529
874
  // CI, DEBIAN_FRONTEND) — this used to check only `process.stdin.isTTY &&
530
875
  // process.stdout.isTTY`, so a CI job with a pseudo-terminal could still
531
876
  // reach these prompts.
532
877
  const canPrompt = isInteractive(options.nonInteractive);
878
+ // #3449 A4: operate on a saved guided plan. `--review` renders it
879
+ // read-only; `--apply` executes it through the existing owners behind the
880
+ // same --yes/confirmation gate as legacy writes. `--dry-run` on a guided
881
+ // plan (no planning or policy flags) previews the same review and writes
882
+ // nothing. `--review` and `--apply` together is a usage error.
883
+ const wantsReview = boolFlag(args, '--review');
884
+ const wantsApply = boolFlag(args, '--apply');
885
+ if (wantsReview && wantsApply) {
886
+ throw new AiwgError({
887
+ code: 'ERR_USAGE_CONFLICTING_FLAGS',
888
+ message: 'Cannot combine --review with --apply; use --review to preview or --apply to write.',
889
+ exitCode: EXIT_CODES.USAGE,
890
+ });
891
+ }
892
+ if (wantsReview || wantsApply || (options.dryRun && !guidedFlags.enabled && !hasLegacySetupPolicyFlags(args))) {
893
+ let planId;
894
+ try {
895
+ planId = flagValue(args, '--plan');
896
+ }
897
+ catch (error) {
898
+ if (error instanceof MissingFlagValueError) {
899
+ throw new AiwgError({ code: 'ERR_USAGE_MISSING_FLAG_VALUE', message: `${error.message}.`, exitCode: EXIT_CODES.USAGE });
900
+ }
901
+ throw error;
902
+ }
903
+ // A bare `--dry-run` without a saved plan keeps its legacy preview
904
+ // meaning; only an existing plan switches it to the guided review.
905
+ if (!wantsReview && !wantsApply && options.dryRun) {
906
+ try {
907
+ return await runGuidedReview({ ...ctx, args }, options.projectDir, planId, options.json ?? false);
908
+ }
909
+ catch (error) {
910
+ if (error instanceof AiwgError && error.code === 'ERR_SETUP_PLAN_NOT_FOUND') {
911
+ // Fall through to the legacy setup preview below.
912
+ }
913
+ else
914
+ throw error;
915
+ }
916
+ }
917
+ else if (wantsReview || options.dryRun) {
918
+ return runGuidedReview({ ...ctx, args }, options.projectDir, planId, options.json ?? false);
919
+ }
920
+ else {
921
+ return runGuidedApply({ ...ctx, args }, options.projectDir, planId, { yes: options.yes ?? false, json: options.json ?? false, canPrompt, frameworkRoot: ctx.frameworkRoot });
922
+ }
923
+ }
924
+ if (guidedFlags.enabled) {
925
+ const target = flagValue(args, '--target');
926
+ const projectDir = target ?? options.projectDir;
927
+ let inputs;
928
+ try {
929
+ inputs = parseInitArgInputs(args);
930
+ }
931
+ catch (error) {
932
+ throw new AiwgError({ code: 'ERR_INVALID_VALUE', exitCode: EXIT_CODES.USAGE,
933
+ message: error instanceof Error ? error.message : String(error) });
934
+ }
935
+ const selected = (entries) => {
936
+ const present = entries.filter((entry) => entry[1] !== undefined);
937
+ return present.length ? Object.fromEntries(present) : undefined;
938
+ };
939
+ const tracker = selected([
940
+ ['primary', options.primary], ['issue_tracker', options.issueTracker], ['issue_provider', options.issueProvider],
941
+ ['customer_issue_tracker', options.customerIssueTracker], ['customer_issue_provider', options.customerIssueProvider],
942
+ ['ci', options.ci], ['tracker_actor_login', options.trackerActorLogin], ['tracker_actor_via', options.trackerActorVia],
943
+ ['customer_tracker_actor_login', options.customerTrackerActorLogin], ['customer_tracker_actor_via', options.customerTrackerActorVia],
944
+ ]);
945
+ const delivery = selected([
946
+ ['mode', options.deliveryMode], ['default_branch', options.defaultBranch], ['require_ci_green', options.requireCiGreen],
947
+ ['auto_close_issues', options.autoCloseIssues], ['issue_comment_on_cycle', options.issueCommentOnCycle], ['force_push_policy', options.forcePushPolicy],
948
+ ]);
949
+ const signing = options.requireSignedCommits === false ? false : selected([
950
+ ['required', options.requireSignedCommits], ['format', options.signingFormat], ['key', options.signingKey], ['enforce', options.signingEnforce],
951
+ ]);
952
+ const hasScripts = inputs.defaultScriptsArg !== undefined || inputs.customScriptsArg !== undefined || Object.keys(inputs.scriptPairs).length > 0;
953
+ const remotes = detectGitRemotes(projectDir);
954
+ const primary = options.primary ?? choosePrimary(remotes);
955
+ return runGuidedSetup({ ...ctx, args }, guidedFlags, { providers: inputs.providersArg,
956
+ workerDispatch: options.workerDispatchChoice, tracker, delivery, signing,
957
+ team: options.forcePushPolicy === undefined ? undefined : options.forcePushPolicy === 'never' ? 'shared' : 'solo',
958
+ ...(hasScripts ? { scripts: { defaultScripts: inputs.defaultScriptsArg ?? true,
959
+ customScripts: inputs.customScriptsArg ?? Object.keys(inputs.scriptPairs).length > 0, scripts: inputs.scriptPairs } } : {}),
960
+ }, canPrompt, projectDir, remotes.find(r => r.name === primary)?.provider === 'unknown', remotes.length ? { primary, issue_tracker: primary, ci: primary,
961
+ ...(remotes.find(r => r.name === primary)?.provider !== 'unknown'
962
+ ? { issue_provider: remotes.find(r => r.name === primary).provider } : {}) } : undefined);
963
+ }
533
964
  // #3062 second review, finding 6: refuse before any child process runs
534
965
  // — `buildSetupProjectPlan()` below makes four `git` calls on its own,
535
966
  // and this exact refusal used to happen only after building (and
@@ -47,7 +47,7 @@ function scoreSchema(frontmatter, diagnostics) {
47
47
  const result = validateSkillFrontmatter(frontmatter);
48
48
  if (result.success)
49
49
  return scoreDimension(true);
50
- const notes = result.errors.errors.map((e) => `${e.path.join('.') || '<root>'}: ${e.message}`);
50
+ const notes = result.errors.issues.map((e) => `${e.path.join('.') || '<root>'}: ${e.message}`);
51
51
  return scoreDimension(false, notes);
52
52
  }
53
53
  /**