universal-dev-standards 6.8.0 → 6.10.0

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 (225) hide show
  1. package/bin/uds.js +12 -2
  2. package/bundled/ai/standards/acceptance-criteria-traceability.ai.yaml +14 -2
  3. package/bundled/ai/standards/adr-standards.ai.yaml +14 -2
  4. package/bundled/ai/standards/code-review.ai.yaml +13 -3
  5. package/bundled/ai/standards/commit-message.ai.yaml +8 -4
  6. package/bundled/ai/standards/deferred-item-exit.ai.yaml +225 -0
  7. package/bundled/ai/standards/feature-discovery-standards.ai.yaml +14 -2
  8. package/bundled/ai/standards/governance-layer.ai.yaml +128 -2
  9. package/bundled/ai/standards/logging.ai.yaml +2 -2
  10. package/bundled/ai/standards/retrospective-standards.ai.yaml +14 -2
  11. package/bundled/ai/standards/reverse-engineering-standards.ai.yaml +73 -2
  12. package/bundled/ai/standards/security-standards.ai.yaml +2 -2
  13. package/bundled/ai/standards/spec-driven-development.ai.yaml +14 -2
  14. package/bundled/ai/standards/tech-debt-standards.ai.yaml +87 -3
  15. package/bundled/ai/standards/turn-completion-integrity.ai.yaml +131 -0
  16. package/bundled/core/acceptance-criteria-traceability.md +5 -2
  17. package/bundled/core/adr-standards.md +26 -2
  18. package/bundled/core/agent-communication-protocol.md +8 -0
  19. package/bundled/core/branch-completion.md +8 -0
  20. package/bundled/core/change-batching-standards.md +8 -0
  21. package/bundled/core/code-review-checklist.md +5 -2
  22. package/bundled/core/context-aware-loading.md +1 -1
  23. package/bundled/core/deferred-item-exit.md +254 -0
  24. package/bundled/core/execution-history.md +8 -0
  25. package/bundled/core/feature-discovery-standards.md +5 -1
  26. package/bundled/core/governance-layer.md +114 -2
  27. package/bundled/core/pipeline-integration-standards.md +8 -0
  28. package/bundled/core/retrospective-standards.md +4 -2
  29. package/bundled/core/reverse-engineering-standards.md +81 -2
  30. package/bundled/core/spec-driven-development.md +8 -2
  31. package/bundled/core/tech-debt-standards.md +67 -8
  32. package/bundled/core/turn-completion-integrity.md +196 -0
  33. package/bundled/core/workflow-enforcement.md +8 -0
  34. package/bundled/core/workflow-state-protocol.md +8 -0
  35. package/bundled/hooks/check-dangerous-cmd.mjs +60 -0
  36. package/bundled/hooks/check-logging-standard.mjs +59 -0
  37. package/bundled/hooks/check-turn-completion.mjs +233 -0
  38. package/bundled/hooks/inject-standards.mjs +183 -0
  39. package/bundled/hooks/telemetry-wrapper.mjs +77 -0
  40. package/bundled/hooks/turn-completion/detect.mjs +99 -0
  41. package/bundled/hooks/turn-completion/locales/en.mjs +159 -0
  42. package/bundled/hooks/turn-completion/locales/zh-TW.mjs +166 -0
  43. package/bundled/hooks/validate-commit-msg.mjs +104 -0
  44. package/bundled/locales/zh-CN/CHANGELOG.md +73 -3
  45. package/bundled/locales/zh-CN/CLAUDE.md +1 -1
  46. package/bundled/locales/zh-CN/README.md +2 -2
  47. package/bundled/locales/zh-CN/SECURITY.md +1 -1
  48. package/bundled/locales/zh-CN/core/adr-standards.md +1 -1
  49. package/bundled/locales/zh-CN/core/agent-communication-protocol.md +7 -0
  50. package/bundled/locales/zh-CN/core/branch-completion.md +7 -0
  51. package/bundled/locales/zh-CN/core/change-batching-standards.md +7 -0
  52. package/bundled/locales/zh-CN/core/execution-history.md +7 -0
  53. package/bundled/locales/zh-CN/core/governance-layer.md +118 -6
  54. package/bundled/locales/zh-CN/core/pipeline-integration-standards.md +7 -0
  55. package/bundled/locales/zh-CN/core/retrospective-standards.md +1 -1
  56. package/bundled/locales/zh-CN/core/tech-debt-standards.md +71 -4
  57. package/bundled/locales/zh-CN/core/turn-completion-integrity.md +190 -0
  58. package/bundled/locales/zh-CN/core/workflow-enforcement.md +7 -0
  59. package/bundled/locales/zh-CN/core/workflow-state-protocol.md +7 -0
  60. package/bundled/locales/zh-CN/docs/CHEATSHEET.md +8 -1
  61. package/bundled/locales/zh-CN/docs/CLI-INIT-OPTIONS.md +29 -68
  62. package/bundled/locales/zh-CN/docs/FEATURE-REFERENCE.md +25 -15
  63. package/bundled/locales/zh-CN/docs/MIGRATION-v6.md +8 -4
  64. package/bundled/locales/zh-CN/docs/USAGE-MODES-COMPARISON.md +1 -2
  65. package/bundled/locales/zh-CN/integrations/google-antigravity/{INSTRUCTIONS.md → AGENTS.md} +1 -1
  66. package/bundled/locales/zh-CN/integrations/google-antigravity/README.md +3 -3
  67. package/bundled/locales/zh-CN/skills/atdd-assistant/SKILL.md +2 -0
  68. package/bundled/locales/zh-CN/skills/bdd-assistant/SKILL.md +2 -0
  69. package/bundled/locales/zh-CN/skills/brainstorm-assistant/SKILL.md +22 -12
  70. package/bundled/locales/zh-CN/skills/brainstorm-assistant/guide.md +12 -9
  71. package/bundled/locales/zh-CN/skills/code-review-assistant/SKILL.md +1 -0
  72. package/bundled/locales/zh-CN/skills/commands/brainstorm.md +17 -13
  73. package/bundled/locales/zh-CN/skills/commands/config.md +0 -1
  74. package/bundled/locales/zh-CN/skills/commands/init.md +1 -2
  75. package/bundled/locales/zh-CN/skills/commit-standards/SKILL.md +2 -0
  76. package/bundled/locales/zh-CN/skills/contract-test-assistant/SKILL.md +1 -0
  77. package/bundled/locales/zh-CN/skills/dev-methodology/SKILL.md +2 -0
  78. package/bundled/locales/zh-CN/skills/observability-assistant/SKILL.md +1 -0
  79. package/bundled/locales/zh-CN/skills/project-structure-guide/SKILL.md +1 -0
  80. package/bundled/locales/zh-CN/skills/release-standards/SKILL.md +3 -0
  81. package/bundled/locales/zh-CN/skills/requirement-assistant/SKILL.md +2 -0
  82. package/bundled/locales/zh-CN/skills/reverse-engineer/SKILL.md +3 -0
  83. package/bundled/locales/zh-CN/skills/runbook-assistant/SKILL.md +1 -0
  84. package/bundled/locales/zh-CN/skills/slo-assistant/SKILL.md +1 -0
  85. package/bundled/locales/zh-CN/skills/tdd-assistant/SKILL.md +2 -0
  86. package/bundled/locales/zh-TW/CHANGELOG.md +74 -3
  87. package/bundled/locales/zh-TW/CLAUDE.md +1 -1
  88. package/bundled/locales/zh-TW/README.md +2 -2
  89. package/bundled/locales/zh-TW/SECURITY.md +1 -1
  90. package/bundled/locales/zh-TW/core/acceptance-criteria-traceability.md +2 -0
  91. package/bundled/locales/zh-TW/core/adr-standards.md +26 -5
  92. package/bundled/locales/zh-TW/core/agent-communication-protocol.md +7 -0
  93. package/bundled/locales/zh-TW/core/branch-completion.md +7 -0
  94. package/bundled/locales/zh-TW/core/change-batching-standards.md +7 -0
  95. package/bundled/locales/zh-TW/core/code-review-checklist.md +2 -0
  96. package/bundled/locales/zh-TW/core/container-image-standards.md +2 -2
  97. package/bundled/locales/zh-TW/core/contract-testing-standards.md +2 -2
  98. package/bundled/locales/zh-TW/core/cross-flow-regression.md +8 -7
  99. package/bundled/locales/zh-TW/core/data-contract.md +2 -2
  100. package/bundled/locales/zh-TW/core/data-migration-testing.md +2 -2
  101. package/bundled/locales/zh-TW/core/data-pipeline.md +2 -2
  102. package/bundled/locales/zh-TW/core/deferred-item-exit.md +251 -0
  103. package/bundled/locales/zh-TW/core/documentation-writing-standards.md +228 -3
  104. package/bundled/locales/zh-TW/core/execution-history.md +7 -0
  105. package/bundled/locales/zh-TW/core/full-coverage-testing.md +15 -2
  106. package/bundled/locales/zh-TW/core/governance-layer.md +118 -5
  107. package/bundled/locales/zh-TW/core/iac-design-principles.md +2 -2
  108. package/bundled/locales/zh-TW/core/incident-response.md +2 -2
  109. package/bundled/locales/zh-TW/core/model-provenance.md +4 -2
  110. package/bundled/locales/zh-TW/core/pii-classification.md +42 -6
  111. package/bundled/locales/zh-TW/core/pipeline-integration-standards.md +7 -0
  112. package/bundled/locales/zh-TW/core/prd-standards.md +4 -2
  113. package/bundled/locales/zh-TW/core/product-metrics-standards.md +4 -2
  114. package/bundled/locales/zh-TW/core/release-readiness-gate.md +2 -2
  115. package/bundled/locales/zh-TW/core/resource-cost-boundary.md +2 -2
  116. package/bundled/locales/zh-TW/core/retrospective-standards.md +5 -3
  117. package/bundled/locales/zh-TW/core/reverse-engineering-standards.md +83 -5
  118. package/bundled/locales/zh-TW/core/runbook.md +2 -2
  119. package/bundled/locales/zh-TW/core/schema-evolution.md +2 -2
  120. package/bundled/locales/zh-TW/core/secret-management-standards.md +2 -2
  121. package/bundled/locales/zh-TW/core/slo-sli.md +2 -2
  122. package/bundled/locales/zh-TW/core/spec-driven-development.md +2 -0
  123. package/bundled/locales/zh-TW/core/tech-debt-standards.md +71 -4
  124. package/bundled/locales/zh-TW/core/turn-completion-integrity.md +190 -0
  125. package/bundled/locales/zh-TW/core/user-journey-testing.md +2 -2
  126. package/bundled/locales/zh-TW/core/user-story-mapping.md +2 -2
  127. package/bundled/locales/zh-TW/core/verification-oracle.md +2 -2
  128. package/bundled/locales/zh-TW/core/workflow-enforcement.md +7 -0
  129. package/bundled/locales/zh-TW/core/workflow-state-protocol.md +7 -0
  130. package/bundled/locales/zh-TW/docs/CHEATSHEET.md +8 -1
  131. package/bundled/locales/zh-TW/docs/CLI-INIT-OPTIONS.md +29 -68
  132. package/bundled/locales/zh-TW/docs/FEATURE-REFERENCE.md +25 -15
  133. package/bundled/locales/zh-TW/docs/MIGRATION-v6.md +8 -4
  134. package/bundled/locales/zh-TW/docs/USAGE-MODES-COMPARISON.md +1 -2
  135. package/bundled/locales/zh-TW/integrations/google-antigravity/{INSTRUCTIONS.md → AGENTS.md} +1 -1
  136. package/bundled/locales/zh-TW/integrations/google-antigravity/README.md +3 -3
  137. package/bundled/locales/zh-TW/skills/adr-assistant/SKILL.md +1 -1
  138. package/bundled/locales/zh-TW/skills/atdd-assistant/SKILL.md +2 -0
  139. package/bundled/locales/zh-TW/skills/bdd-assistant/SKILL.md +2 -0
  140. package/bundled/locales/zh-TW/skills/brainstorm-assistant/SKILL.md +22 -12
  141. package/bundled/locales/zh-TW/skills/brainstorm-assistant/guide.md +12 -9
  142. package/bundled/locales/zh-TW/skills/code-review-assistant/SKILL.md +1 -0
  143. package/bundled/locales/zh-TW/skills/commands/brainstorm.md +17 -13
  144. package/bundled/locales/zh-TW/skills/commands/config.md +0 -1
  145. package/bundled/locales/zh-TW/skills/commands/init.md +1 -2
  146. package/bundled/locales/zh-TW/skills/commit-standards/SKILL.md +2 -0
  147. package/bundled/locales/zh-TW/skills/contract-test-assistant/SKILL.md +2 -1
  148. package/bundled/locales/zh-TW/skills/dev-methodology/SKILL.md +2 -0
  149. package/bundled/locales/zh-TW/skills/dev-workflow-guide/SKILL.md +1 -1
  150. package/bundled/locales/zh-TW/skills/knowledge-graph/guide.md +2 -2
  151. package/bundled/locales/zh-TW/skills/migration-assistant/SKILL.md +1 -1
  152. package/bundled/locales/zh-TW/skills/observability-assistant/SKILL.md +1 -0
  153. package/bundled/locales/zh-TW/skills/project-discovery/SKILL.md +1 -0
  154. package/bundled/locales/zh-TW/skills/project-structure-guide/SKILL.md +1 -0
  155. package/bundled/locales/zh-TW/skills/release-standards/SKILL.md +3 -0
  156. package/bundled/locales/zh-TW/skills/requirement-assistant/SKILL.md +2 -0
  157. package/bundled/locales/zh-TW/skills/reverse-engineer/SKILL.md +3 -0
  158. package/bundled/locales/zh-TW/skills/runbook-assistant/SKILL.md +1 -0
  159. package/bundled/locales/zh-TW/skills/slo-assistant/SKILL.md +1 -0
  160. package/bundled/locales/zh-TW/skills/tdd-assistant/SKILL.md +2 -0
  161. package/bundled/skills/atdd-assistant/SKILL.md +2 -0
  162. package/bundled/skills/bdd-assistant/SKILL.md +2 -0
  163. package/bundled/skills/brainstorm-assistant/SKILL.md +31 -13
  164. package/bundled/skills/brainstorm-assistant/guide.md +9 -6
  165. package/bundled/skills/code-review-assistant/SKILL.md +1 -0
  166. package/bundled/skills/commands/brainstorm.md +12 -9
  167. package/bundled/skills/commands/config.md +0 -1
  168. package/bundled/skills/commands/init.md +2 -3
  169. package/bundled/skills/commit-standards/SKILL.md +2 -0
  170. package/bundled/skills/contract-test-assistant/SKILL.md +1 -0
  171. package/bundled/skills/dev-methodology/SKILL.md +4 -0
  172. package/bundled/skills/observability-assistant/SKILL.md +1 -0
  173. package/bundled/skills/project-discovery/SKILL.md +1 -0
  174. package/bundled/skills/project-structure-guide/SKILL.md +1 -0
  175. package/bundled/skills/release-standards/SKILL.md +3 -0
  176. package/bundled/skills/requirement-assistant/SKILL.md +2 -0
  177. package/bundled/skills/reverse-engineer/SKILL.md +3 -0
  178. package/bundled/skills/runbook-assistant/SKILL.md +1 -0
  179. package/bundled/skills/slo-assistant/SKILL.md +1 -0
  180. package/bundled/skills/tdd-assistant/SKILL.md +2 -0
  181. package/bundled/templates/.ai-context.yaml.template +194 -0
  182. package/bundled/templates/CLAUDE.md.template +145 -0
  183. package/bundled/templates/DESIGN.md +237 -0
  184. package/bundled/templates/SKILL-BRIEF-TEMPLATE.md +57 -0
  185. package/bundled/templates/SKILL-CANDIDATES.md +39 -0
  186. package/bundled/templates/gates/check-error-exit.mjs +309 -0
  187. package/bundled/templates/mcp-config.json +10 -0
  188. package/bundled/templates/methodology-template.yaml +209 -0
  189. package/bundled/templates/migration-template.md +408 -0
  190. package/bundled/templates/requirement-checklist.md +410 -0
  191. package/bundled/templates/requirement-document-template.md +591 -0
  192. package/bundled/templates/requirement-template.md +881 -0
  193. package/bundled/templates/reverse-spec-template.md +409 -0
  194. package/bundled/templates/test-case-template.md +74 -0
  195. package/bundled/templates/test-plan-template.md +74 -0
  196. package/package.json +12 -9
  197. package/src/commands/audit.js +82 -0
  198. package/src/commands/check.js +227 -34
  199. package/src/commands/config.js +19 -19
  200. package/src/commands/init.js +174 -20
  201. package/src/commands/spec.js +2 -2
  202. package/src/commands/update.js +537 -43
  203. package/src/compilers/claude-code-compiler.js +4 -1
  204. package/src/config/ai-agent-paths.js +62 -17
  205. package/src/core/constants.js +42 -11
  206. package/src/core/manifest.js +201 -3
  207. package/src/core/paths.js +2 -2
  208. package/src/i18n/messages.js +42 -29
  209. package/src/installers/hooks-installer.js +167 -75
  210. package/src/installers/integration-installer.js +13 -9
  211. package/src/installers/skills-installer.js +4 -4
  212. package/src/installers/standards-installer.js +3 -3
  213. package/src/prompts/init.js +47 -18
  214. package/src/reconciler/diff-engine.js +57 -2
  215. package/src/reconciler/plan-executor.js +31 -11
  216. package/src/utils/detector.js +21 -1
  217. package/src/utils/effect-boundary.js +1093 -0
  218. package/src/utils/hasher.js +166 -1
  219. package/src/utils/hook-stats.js +1 -1
  220. package/src/utils/integration-generator.js +288 -82
  221. package/src/utils/reference-sync.js +107 -8
  222. package/src/utils/registry.js +57 -0
  223. package/src/utils/spinner.js +31 -0
  224. package/src/utils/yaml-generator.js +51 -9
  225. package/standards-registry.json +32 -9
