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
@@ -100,12 +100,10 @@ export const messages = {
100
100
  question: 'Select content mode:',
101
101
  labels: {
102
102
  index: 'Standard',
103
- full: 'Full Embed',
104
103
  minimal: 'Minimal'
105
104
  },
106
105
  choices: {
107
106
  index: 'Summary + task mapping, AI knows when to read which standard',
108
- full: 'Embed all rules, AI can use immediately but larger file',
109
107
  minimal: 'File references only, best with Skills'
110
108
  },
111
109
  explanations: {
@@ -114,11 +112,6 @@ export const messages = {
114
112
  ' → AI can determine "which standard to read for which task"',
115
113
  ' → Balance between context usage and compliance'
116
114
  ],
117
- full: [
118
- ' → All rules embedded in config file (~10-15 KB)',
119
- ' → AI needs no extra file reads, highest compliance',
120
- ' → Best for short tasks or strict compliance projects'
121
- ],
122
115
  minimal: [
123
116
  ' → Only contains .standards/ file list',
124
117
  ' → AI needs to actively read standard files',
@@ -328,7 +321,6 @@ export const messages = {
328
321
  warning: 'Changing Content Mode will regenerate all AI tool config files',
329
322
  explanations: {
330
323
  index: ' → AI will determine when to read standards based on task mapping',
331
- full: ' → All rules embedded directly, highest AI compliance',
332
324
  minimal: ' → AI must actively read standards, recommend using with Skills'
333
325
  }
334
326
  },
@@ -751,6 +743,9 @@ export const messages = {
751
743
  unchanged: 'unchanged',
752
744
  modified: 'modified',
753
745
  missing: 'missing',
746
+ retired: 'no longer shipped by UDS',
747
+ retiredHeader: '{count} tracked file(s) are gone because UDS stopped shipping them. That is the migration completed, not a fault:',
748
+ retiredHint: 'Run `uds update` to drop their manifest records. `--restore` cannot bring them back — there is no source upstream.',
754
749
  existsNoHash: 'exists, no hash',
755
750
  summary: 'Summary: {unchanged} unchanged, {modified} modified, {missing} missing',
756
751
  // Actions available
@@ -849,6 +844,13 @@ export const messages = {
849
844
  refsInSync: '{path}: references in sync ({count} refs)',
850
845
  noIntegrationRefs: 'No integration files with standard references found.',
851
846
  runSyncRefs: 'Run `uds update --sync-refs` to fix reference issues.',
847
+ runIntegrationsOnly: 'Run `uds update --integrations-only` to regenerate integration files.',
848
+ danglingRefs: 'references files that are not on disk:',
849
+ brokenMentions: 'mentions paths that do not exist in this project:',
850
+ brokenMentionsFix: 'These are usually outside the UDS block, left by an older install. UDS does not rewrite text it did not write — correct them by hand or delete the line.',
851
+ danglingRefsFix: 'Run `uds update --integrations-only` to regenerate them.',
852
+ commandsUntracked: '{count} installed command file(s) are covered by no hash — integrity is not checked for them',
853
+ commandsUntrackedFix: 'Run `uds update --commands` to record them again.',
852
854
  // CLI update
853
855
  checkingCliUpdates: 'Checking for CLI updates...',
854
856
  couldNotCheckUpdates: 'ℹ Could not check for CLI updates (offline mode)',
@@ -934,7 +936,6 @@ export const messages = {
934
936
  standardsScopeLean: 'Lean (Skills handle the rest)',
935
937
  standardsScopeComplete: 'Complete',
936
938
  contentModeLabel: 'Content Mode',
937
- contentModeFull: 'Full Embed',
938
939
  contentModeIndex: 'Standard (recommended)',
939
940
  contentModeMinimal: 'Minimal (core only)',
940
941
  displayLanguageLabel: 'Display Language',
@@ -969,7 +970,10 @@ export const messages = {
969
970
  generatingAgentsMd: 'Generating AGENTS.md (universal summary)...',
970
971
  generatedAgentsMd: 'Generated AGENTS.md (universal summary)',
971
972
  couldNotGenerateAgentsMd: 'Could not generate AGENTS.md',
972
- installingSkills: 'Installing Claude Code Skills...',
973
+ installingSkills: 'Installing Skills...',
974
+ // Named per detected tool, never per one tool: the install now goes to each
975
+ // tool's own path (XSPEC-408 §18.3), so a Claude-only label would be a lie.
976
+ skillsPathUnknown: 'no verified skills path for this tool — nothing was installed for it',
973
977
  installedSkills: 'Installed {count} Skills to {locations}',
974
978
  installedSkillsWithErrors: 'Installed {count} Skills with {errors} errors',
975
979
  // P1-CLI-1: locale fallback summary (printed after install when some
@@ -1026,6 +1030,7 @@ export const messages = {
1026
1030
  syncingIntegrations: 'Syncing integration files...',
1027
1031
  syncedIntegrations: 'Synced {count} integration files',
1028
1032
  prunedOrphanedBlockHashes: 'Pruned {count} orphaned integration hash(es): {files}',
1033
+ droppedRetiredHashes: 'Dropped {count} manifest record(s) for files UDS no longer ships and that are already gone:',
1029
1034
  // Success
1030
1035
  updateSuccess: '✓ Standards updated successfully!',
1031
1036
  versionUpdated: 'Version: {current} → {latest}',
@@ -1053,6 +1058,7 @@ export const messages = {
1053
1058
  // Sync refs
1054
1059
  syncingRefs: 'Syncing integration references...',
1055
1060
  noIntegrationConfigs: '⚠ No integration configurations found in manifest.',
1061
+ integrationConfigsBackfilled: 'Rebuilt integration config for {count} file(s) from the manifest.',
1056
1062
  integrationConfigsRequired: 'Integration configs are required for reference sync.',
1057
1063
  thisHappensWhen: 'This happens when:',
1058
1064
  oldVersion: '- The project was initialized with an older version of UDS',
@@ -1334,12 +1340,10 @@ export const messages = {
1334
1340
  question: '選擇內容模式:',
1335
1341
  labels: {
1336
1342
  index: '標準',
1337
- full: '完整嵌入',
1338
1343
  minimal: '最小化'
1339
1344
  },
1340
1345
  choices: {
1341
1346
  index: '摘要 + 任務對照表,AI 知道何時讀哪個規範',
1342
- full: '完整嵌入所有規則,AI 立即可用但檔案較大',
1343
1347
  minimal: '僅檔案參考,適合搭配 Skills 使用'
1344
1348
  },
1345
1349
  explanations: {
@@ -1348,11 +1352,6 @@ export const messages = {
1348
1352
  ' → AI 能判斷「做什麼任務時要讀哪個規範」',
1349
1353
  ' → 平衡 Context 使用量和合規程度'
1350
1354
  ],
1351
- full: [
1352
- ' → 所有規則直接嵌入設定檔(檔案約 10-15 KB)',
1353
- ' → AI 無需額外讀檔,合規率最高',
1354
- ' → 適合短期任務或需要嚴格遵循的專案'
1355
- ],
1356
1355
  minimal: [
1357
1356
  ' → 僅包含 .standards/ 檔案清單',
1358
1357
  ' → AI 需要主動讀取規範檔案',
@@ -1562,7 +1561,6 @@ export const messages = {
1562
1561
  warning: '變更 Content Mode 將重新生成所有 AI 工具設定檔',
1563
1562
  explanations: {
1564
1563
  index: ' → AI 會根據任務對照表判斷何時讀取規範',
1565
- full: ' → 所有規則直接嵌入,AI 合規率最高',
1566
1564
  minimal: ' → AI 需主動讀取規範,建議搭配 Skills'
1567
1565
  }
1568
1566
  },
@@ -1985,6 +1983,9 @@ export const messages = {
1985
1983
  unchanged: '未變更',
1986
1984
  modified: '已修改',
1987
1985
  missing: '遺失',
1986
+ retired: 'UDS 已不再出貨',
1987
+ retiredHeader: '有 {count} 個被追蹤的檔案不見了,原因是 UDS 已不再出貨。那是遷移完成的樣子,不是故障:',
1988
+ retiredHint: '執行 `uds update` 清掉它們在 manifest 的紀錄。`--restore` 救不回來——上游已經沒有來源。',
1988
1989
  existsNoHash: '存在,無 hash',
1989
1990
  summary: '摘要:{unchanged} 未變更,{modified} 已修改,{missing} 遺失',
1990
1991
  // Actions available
@@ -2083,6 +2084,13 @@ export const messages = {
2083
2084
  refsInSync: '{path}:參考已同步({count} 個參考)',
2084
2085
  noIntegrationRefs: '找不到有標準參考的整合檔案。',
2085
2086
  runSyncRefs: '執行 `uds update --sync-refs` 修復參考問題。',
2087
+ runIntegrationsOnly: '執行 `uds update --integrations-only` 重新產生整合檔案。',
2088
+ danglingRefs: '引用了磁碟上不存在的檔案:',
2089
+ brokenMentions: '提到了本專案裡不存在的路徑:',
2090
+ brokenMentionsFix: '這些通常在 UDS 區塊之外,是舊版安裝留下的。UDS 不會改寫不是它寫的文字——請手動更正或刪掉那一行。',
2091
+ danglingRefsFix: '執行 `uds update --integrations-only` 重新產生。',
2092
+ commandsUntracked: '{count} 個已安裝的斜線命令沒有任何雜湊涵蓋——這些檔案的完整性沒有被檢查',
2093
+ commandsUntrackedFix: '執行 `uds update --commands` 重新記錄。',
2086
2094
  // CLI update
2087
2095
  checkingCliUpdates: '正在檢查 CLI 更新...',
2088
2096
  couldNotCheckUpdates: 'ℹ 無法檢查 CLI 更新(離線模式)',
@@ -2168,7 +2176,6 @@ export const messages = {
2168
2176
  standardsScopeLean: '精簡(Skills 處理其餘)',
2169
2177
  standardsScopeComplete: '完整',
2170
2178
  contentModeLabel: '內容模式',
2171
- contentModeFull: '完整嵌入',
2172
2179
  contentModeIndex: '標準(推薦)',
2173
2180
  contentModeMinimal: '最小(僅核心)',
2174
2181
  displayLanguageLabel: '顯示語言',
@@ -2203,7 +2210,8 @@ export const messages = {
2203
2210
  generatingAgentsMd: '產生 AGENTS.md(通用摘要)中...',
2204
2211
  generatedAgentsMd: '已產生 AGENTS.md(通用摘要)',
2205
2212
  couldNotGenerateAgentsMd: '無法產生 AGENTS.md',
2206
- installingSkills: '安裝 Claude Code Skills 中...',
2213
+ installingSkills: '安裝 Skills 中...',
2214
+ skillsPathUnknown: '沒有查證過的 skills 路徑,這個工具沒有安裝任何東西',
2207
2215
  installedSkills: '已安裝 {count} 個 Skills 到 {locations}',
2208
2216
  installedSkillsWithErrors: '已安裝 {count} 個 Skills,有 {errors} 個錯誤',
2209
2217
  // P1-CLI-1:locale fallback 摘要(安裝結束後顯示,列出沒有對應語系變體而退回英文來源的 skill)
@@ -2259,6 +2267,7 @@ export const messages = {
2259
2267
  syncingIntegrations: '同步整合檔案中...',
2260
2268
  syncedIntegrations: '已同步 {count} 個整合檔案',
2261
2269
  prunedOrphanedBlockHashes: '已清除 {count} 個孤兒整合雜湊:{files}',
2270
+ droppedRetiredHashes: '已清掉 {count} 筆 manifest 紀錄——這些檔案 UDS 已不再出貨,而且本來就已經不在了:',
2262
2271
  // Success
2263
2272
  updateSuccess: '✓ 標準更新成功!',
2264
2273
  versionUpdated: '版本:{current} → {latest}',
@@ -2286,6 +2295,7 @@ export const messages = {
2286
2295
  // Sync refs
2287
2296
  syncingRefs: '同步整合參考中...',
2288
2297
  noIntegrationConfigs: '⚠ manifest 中找不到整合設定。',
2298
+ integrationConfigsBackfilled: '已從 manifest 重建 {count} 個整合檔的設定。',
2289
2299
  integrationConfigsRequired: '參考同步需要整合設定。',
2290
2300
  thisHappensWhen: '這會發生在:',
2291
2301
  oldVersion: '- 專案使用較舊版本的 UDS 初始化',
@@ -2567,12 +2577,10 @@ export const messages = {
2567
2577
  question: '选择内容模式:',
2568
2578
  labels: {
2569
2579
  index: '标准',
2570
- full: '完整嵌入',
2571
2580
  minimal: '最小化'
2572
2581
  },
2573
2582
  choices: {
2574
2583
  index: '摘要 + 任务对照表,AI 知道何时读哪个规范',
2575
- full: '完整嵌入所有规则,AI 立即可用但文件较大',
2576
2584
  minimal: '仅文件参考,适合搭配 Skills 使用'
2577
2585
  },
2578
2586
  explanations: {
@@ -2581,11 +2589,6 @@ export const messages = {
2581
2589
  ' → AI 能判断"做什么任务时要读哪个规范"',
2582
2590
  ' → 平衡 Context 使用量和合规程度'
2583
2591
  ],
2584
- full: [
2585
- ' → 所有规则直接嵌入配置文件(文件约 10-15 KB)',
2586
- ' → AI 无需额外读档,合规率最高',
2587
- ' → 适合短期任务或需要严格遵循的项目'
2588
- ],
2589
2592
  minimal: [
2590
2593
  ' → 仅包含 .standards/ 文件清单',
2591
2594
  ' → AI 需要主动读取规范文件',
@@ -2795,7 +2798,6 @@ export const messages = {
2795
2798
  warning: '变更 Content Mode 将重新生成所有 AI 工具配置文件',
2796
2799
  explanations: {
2797
2800
  index: ' → AI 会根据任务对照表判断何时读取规范',
2798
- full: ' → 所有规则直接嵌入,AI 合规率最高',
2799
2801
  minimal: ' → AI 需主动读取规范,建议搭配 Skills'
2800
2802
  }
2801
2803
  },
@@ -3144,7 +3146,6 @@ export const messages = {
3144
3146
  standardsScopeLean: '精简(Skills 处理其余)',
3145
3147
  standardsScopeComplete: '完整',
3146
3148
  contentModeLabel: '内容模式',
3147
- contentModeFull: '完整嵌入',
3148
3149
  contentModeIndex: '标准(推荐)',
3149
3150
  contentModeMinimal: '最小(仅核心)',
3150
3151
  displayLanguageLabel: '显示语言',
@@ -3234,6 +3235,9 @@ export const messages = {
3234
3235
  unchanged: '未更改',
3235
3236
  modified: '已修改',
3236
3237
  missing: '缺失',
3238
+ retired: 'UDS 已不再发布',
3239
+ retiredHeader: '有 {count} 个被追踪的文件不见了,原因是 UDS 已不再发布。那是迁移完成的样子,不是故障:',
3240
+ retiredHint: '执行 `uds update` 清掉它们在 manifest 的记录。`--restore` 救不回来——上游已经没有来源。',
3237
3241
  existsNoHash: '存在,无哈希',
3238
3242
  summary: '摘要:{unchanged} 未更改,{modified} 已修改,{missing} 缺失',
3239
3243
  // Actions available
@@ -3332,6 +3336,13 @@ export const messages = {
3332
3336
  refsInSync: '{path}:引用已同步({count} 个引用)',
3333
3337
  noIntegrationRefs: '未找到包含标准引用的集成文件。',
3334
3338
  runSyncRefs: '执行 `uds update --sync-refs` 修复引用问题。',
3339
+ runIntegrationsOnly: '执行 `uds update --integrations-only` 重新生成集成文件。',
3340
+ danglingRefs: '引用了磁盘上不存在的文件:',
3341
+ brokenMentions: '提到了本项目里不存在的路径:',
3342
+ brokenMentionsFix: '这些通常在 UDS 区块之外,是旧版安装留下的。UDS 不会改写不是它写的文字——请手动更正或删掉那一行。',
3343
+ danglingRefsFix: '执行 `uds update --integrations-only` 重新生成。',
3344
+ commandsUntracked: '{count} 个已安装的斜杠命令没有任何哈希覆盖——这些文件的完整性没有被检查',
3345
+ commandsUntrackedFix: '执行 `uds update --commands` 重新记录。',
3335
3346
  // CLI update
3336
3347
  checkingCliUpdates: '检查 CLI 更新...',
3337
3348
  couldNotCheckUpdates: 'ℹ 无法检查 CLI 更新(离线模式)',
@@ -3421,6 +3432,7 @@ export const messages = {
3421
3432
  syncingIntegrations: '正在同步集成文件...',
3422
3433
  syncedIntegrations: '已同步 {count} 个集成文件',
3423
3434
  prunedOrphanedBlockHashes: '已清除 {count} 个孤儿集成哈希:{files}',
3435
+ droppedRetiredHashes: '已清掉 {count} 笔 manifest 记录——这些文件 UDS 已不再发布,而且本来就已经不在了:',
3424
3436
  // Success
3425
3437
  updateSuccess: '✓ 标准更新成功!',
3426
3438
  versionUpdated: '版本:{current} → {latest}',
@@ -3448,6 +3460,7 @@ export const messages = {
3448
3460
  // Sync refs
3449
3461
  syncingRefs: '正在同步集成引用...',
3450
3462
  noIntegrationConfigs: '⚠ manifest 中未找到集成配置。',
3463
+ integrationConfigsBackfilled: '已从 manifest 重建 {count} 个集成文件的配置。',
3451
3464
  integrationConfigsRequired: '引用同步需要集成配置。',
3452
3465
  thisHappensWhen: '发生这种情况时:',
3453
3466
  oldVersion: '- 项目使用旧版 UDS 初始化',
@@ -1,105 +1,197 @@
1
1
  /**
2
2
  * UDS Hook Installer
3
3
  *
4
- * Copies hook scripts and generates/merges .claude/settings.json
5
- * with hook configurations.
4
+ * Copies hook scripts and merges .claude/settings.json with hook configurations
5
+ * derived from the `enforcement:` blocks of the shipped standards.
6
6
  *
7
7
  * Key constraints:
8
8
  * - MUST merge, never overwrite existing settings.json
9
9
  * - MUST be idempotent (no duplicate hooks on re-install)
10
+ * - MUST emit the hook handler shape Claude Code actually executes
11
+ *
12
+ * 🔴 Three defects fixed here on 2026-09-08, each of which failed silently and
13
+ * all three of which were present at once:
14
+ *
15
+ * 1. Hook entries were written as bare strings (`hooks: ['node x.js']`).
16
+ * Measured with a two-arm run — a bare-string entry and an object entry
17
+ * side by side in the same event of the same session: the object ran, the
18
+ * bare string did not. Claude Code dispatches on `type`, and an entry
19
+ * without one is skipped. settings.json stays valid JSON, the install
20
+ * reports success, and nothing ever runs.
21
+ * 2. The hook scripts were resolved from `<repo>/scripts/hooks`, which is
22
+ * outside the published package (`npm pack` listed 1 file matching
23
+ * "hooks": this installer). Adopters installing from npm copied zero
24
+ * scripts and still got `installed: true`.
25
+ * 3. The event/script list was hardcoded here, so a standard declaring an
26
+ * `enforcement:` block got no hook unless someone also remembered to edit
27
+ * this file. It is now derived by walking the standards.
10
28
  *
11
29
  * @module installers/hooks-installer
12
30
  * @see docs/specs/SPEC-HOOKS-001-core-standard-hooks.md (REQ-4)
31
+ * @see core/turn-completion-integrity.md
13
32
  */
14
33
 
15
- import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'fs';
16
- import { join, dirname } from 'path';
34
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync, readdirSync } from 'fs';
35
+ import { join, dirname, basename } from 'path';
17
36
  import { fileURLToPath } from 'url';
37
+ import { execFileSync } from 'child_process';
38
+ import { load as parseYaml } from 'js-yaml';
18
39
 
19
40
  const __dirname = dirname(fileURLToPath(import.meta.url));
20
41
 
21
- const HOOK_CONFIGS = {
22
- PreToolUse: [
23
- {
24
- matcher: 'Bash',
25
- hooks: ['node scripts/hooks/check-dangerous-cmd.js'],
26
- },
27
- ],
28
- PostToolUse: [
29
- {
30
- matcher: 'Bash',
31
- hooks: ['node scripts/hooks/check-logging-standard.js'],
32
- },
33
- ],
34
- UserPromptSubmit: [
35
- {
36
- matcher: '',
37
- hooks: ['node scripts/hooks/validate-commit-msg.js'],
38
- },
39
- ],
40
- };
41
-
42
- const HOOK_SCRIPTS = [
43
- 'validate-commit-msg.js',
44
- 'check-dangerous-cmd.js',
45
- 'check-logging-standard.js',
46
- ];
42
+ /** Prefer the bundled copy (present in the npm package), fall back to the repo. */
43
+ function resolveDir(bundledRel, repoRel) {
44
+ const bundled = join(__dirname, '..', '..', 'bundled', ...bundledRel);
45
+ if (existsSync(bundled)) return bundled;
46
+ const repo = join(__dirname, '..', '..', '..', ...repoRel);
47
+ return existsSync(repo) ? repo : null;
48
+ }
49
+
50
+ export const standardsSourceDir = () => resolveDir(['ai', 'standards'], ['ai', 'standards']);
51
+ export const hooksSourceDir = () => resolveDir(['hooks'], ['scripts', 'hooks']);
52
+
53
+ /**
54
+ * Claude Code's matcher is a string. Some standards declare it as an object
55
+ * (`matcher: { tool: Bash }`), which would be written into settings.json
56
+ * verbatim and never match anything.
57
+ */
58
+ function normalizeMatcher(matcher) {
59
+ if (typeof matcher === 'string') return matcher;
60
+ if (matcher && typeof matcher === 'object' && typeof matcher.tool === 'string') return matcher.tool;
61
+ return '';
62
+ }
63
+
64
+ /**
65
+ * Walk the shipped standards and build the hook configuration from every
66
+ * complete `enforcement:` block.
67
+ *
68
+ * @param {string|null} stdDir - directory of *.ai.yaml standards
69
+ * @param {string|null} hookDir - directory the hook scripts live in
70
+ * @returns {{ configs: Object, scripts: string[], skipped: Array<{id: string, why: string}> }}
71
+ */
72
+ export function collectHookConfigs(stdDir, hookDir) {
73
+ const configs = {};
74
+ const scripts = [];
75
+ const skipped = [];
76
+ if (!stdDir) return { configs, scripts, skipped: [{ id: '*', why: 'standards directory not found' }] };
77
+
78
+ for (const file of readdirSync(stdDir).filter((f) => f.endsWith('.ai.yaml')).sort()) {
79
+ let std;
80
+ try {
81
+ std = parseYaml(readFileSync(join(stdDir, file), 'utf-8'));
82
+ } catch {
83
+ skipped.push({ id: file, why: 'unparseable YAML' });
84
+ continue;
85
+ }
86
+ const e = std && std.enforcement;
87
+ if (!e) continue;
88
+
89
+ const id = (std && std.id) || file;
90
+ if (typeof e.trigger !== 'string' || !e.trigger || typeof e.hook_script !== 'string' || !e.hook_script) {
91
+ // A block missing either field used to compile to hooks["undefined"]:
92
+ // [{ hooks: ["node undefined"] }] with no error at any layer.
93
+ skipped.push({ id, why: 'enforcement block missing trigger or hook_script' });
94
+ continue;
95
+ }
96
+
97
+ const rel = e.hook_script.replace(/^scripts\/hooks\//, '');
98
+ if (hookDir && !existsSync(join(hookDir, rel))) {
99
+ skipped.push({ id, why: `hook script not found: ${e.hook_script}` });
100
+ continue;
101
+ }
102
+
103
+ (configs[e.trigger] ||= []).push({
104
+ matcher: normalizeMatcher(e.matcher),
105
+ hooks: [{ type: 'command', command: `node scripts/hooks/${rel}` }],
106
+ });
107
+ scripts.push(rel);
108
+ }
109
+ return { configs, scripts, skipped };
110
+ }
111
+
112
+ /** The command string an entry runs, whatever shape it is stored in. */
113
+ function commandOf(entry) {
114
+ const h = entry && entry.hooks && entry.hooks[0];
115
+ if (typeof h === 'string') return h;
116
+ return h && typeof h.command === 'string' ? h.command : undefined;
117
+ }
47
118
 
48
119
  /**
49
- * Deep merge hook arrays, deduplicating by hook script path.
50
- * @param {Array} existing - Existing hook entries
51
- * @param {Array} incoming - New hook entries to merge
52
- * @returns {Array} Merged array without duplicates
120
+ * Merge hook arrays, deduplicating by (command, matcher).
121
+ * Existing entries are never rewritten — an adopter may have edited them.
53
122
  */
54
- function mergeHookArray(existing, incoming) {
123
+ export function mergeHookArray(existing, incoming) {
55
124
  const result = [...existing];
56
125
  for (const entry of incoming) {
57
- const hookScript = entry.hooks?.[0];
58
- const isDuplicate = result.some(
59
- (e) => e.hooks?.[0] === hookScript && e.matcher === entry.matcher
60
- );
61
- if (!isDuplicate) {
62
- result.push(entry);
63
- }
126
+ const cmd = commandOf(entry);
127
+ const dup = result.some((e) => commandOf(e) === cmd && e.matcher === entry.matcher);
128
+ if (!dup) result.push(entry);
64
129
  }
65
130
  return result;
66
131
  }
67
132
 
68
133
  /**
69
134
  * Install UDS hooks into a target project.
70
- * - Copies hook scripts to scripts/hooks/
71
- * - Creates or merges .claude/settings.json with hook configs
72
135
  *
73
136
  * @param {string} projectPath - Target project root path
74
- * @returns {{ installed: boolean, scriptsCount: number, settingsPath: string }}
137
+ * @returns {{ installed: boolean, scriptsCount: number, settingsPath: string, events: string[], skipped: Array }}
138
+ */
139
+ /**
140
+ * Which installed hooks only work in some languages, asked of the hooks themselves.
141
+ *
142
+ * turn-completion-integrity R8 says an unsupported language must be declared,
143
+ * and the hook already answers `--languages`. Restating that list here would
144
+ * make a second hand-maintained copy of it, and the copy would drift — quietly,
145
+ * because both halves keep looking like valid data.
146
+ *
147
+ * 🔴 Why it matters at all: a prose-reading hook in a language it does not ship
148
+ * is installed, running, and structurally unable to fire. Its output is
149
+ * byte-identical to a turn with nothing wrong. Without this line the adopter
150
+ * has no way to tell those apart, ever.
151
+ *
152
+ * A hook with no such flag simply produces nothing here; failure is not an
153
+ * error, because "cannot introspect" must not block an install.
75
154
  */
155
+ function probeLanguageLimits(hooksDir, scripts) {
156
+ const out = [];
157
+ for (const rel of new Set(scripts)) {
158
+ const abs = join(hooksDir, basename(rel));
159
+ if (!existsSync(abs)) continue;
160
+ try {
161
+ const text = execFileSync(process.execPath, [abs, '--languages'], {
162
+ encoding: 'utf-8',
163
+ timeout: 5000,
164
+ stdio: ['ignore', 'pipe', 'ignore'],
165
+ }).trim();
166
+ if (text) out.push({ script: basename(rel), languages: text });
167
+ } catch {
168
+ // no --languages, or it refused: nothing to declare.
169
+ }
170
+ }
171
+ return out;
172
+ }
173
+
76
174
  export function installHooks(projectPath) {
77
175
  const claudeDir = join(projectPath, '.claude');
78
176
  const settingsPath = join(claudeDir, 'settings.json');
177
+ const hooksDir = join(projectPath, 'scripts', 'hooks');
79
178
 
80
- // Ensure .claude/ directory exists
81
- if (!existsSync(claudeDir)) {
82
- mkdirSync(claudeDir, { recursive: true });
83
- }
179
+ const stdDir = standardsSourceDir();
180
+ const hookDir = hooksSourceDir();
181
+ const { configs, scripts, skipped } = collectHookConfigs(stdDir, hookDir);
182
+ const events = Object.keys(configs);
84
183
 
85
- // Copy hook scripts
86
- const hooksDir = join(projectPath, 'scripts', 'hooks');
87
- if (!existsSync(hooksDir)) {
88
- mkdirSync(hooksDir, { recursive: true });
184
+ if (events.length === 0) {
185
+ // Reporting success here is what let three separate breakages ship.
186
+ return { installed: false, scriptsCount: 0, settingsPath, events, skipped };
89
187
  }
90
188
 
91
- const sourceHooksDir = join(__dirname, '..', '..', '..', 'scripts', 'hooks');
92
- let scriptsCount = 0;
93
- for (const script of HOOK_SCRIPTS) {
94
- const src = join(sourceHooksDir, script);
95
- const dest = join(hooksDir, script);
96
- if (existsSync(src)) {
97
- copyFileSync(src, dest);
98
- scriptsCount++;
99
- }
100
- }
189
+ if (!existsSync(claudeDir)) mkdirSync(claudeDir, { recursive: true });
190
+ if (!existsSync(hooksDir)) mkdirSync(hooksDir, { recursive: true });
191
+
192
+ // Recursive: a hook may ship a directory beside it (locale packs, fixtures).
193
+ cpSync(hookDir, hooksDir, { recursive: true });
101
194
 
102
- // Read or create settings.json
103
195
  let settings = {};
104
196
  if (existsSync(settingsPath)) {
105
197
  try {
@@ -108,21 +200,21 @@ export function installHooks(projectPath) {
108
200
  settings = {};
109
201
  }
110
202
  }
203
+ if (!settings.hooks) settings.hooks = {};
111
204
 
112
- // Merge hooks
113
- if (!settings.hooks) {
114
- settings.hooks = {};
115
- }
116
-
117
- for (const [event, entries] of Object.entries(HOOK_CONFIGS)) {
118
- if (!settings.hooks[event]) {
119
- settings.hooks[event] = [];
120
- }
205
+ for (const [event, entries] of Object.entries(configs)) {
206
+ if (!settings.hooks[event]) settings.hooks[event] = [];
121
207
  settings.hooks[event] = mergeHookArray(settings.hooks[event], entries);
122
208
  }
123
209
 
124
- // Write settings.json
125
210
  writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
126
211
 
127
- return { installed: true, scriptsCount, settingsPath };
212
+ return {
213
+ installed: true,
214
+ scriptsCount: new Set(scripts).size,
215
+ settingsPath,
216
+ events,
217
+ skipped,
218
+ languageLimits: probeLanguageLimits(hooksDir, scripts),
219
+ };
128
220
  }
@@ -1,4 +1,4 @@
1
- import ora from 'ora';
1
+ import { createSpinner } from '../utils/spinner.js';
2
2
  import { copyIntegration } from '../utils/copier.js';
3
3
  import {
4
4
  writeIntegrationFile,
@@ -32,11 +32,15 @@ export const INTEGRATION_MAPPINGS = {
32
32
  target: '.github/copilot-instructions.md'
33
33
  },
34
34
  antigravity: {
35
- source: 'integrations/google-antigravity/INSTRUCTIONS.md',
36
- target: 'INSTRUCTIONS.md'
35
+ source: 'integrations/google-antigravity/AGENTS.md',
36
+ target: '.agents/AGENTS.md'
37
37
  },
38
38
  codex: {
39
- source: 'integrations/openai-codex/AGENTS.md',
39
+ // 🔴 Was 'integrations/openai-codex/AGENTS.md'; that directory does not exist.
40
+ // This map is only reached when generation fails, so a broken entry here is a
41
+ // fallback that fails exactly when it is needed. Found by walking the map and
42
+ // stat-ing every source — nothing was checking that these paths resolve.
43
+ source: 'integrations/codex/AGENTS.md',
40
44
  target: 'AGENTS.md'
41
45
  },
42
46
  'gemini-cli': {
@@ -56,7 +60,7 @@ export const INTEGRATION_MAPPINGS = {
56
60
  * @param {Array<string>} config.integrations - List of AI tool names (e.g., ['cursor', 'windsurf'])
57
61
  * @param {Object} config.integrationConfigs - Tool-specific configurations
58
62
  * @param {Array<string>} config.installedStandards - List of installed standard file names
59
- * @param {string} config.contentMode - Content mode ('minimal', 'index', 'full')
63
+ * @param {string} config.contentMode - Content mode ('minimal', 'index'; 'full' retired — XSPEC-357 R7)
60
64
  * @param {number} config.level - Adoption level (1-3)
61
65
  * @param {string} config.commonLanguage - Language setting ('en', 'zh-tw', 'zh-cn', 'bilingual')
62
66
  * @param {string} config.outputLanguage - Output language preference
@@ -95,7 +99,7 @@ export async function installIntegrations(config, projectPath) {
95
99
  }
96
100
 
97
101
  // Start installation spinner
98
- const intSpinner = ora(msg.generatingIntegrations).start();
102
+ const intSpinner = createSpinner(msg.generatingIntegrations).start();
99
103
 
100
104
  // Track generated files to handle AGENTS.md sharing (codex + opencode)
101
105
  const generatedFiles = new Set();
@@ -191,7 +195,7 @@ export async function installIntegrations(config, projectPath) {
191
195
  * @param {Object} config - Claude Code configuration
192
196
  * @param {Array<string>} config.aiTools - List of selected AI tools
193
197
  * @param {Array<string>} config.installedStandards - List of installed standard file names
194
- * @param {string} config.contentMode - Content mode ('minimal', 'index', 'full')
198
+ * @param {string} config.contentMode - Content mode ('minimal', 'index'; 'full' retired — XSPEC-357 R7)
195
199
  * @param {number} config.level - Adoption level (1-3)
196
200
  * @param {string} config.commonLanguage - Language setting ('en', 'zh-tw', 'zh-cn', 'bilingual')
197
201
  * @param {string} config.outputLanguage - Output language preference
@@ -220,7 +224,7 @@ export async function generateClaudeMd(config, projectPath) {
220
224
  return { path: null, error: null };
221
225
  }
222
226
 
223
- const claudeSpinner = ora(msg.generatingClaudeMd).start();
227
+ const claudeSpinner = createSpinner(msg.generatingClaudeMd).start();
224
228
 
225
229
  // Derive categories from installedStandards to avoid referencing non-installed standards
226
230
  const categories = installedStandards.length > 0
@@ -281,7 +285,7 @@ export async function generateUniversalAgentsMd(config, integrationResults, proj
281
285
  }
282
286
 
283
287
  const msg = t().commands.init;
284
- const spinner = ora(msg.generatingAgentsMd || 'Generating AGENTS.md...').start();
288
+ const spinner = createSpinner(msg.generatingAgentsMd || 'Generating AGENTS.md...').start();
285
289
 
286
290
  const outputLanguage = config.outputLanguage || config.commitLanguage ||
287
291
  config.standardOptions?.output_language || config.standardOptions?.commit_language ||
@@ -13,7 +13,7 @@
13
13
  * @version 1.0.0
14
14
  */
15
15
 
16
- import ora from 'ora';
16
+ import { createSpinner } from '../utils/spinner.js';
17
17
  import chalk from 'chalk';
18
18
  import {
19
19
  installSkillsToMultipleAgents,
@@ -115,7 +115,7 @@ function getSkillFiles() {
115
115
  export async function installSkills(skillsConfig, projectPath, messages, results) {
116
116
  // Modern unified multi-agent installation
117
117
  if (skillsConfig.needsInstall && skillsConfig.skillsInstallations?.length > 0) {
118
- const skillSpinner = ora(messages.installingSkills).start();
118
+ const skillSpinner = createSpinner(messages.installingSkills).start();
119
119
 
120
120
  // Use new unified installer for multi-agent support
121
121
  const installResult = await installSkillsToMultipleAgents(
@@ -186,7 +186,7 @@ export async function installSkills(skillsConfig, projectPath, messages, results
186
186
  * @returns {Promise<void>}
187
187
  */
188
188
  async function installSkillsLegacy(skillsConfig, projectPath, messages, results) {
189
- const skillSpinner = ora(messages.installingSkills).start();
189
+ const skillSpinner = createSpinner(messages.installingSkills).start();
190
190
 
191
191
  const skillFiles = getSkillFiles();
192
192
  let successCount = 0;
@@ -255,7 +255,7 @@ export async function installCommands(skillsConfig, projectPath, messages, resul
255
255
  return;
256
256
  }
257
257
 
258
- const cmdSpinner = ora(messages.installingCommands || 'Installing slash commands...').start();
258
+ const cmdSpinner = createSpinner(messages.installingCommands || 'Installing slash commands...').start();
259
259
 
260
260
  const cmdResult = await installCommandsToMultipleAgents(
261
261
  skillsConfig.commandsInstallations,