@@ -1,10 +1,12 @@
1
1
  import chalk from 'chalk';
2
- import ora from 'ora';
2
+ import { createSpinner } from '../utils/spinner.js';
3
3
  import { execSync } from 'child_process';
4
4
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
5
- import { basename, join } from 'path';
5
+ import { join } from 'path';
6
6
  import {
7
- manifestExists as isInitialized
7
+ manifestExists as isInitialized,
8
+ normalizeContentMode,
9
+ SUPPORTED_CONTENT_MODES
8
10
  } from '../core/manifest.js';
9
11
  import { t, detectLanguage } from '../i18n/messages.js';
10
12
  import { detectAll } from '../utils/detector.js';
@@ -53,7 +55,7 @@ export async function initCommand(options) {
53
55
  }
54
56
 
55
57
  // STEP 2: Detect project characteristics
56
- const spinner = ora(msg.detectingProject).start();
58
+ const spinner = createSpinner(msg.detectingProject).start();
57
59
  const detected = detectAll(projectPath);
58
60
  spinner.succeed(msg.analysisComplete);
59
61
 
@@ -121,7 +123,16 @@ export async function initCommand(options) {
121
123
  apply: async () => {
122
124
  // 1. Install Standards
123
125
  const standardsResults = await installStandards(config, projectPath);
124
- config.installedStandards = standardsResults.standards.map(s => basename(s));
126
+ // Paths, not basenames. Everything downstream classifies an option
127
+ // by an `/options/` segment, so reducing to basenames here is not a
128
+ // simplification — it deletes the only signal that distinguishes the
129
+ // two, and `contentLayout: flat` installs option files with no
130
+ // directory to recover it from. The index block consequently said
131
+ // "options 0" on every project for two releases, while the manifest
132
+ // right beside it listed seven. `buildToolIntegrationConfig` (the
133
+ // update path's equivalent) has carried a comment warning against
134
+ // exactly this reduction the whole time; only this call site did it.
135
+ config.installedStandards = standardsResults.standards;
125
136
 
126
137
  // 1.5. Generate release-config.yaml if non-default mode selected
127
138
  if (config.releaseMode && config.releaseMode !== 'ci-cd') {
@@ -156,9 +167,29 @@ export async function initCommand(options) {
156
167
  skillHashes: {},
157
168
  commandHashes: {}
158
169
  };
170
+ // A detected tool that can take skills and has no verified path gets
171
+ // nothing — and must be told so. Silence was the actual defect measured
172
+ // on 2026-09-08: `--mode skills` installed nothing, printed no skills
173
+ // line, and exited 0. An adopter cannot know to go looking.
174
+ for (const tool of config.skillsConfig.skillsPathUnknownTools || []) {
175
+ console.log(chalk.yellow(
176
+ `⚠ ${getAgentDisplayName(tool) || tool}: ` +
177
+ `${msg.skillsPathUnknown || 'no verified skills path — nothing was installed for this tool'}`
178
+ ));
179
+ }
159
180
  await installSkills(config.skillsConfig, projectPath, msg, skillsResults);
160
181
  await installCommands(config.skillsConfig, projectPath, msg, skillsResults);
161
182
 
183
+ // A tool may need something from the adopter before it will read what
184
+ // we just wrote. Driven by an `installNote` on the path table, so a new
185
+ // precondition is a field and not a branch here.
186
+ for (const { agent } of config.skillsConfig.skillsInstallations || []) {
187
+ const note = getAgentConfig(agent)?.installNote;
188
+ if (note) {
189
+ console.log(chalk.yellow(` ⚠ ${getAgentDisplayName(agent) || agent}: ${note}`));
190
+ }
191
+ }
192
+
162
193
  // Combine results
163
194
  installErrors = [
164
195
  ...standardsResults.errors,
@@ -225,7 +256,25 @@ export async function initCommand(options) {
225
256
  const { installHooks } = await import('../installers/hooks-installer.js');
226
257
  const hookResult = installHooks(projectPath);
227
258
  if (hookResult.installed) {
228
- console.log(chalk.green(` ✓ Enforcement hooks installed (${hookResult.scriptsCount} scripts)`));
259
+ console.log(chalk.green(
260
+ ` ✓ Enforcement hooks installed (${hookResult.scriptsCount} scripts, `
261
+ + `${hookResult.events.join(', ')})`));
262
+ } else {
263
+ // Silence here is how three broken installs reported success.
264
+ console.log(chalk.yellow(' ⚠ No enforcement hooks installed — no standard produced a usable hook.'));
265
+ }
266
+ for (const s of hookResult.skipped ?? []) {
267
+ console.log(chalk.yellow(` · skipped ${s.id}: ${s.why}`));
268
+ }
269
+ // turn-completion-integrity R8: a prose-reading hook in a language it does
270
+ // not ship is installed, running, and unable to fire — and that looks
271
+ // exactly like a turn with nothing wrong. Say so at install time; there is
272
+ // no later moment where the adopter could find out.
273
+ for (const l of hookResult.languageLimits ?? []) {
274
+ console.log(chalk.yellow(` · ${l.script} reads prose, and ships:`));
275
+ for (const line of l.languages.split('\n')) {
276
+ console.log(chalk.gray(` ${line}`));
277
+ }
229
278
  }
230
279
  }
231
280
 
@@ -433,16 +482,95 @@ function buildNonInteractiveConfig(options, detected, projectPath) {
433
482
  });
434
483
 
435
484
  // Skills Configuration Logic
436
- const hasSkillsCompatibleTool = aiToolsNormalized.some(t => t === 'claude-code' || t === 'opencode');
437
- const onlySkillsCompatibleTools = aiToolsNormalized.every(t => t === 'claude-code' || t === 'opencode');
438
-
485
+ //
486
+ // 🔴 Which tools can take skills is asked of the path table, never listed here.
487
+ // This used to read `t === 'claude-code' || t === 'opencode'`, and the two
488
+ // consequences were both measured on 2026-09-08 (XSPEC-408 §18.3):
489
+ //
490
+ // - A repo detected as codex ran `uds init --mode skills -y` and got **zero
491
+ // skills, in any directory, with no message saying so.**
492
+ // - When a location was passed explicitly, the install went to `.claude/skills/`
493
+ // for every tool, because the branch below never built `skillsInstallations`
494
+ // and `installSkills()` then fell through to the legacy path, whose target is
495
+ // the hardcoded `getProjectSkillsDir()`. Codex does not read that directory:
496
+ // two arms differing only in path gave 15,235 vs 18,096 input tokens, and only
497
+ // the `.agents/skills` arm made Codex say it could see the skills at all.
498
+ //
499
+ // 🔴 This is the second time in the same shape. `ai-agent-paths.js` records the
500
+ // first: `.codex/skills/` was "a directory UDS invented", skills there were
501
+ // invisible, and a behavioural probe failed while Codex behaved correctly. That
502
+ // fix corrected the path table. This one broke in the code that never asked it.
503
+ // The predicate below is the same one `promptSkillsInstallLocation` already used —
504
+ // the interactive flow was never wrong.
505
+ const skillsCapableTools = aiToolsNormalized.filter(tool => {
506
+ const config = getAgentConfig(tool);
507
+ return Boolean(config?.supportsSkills && config?.skills);
508
+ });
509
+ const hasSkillsCompatibleTool = skillsCapableTools.length > 0;
510
+ // Marketplace is Claude Code's. A tool reaches it either by having one
511
+ // (`supportsMarketplace`) or by reading Claude's directory (`fallbackSkillsPath`).
512
+ // ⚠️ Those fallback claims are NOT all verified — `opencode`'s carries the bare
513
+ // comment "Can read Claude skills" and no evidence. It is preserved here rather
514
+ // than flipped, because changing behaviour on an unverified field in either
515
+ // direction is a guess. Codex's identical claim WAS measured, and falsified, so
516
+ // its field is now null (see `ai-agent-paths.js`) and it drops out here by data.
517
+ // 🔴 The marketplace is all-or-nothing for a repo: it installs into Claude's
518
+ // directory, so it serves a tool only if that tool has a marketplace of its own or
519
+ // declares Claude's directory as its fallback. If ANY detected tool is not served
520
+ // by it, file installs are used instead — every tool then gets its own path, and
521
+ // nobody is left with a successful init and an empty directory.
522
+ const reachesMarketplace = t => {
523
+ const c = getAgentConfig(t);
524
+ return Boolean(c?.supportsMarketplace || c?.fallbackSkillsPath);
525
+ };
526
+ const onlySkillsCompatibleTools =
527
+ hasSkillsCompatibleTool && aiToolsNormalized.every(reachesMarketplace);
528
+
439
529
  let skillsLocationFlag = options.skillsLocation;
440
530
  if (!skillsLocationFlag) {
441
- skillsLocationFlag = (hasSkillsCompatibleTool && onlySkillsCompatibleTools) ? 'marketplace' : 'none';
531
+ skillsLocationFlag = hasSkillsCompatibleTool
532
+ ? (onlySkillsCompatibleTools ? 'marketplace' : 'project')
533
+ : 'none';
442
534
  }
443
535
 
444
- const contentModeFlag = options.contentMode || 'auto';
536
+ // A detected tool that can take skills and is getting none must SAY SO. The worst
537
+ // property of the old default was not the wrong directory, it was the silence:
538
+ // `--mode skills` printed no skills line at all and exited 0.
539
+ const skippedSkillsTools = aiToolsNormalized.filter(tool => {
540
+ const config = getAgentConfig(tool);
541
+ return Boolean(config?.supportsSkills) && !config?.skills;
542
+ });
543
+ // Carried on the config and printed by the caller — this function builds config
544
+ // and has no message bundle in scope. (First version called `msg` here and every
545
+ // init that detected a pathless tool crashed with `ReferenceError: msg is not
546
+ // defined`; the gate's own control arm missed it, because the string it looked for
547
+ // appeared in the stack trace.)
548
+
549
+ // `auto` is resolved later per tool by resolveContentModeForTool, so it is
550
+ // not a content mode and must not go through the normalizer.
551
+ let contentModeFlag = options.contentMode || 'auto';
552
+ if (contentModeFlag !== 'auto') {
553
+ // An unrecognised value is never substituted quietly: a typo that still
554
+ // produces a normal-looking run is how `--content-mode` would lie about
555
+ // what it generated. (XSPEC-357 R7) In 6.x it warns and keeps 6.8.0's
556
+ // result (`index`); it becomes an error in 7.0.0 — see normalizeContentMode.
557
+ const normalized = normalizeContentMode(contentModeFlag);
558
+ if (normalized.unrecognized) {
559
+ console.log(chalk.yellow(
560
+ `⚠ Unknown content mode '${normalized.unrecognized}'; using '${normalized.mode}'. ` +
561
+ `Supported: ${SUPPORTED_CONTENT_MODES.join(', ')}. This will be an error in 7.0.0.`
562
+ ));
563
+ }
564
+ if (normalized.migratedFrom) {
565
+ console.log(chalk.yellow(
566
+ `⚠ --content-mode ${normalized.migratedFrom} is retired; using '${normalized.mode}'. ` +
567
+ 'The two produced identical files, so nothing about your output changes.'
568
+ ));
569
+ }
570
+ contentModeFlag = normalized.mode;
571
+ }
445
572
  let skillsConfig = {};
573
+ let skillsInstallationsForYes = [];
446
574
 
447
575
  if (skillsLocationFlag === 'marketplace') {
448
576
  skillsConfig = {
@@ -472,14 +600,39 @@ function buildNonInteractiveConfig(options, detected, projectPath) {
472
600
  location = 'project';
473
601
  }
474
602
 
475
- skillsConfig = {
476
- installed: true,
477
- location,
478
- needsInstall: skillsLocationFlag === 'project' || skillsLocationFlag === 'user' || (!userSkillsInfo?.installed && !projectSkillsInfo?.installed),
479
- updateTargets: [location],
480
- standardsScope: 'minimal',
481
- contentMode: contentModeFlag
482
- };
603
+ // 🔴 One installation per skills-capable detected tool, each at that tool's own
604
+ // path from the table. Without this the config carries only `updateTargets`,
605
+ // `installSkills()` takes its legacy branch, and every tool's skills land in
606
+ // `.claude/skills/` — see the block above for what that measured.
607
+ skillsInstallationsForYes = skillsCapableTools.map(agent => ({ agent, level: location }));
608
+
609
+ // 🔴 Detected tools, none of which can take skills, is NOT the same as "no tools
610
+ // detected". The first is knowledge — install nothing and say why. The second is
611
+ // ignorance, and there the historical `.claude/skills/` fallback is the least-bad
612
+ // guess and is kept. Without this split, `--skills-location project` in an
613
+ // Antigravity-only repo wrote 55 skills into `.claude/skills/`, a directory
614
+ // nothing in that repo reads. Caught by `check:install-paths`, not by me.
615
+ const knowinglyUnsupported = skillsCapableTools.length === 0 && aiToolsNormalized.length > 0;
616
+
617
+ skillsConfig = knowinglyUnsupported
618
+ ? {
619
+ installed: false,
620
+ location: null,
621
+ needsInstall: false,
622
+ updateTargets: [],
623
+ skillsInstallations: [],
624
+ standardsScope: 'full',
625
+ contentMode: contentModeFlag
626
+ }
627
+ : {
628
+ installed: true,
629
+ location,
630
+ skillsInstallations: skillsInstallationsForYes,
631
+ needsInstall: skillsLocationFlag === 'project' || skillsLocationFlag === 'user' || (!userSkillsInfo?.installed && !projectSkillsInfo?.installed),
632
+ updateTargets: [location],
633
+ standardsScope: 'minimal',
634
+ contentMode: contentModeFlag
635
+ };
483
636
  }
484
637
 
485
638
  // Auto-install commands
@@ -496,6 +649,7 @@ function buildNonInteractiveConfig(options, detected, projectPath) {
496
649
  }
497
650
 
498
651
  skillsConfig.locale = displayLanguageToLocale(displayLanguage);
652
+ skillsConfig.skillsPathUnknownTools = skippedSkillsTools;
499
653
 
500
654
  // AGENTS.md: default to true in --yes mode unless codex/opencode selected or --no-agents-md
501
655
  // When codex/opencode is selected, they already generate AGENTS.md — no need for universal output
@@ -639,7 +793,7 @@ function displaySummary(config, msg, common) {
639
793
  }
640
794
 
641
795
  // 9. Content Mode (STEP 11)
642
- const contentModeLabels = t().contentMode?.labels || { index: 'Standard', full: 'Full', minimal: 'Minimal' };
796
+ const contentModeLabels = t().contentMode?.labels || { index: 'Standard', minimal: 'Minimal' };
643
797
  console.log(chalk.gray(` ${msg.contentModeLabel}: ${contentModeLabels[config.contentMode] || config.contentMode}`));
644
798
 
645
799
  // 10. Methodology (STEP 12, experimental)
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  import chalk from 'chalk';
12
- import ora from 'ora';
12
+ import { createSpinner } from '../utils/spinner.js';
13
13
  import { select, confirm as inquirerConfirm } from '@inquirer/prompts';
14
14
  import { existsSync, readFileSync } from 'node:fs';
15
15
  import { join } from 'node:path';
@@ -48,7 +48,7 @@ export async function specCreateCommand(intent, options = {}) {
48
48
  output: options.output
49
49
  });
50
50
 
51
- const spinner = ora({
51
+ const spinner = createSpinner({
52
52
  text: t('spec.generating', 'Generating micro-spec...'),
53
53
  color: 'cyan'
54
54
  }).start();