@polymorphism-tech/morph-spec 9.0.0 → 9.1.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 (304) hide show
  1. package/CLAUDE.md +8 -9
  2. package/README.md +38 -36
  3. package/bin/morph-spec.js +4 -62
  4. package/bin/validate.js +1 -39
  5. package/claude-plugin.json +1 -1
  6. package/docs/CHEATSHEET.md +1 -1
  7. package/docs/QUICKSTART.md +1 -1
  8. package/framework/CLAUDE.md +1 -1
  9. package/framework/MORPH.md +1 -1
  10. package/framework/agents.json +12 -4
  11. package/framework/commands/morph-apply.md +1 -1
  12. package/framework/commands/morph-status.md +1 -1
  13. package/framework/docs/CLI.md +6 -17
  14. package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +6 -49
  15. package/framework/hooks/claude-code/core/block-raw-worktree-add.js +2 -35
  16. package/framework/hooks/claude-code/core/chain.js +4 -65
  17. package/framework/hooks/claude-code/core/comment-guard.js +2 -16
  18. package/framework/hooks/claude-code/core/enforce-phase-writes.js +6 -50
  19. package/framework/hooks/claude-code/core/gate-guard.js +7 -67
  20. package/framework/hooks/claude-code/core/graph-refresh-kick.js +3 -24
  21. package/framework/hooks/claude-code/core/heavy-gate.js +3 -21
  22. package/framework/hooks/claude-code/core/heavy-release.js +2 -13
  23. package/framework/hooks/claude-code/core/loop-detect.js +2 -31
  24. package/framework/hooks/claude-code/core/pre-bash-denylist.js +0 -4
  25. package/framework/hooks/claude-code/core/protect-spec-files.js +7 -67
  26. package/framework/hooks/claude-code/core/state-sync.js +11 -67
  27. package/framework/hooks/claude-code/core/telemetry-log.js +12 -93
  28. package/framework/hooks/claude-code/core/validate-completion.js +11 -57
  29. package/framework/hooks/claude-code/core/warn-bash-source-write.js +1 -9
  30. package/framework/hooks/claude-code/core/worktree-context.js +10 -110
  31. package/framework/hooks/claude-code/core/worktree-create.js +6 -70
  32. package/framework/hooks/claude-code/core/worktree-env-inject.js +5 -56
  33. package/framework/hooks/claude-code/core/worktree-remove.js +5 -31
  34. package/framework/hooks/shared/activity-logger.js +9 -89
  35. package/framework/hooks/shared/agent-reap.js +2 -17
  36. package/framework/hooks/shared/build-check.js +6 -75
  37. package/framework/hooks/shared/claim-registry.js +9 -119
  38. package/framework/hooks/shared/command-tokens.js +6 -51
  39. package/framework/hooks/shared/comment-rules.js +5 -20
  40. package/framework/hooks/shared/comment-scanner.js +6 -25
  41. package/framework/hooks/shared/comment-stripper.js +11 -85
  42. package/framework/hooks/shared/e2e-check.js +0 -0
  43. package/framework/hooks/shared/errata.js +2 -15
  44. package/framework/hooks/shared/feature-locator.js +11 -95
  45. package/framework/hooks/shared/frontend-locations.js +1 -3
  46. package/framework/hooks/shared/gate-question.js +1 -7
  47. package/framework/hooks/shared/git-exclude.js +3 -20
  48. package/framework/hooks/shared/git-paths.js +8 -104
  49. package/framework/hooks/shared/graph-freshness.js +22 -166
  50. package/framework/hooks/shared/graph-refresh.js +21 -149
  51. package/framework/hooks/shared/heavy-command.js +4 -12
  52. package/framework/hooks/shared/hook-response.js +8 -83
  53. package/framework/hooks/shared/morph-cli.js +8 -52
  54. package/framework/hooks/shared/payload-utils.js +10 -132
  55. package/framework/hooks/shared/phase-utils.js +1 -42
  56. package/framework/hooks/shared/redact-secrets.js +4 -15
  57. package/framework/hooks/shared/reparse-scan.js +6 -66
  58. package/framework/hooks/shared/slice-progress.js +4 -23
  59. package/framework/hooks/shared/source-files.js +4 -17
  60. package/framework/hooks/shared/state-reader.js +13 -183
  61. package/framework/hooks/shared/state-writer.js +8 -52
  62. package/framework/hooks/shared/stdin-reader.js +1 -11
  63. package/framework/hooks/shared/telemetry-logger.js +7 -67
  64. package/framework/hooks/shared/transcript-usage.js +7 -29
  65. package/framework/hooks/shared/worktree-root.js +7 -29
  66. package/framework/rules/csharp-standards.md +1 -1
  67. package/framework/rules/frontend-standards.md +1 -0
  68. package/framework/rules/hangfire-standards.md +1 -1
  69. package/framework/rules/neon-standards.md +1 -1
  70. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  71. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  72. package/framework/skills/core/morph-apply/SKILL.md +2 -2
  73. package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
  74. package/framework/skills/core/morph-machine/SKILL.md +1 -1
  75. package/framework/skills/core/morph-media/SKILL.md +1 -1
  76. package/framework/skills/core/morph-plan/SKILL.md +2 -2
  77. package/framework/skills/core/morph-review/SKILL.md +1 -1
  78. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  79. package/framework/skills/core/morph-uiux/SKILL.md +29 -12
  80. package/framework/standards/STANDARDS.json +34 -12
  81. package/framework/standards/STANDARDS.meta.json +16 -2
  82. package/framework/standards/ai-agents/agent-archetypes.md +2 -2
  83. package/framework/standards/ai-agents/agent-session.md +1 -1
  84. package/framework/standards/ai-agents/conversational-agent-with-phases.md +4 -4
  85. package/framework/standards/ai-agents/durable-workflows-hitl.md +3 -3
  86. package/framework/standards/ai-agents/guardrails.md +1 -1
  87. package/framework/standards/ai-agents/multi-agent-patterns.md +2 -2
  88. package/framework/standards/ai-agents/observability-patterns.md +1 -1
  89. package/framework/standards/ai-agents/production.md +1 -1
  90. package/framework/standards/ai-agents/prompt-sources.md +2 -2
  91. package/framework/standards/ai-agents/providers/model-registry.md +1 -1
  92. package/framework/standards/ai-agents/rag-custom-pgvector.md +2 -2
  93. package/framework/standards/ai-agents/setup.md +2 -2
  94. package/framework/standards/ai-agents/sweet-spot.md +2 -2
  95. package/framework/standards/ai-agents/tool-adapters.md +0 -2
  96. package/framework/standards/ai-agents/vector-data-extensions.md +4 -4
  97. package/framework/standards/ai-agents/workflows.md +1 -1
  98. package/framework/standards/architecture/code-comments.md +1 -1
  99. package/framework/standards/architecture/vertical-slice/vertical-slice.md +1 -1
  100. package/framework/standards/backend/api/validation.md +1 -1
  101. package/framework/standards/backend/dotnet/vsa-handler-patterns.md +5 -5
  102. package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +1 -1
  103. package/framework/standards/backend/integrations/neon-auth/neon-auth.md +2 -2
  104. package/framework/standards/data/nosql/cache/redis.md +1 -1
  105. package/framework/standards/data/nosql/cosmos-db.md +3 -3
  106. package/framework/standards/frontend/admin-app/forms.md +1 -1
  107. package/framework/standards/frontend/design-system/art-direction.md +88 -0
  108. package/framework/standards/frontend/design-system/premium-finish.md +77 -2
  109. package/framework/standards/infrastructure/neon/neon-pgvector.md +5 -5
  110. package/framework/templates/CLAUDE.md.core.template +3 -3
  111. package/framework/templates/REGISTRY.json +9 -9
  112. package/framework/templates/docs/ui-mockups.md +4 -0
  113. package/package.json +1 -1
  114. package/src/commands/context/context-refresh.js +0 -16
  115. package/src/commands/dashboard/dashboard.js +2 -8
  116. package/src/commands/e2e/e2e.js +17 -104
  117. package/src/commands/graph/affected.js +0 -14
  118. package/src/commands/graph/build.js +11 -50
  119. package/src/commands/graph/explain.js +0 -16
  120. package/src/commands/graph/status.js +1 -12
  121. package/src/commands/mcp/mcp-setup.js +4 -62
  122. package/src/commands/observability/cost.js +5 -57
  123. package/src/commands/observability/telemetry.js +1 -14
  124. package/src/commands/project/branch.js +4 -45
  125. package/src/commands/project/claim.js +4 -48
  126. package/src/commands/project/doctor.js +48 -302
  127. package/src/commands/project/env.js +1 -27
  128. package/src/commands/project/fleet.js +3 -32
  129. package/src/commands/project/init.js +4 -68
  130. package/src/commands/project/install-plugin-cmd.js +0 -1
  131. package/src/commands/project/standards.js +1 -62
  132. package/src/commands/project/status.js +0 -53
  133. package/src/commands/project/update.js +31 -239
  134. package/src/commands/project/worktree.js +108 -882
  135. package/src/commands/scaffold/scaffold.js +0 -25
  136. package/src/commands/state/advance.js +14 -85
  137. package/src/commands/state/approve.js +14 -96
  138. package/src/commands/state/archive.js +12 -64
  139. package/src/commands/state/auto-approval.js +2 -5
  140. package/src/commands/state/create.js +22 -109
  141. package/src/commands/state/delete.js +11 -63
  142. package/src/commands/state/finish.js +98 -475
  143. package/src/commands/state/gate-check.js +22 -132
  144. package/src/commands/state/gate-decision.js +3 -39
  145. package/src/commands/state/handoff.js +3 -30
  146. package/src/commands/state/list.js +14 -84
  147. package/src/commands/state/report-check.js +8 -58
  148. package/src/commands/state/retype.js +4 -26
  149. package/src/commands/validation/index.js +0 -3
  150. package/src/commands/validation/mutate.js +2 -5
  151. package/src/commands/validation/validate-feature.js +5 -94
  152. package/src/commands/validation/verify.js +15 -98
  153. package/src/core/paths/output-schema.js +2 -101
  154. package/src/core/state/feature-identity.js +1 -25
  155. package/src/core/state/gate-order.js +0 -27
  156. package/src/core/state/lifecycle-audit.js +8 -100
  157. package/src/core/state/state-manager.js +22 -304
  158. package/src/core/templates/template-registry.js +2 -97
  159. package/src/core/templates/template-renderer.js +13 -93
  160. package/src/core/templates/template-seed.js +0 -1
  161. package/src/core/work-types.js +1 -36
  162. package/src/dashboard/app/App.jsx +1 -8
  163. package/src/dashboard/app/components/ActivityFeed.jsx +0 -5
  164. package/src/dashboard/app/components/CommandPalette.jsx +0 -7
  165. package/src/dashboard/app/components/DetailPanel.jsx +1 -5
  166. package/src/dashboard/app/components/EntityLink.jsx +0 -12
  167. package/src/dashboard/app/components/ErrorBoundary.jsx +1 -8
  168. package/src/dashboard/app/components/KnowledgeMarkdown.jsx +0 -11
  169. package/src/dashboard/app/components/Markdown.jsx +0 -9
  170. package/src/dashboard/app/components/PhaseRail.jsx +0 -11
  171. package/src/dashboard/app/components/SearchFilter.jsx +0 -4
  172. package/src/dashboard/app/components/Sidebar.jsx +0 -5
  173. package/src/dashboard/app/hooks/useMorphQuery.js +1 -11
  174. package/src/dashboard/app/hooks/usePref.js +1 -5
  175. package/src/dashboard/app/lib/format.js +0 -2
  176. package/src/dashboard/app/lib/phases.js +1 -5
  177. package/src/dashboard/app/lib/project.js +0 -12
  178. package/src/dashboard/app/pages/AgentMap.jsx +1 -8
  179. package/src/dashboard/app/pages/FeatureDetail.jsx +1 -5
  180. package/src/dashboard/app/pages/Features.jsx +1 -8
  181. package/src/dashboard/app/pages/Guide.jsx +0 -1
  182. package/src/dashboard/app/pages/HookInspector.jsx +2 -23
  183. package/src/dashboard/app/pages/PhasePipeline.jsx +0 -3
  184. package/src/dashboard/app/pages/Portfolio.jsx +0 -1
  185. package/src/dashboard/app/pages/RulesMap.jsx +1 -16
  186. package/src/dashboard/app/pages/SkillsLibrary.jsx +1 -16
  187. package/src/dashboard/app/pages/Standards.jsx +2 -17
  188. package/src/dashboard/scanner/activity-scanner.js +10 -69
  189. package/src/dashboard/scanner/agents-scanner.js +1 -23
  190. package/src/dashboard/scanner/docs-scanner.js +0 -6
  191. package/src/dashboard/scanner/feature-status.js +2 -5
  192. package/src/dashboard/scanner/features-scanner.js +10 -66
  193. package/src/dashboard/scanner/hooks-scanner.js +5 -28
  194. package/src/dashboard/scanner/index.js +0 -4
  195. package/src/dashboard/scanner/portfolio.js +5 -29
  196. package/src/dashboard/scanner/project-api.js +8 -54
  197. package/src/dashboard/scanner/rules-scanner.js +1 -2
  198. package/src/dashboard/scanner/skills-scanner.js +2 -12
  199. package/src/dashboard/scanner/standards-scanner.js +2 -6
  200. package/src/dashboard/vite-plugin-morph-data.js +5 -19
  201. package/src/lib/ai/ai-checks.js +7 -52
  202. package/src/lib/ai/ai-project-scan.js +14 -108
  203. package/src/lib/ai/code-audit.js +7 -63
  204. package/src/lib/ai/pin-drift.js +8 -51
  205. package/src/lib/ai/registry-audit.js +11 -90
  206. package/src/lib/ci/ci-verify.js +4 -19
  207. package/src/lib/ci/github-ci.js +9 -37
  208. package/src/lib/ci/workflow-scaffold.js +2 -10
  209. package/src/lib/detectors/claude-config-detector.js +13 -74
  210. package/src/lib/detectors/index.js +4 -50
  211. package/src/lib/e2e/compose-env.js +5 -66
  212. package/src/lib/e2e/stack-teardown.js +6 -40
  213. package/src/lib/generators/architecture-scanner.js +18 -156
  214. package/src/lib/generators/handoff-generator.js +9 -53
  215. package/src/lib/generators/scaffold-generator.js +5 -101
  216. package/src/lib/generators/settings-generator.js +4 -37
  217. package/src/lib/git/branch-classifier.js +11 -84
  218. package/src/lib/git/default-branch.js +14 -169
  219. package/src/lib/git/evidence-staleness.js +1 -0
  220. package/src/lib/git/gh.js +2 -17
  221. package/src/lib/git/pending-prs.js +6 -37
  222. package/src/lib/git/pr-files.js +3 -28
  223. package/src/lib/git/pr-index.js +3 -34
  224. package/src/lib/git/tree-fingerprint.js +3 -15
  225. package/src/lib/git/tree-state.js +6 -33
  226. package/src/lib/graph/god-nodes.js +2 -22
  227. package/src/lib/graph/graph-health.js +3 -24
  228. package/src/lib/graph/graph-loader.js +5 -56
  229. package/src/lib/graph/graphify-runtime.js +7 -37
  230. package/src/lib/graph/graphifyignore.js +8 -74
  231. package/src/lib/graph/sanitize.js +16 -136
  232. package/src/lib/heavy/cleanup.js +1 -1
  233. package/src/lib/installers/effects.js +8 -93
  234. package/src/lib/installers/mcp-installer.js +9 -169
  235. package/src/lib/installers/memory-installer.js +4 -27
  236. package/src/lib/installers/templates-reconcile.js +5 -60
  237. package/src/lib/mutation/dotnet-introspection.js +20 -106
  238. package/src/lib/mutation/subset.js +1 -4
  239. package/src/lib/plan/artifact-vocabulary.js +5 -25
  240. package/src/lib/plan/checks.js +5 -31
  241. package/src/lib/plan/plan-parser.js +1 -6
  242. package/src/lib/projects/registry.js +7 -44
  243. package/src/lib/review-reports.js +5 -23
  244. package/src/lib/risk-detector.js +39 -173
  245. package/src/lib/specs/adr-index.js +6 -34
  246. package/src/lib/specs/frontmatter.js +2 -15
  247. package/src/lib/specs/gfm-table.js +1 -7
  248. package/src/lib/specs/revocations.js +1 -14
  249. package/src/lib/specs/screen-checklist.js +47 -124
  250. package/src/lib/stack/dotnet-build-ignores.js +2 -6
  251. package/src/lib/stack/stack-profile.js +1 -28
  252. package/src/lib/stack/stack-scan.js +1 -8
  253. package/src/lib/stack-filter.js +4 -27
  254. package/src/lib/standards/registry.js +1 -7
  255. package/src/lib/standards/sections.js +2 -13
  256. package/src/lib/standards/verified-against.js +19 -191
  257. package/src/lib/tasks/eval-node.js +21 -169
  258. package/src/lib/tasks/linux-runner.js +18 -142
  259. package/src/lib/tasks/test-nodes.js +43 -240
  260. package/src/lib/tasks/test-runner.js +43 -341
  261. package/src/lib/telemetry/metrics.js +7 -36
  262. package/src/lib/telemetry/telemetry-reader.js +13 -125
  263. package/src/lib/telemetry/verify-event.js +2 -30
  264. package/src/lib/validators/code-budget/code-budget-validator.js +3 -43
  265. package/src/lib/validators/code-budget/index.js +0 -7
  266. package/src/lib/validators/contracts/contract-compliance-validator.js +2 -24
  267. package/src/lib/validators/contracts/index.js +0 -6
  268. package/src/lib/validators/nextjs/index.js +0 -5
  269. package/src/lib/validators/nextjs/next-component-validator.js +4 -81
  270. package/src/lib/validators/packages/index.js +0 -6
  271. package/src/lib/validators/packages/package-validator.js +6 -56
  272. package/src/lib/validators/reuse/index.js +0 -8
  273. package/src/lib/validators/reuse/reuse-validator.js +11 -101
  274. package/src/lib/validators/reuse/symbol-scanner.js +6 -62
  275. package/src/lib/validators/traceability-check.js +5 -63
  276. package/src/lib/validators/validation-runner.js +20 -125
  277. package/src/lib/validators/verify-runner.js +52 -358
  278. package/src/lib/work-type-detector.js +5 -67
  279. package/src/lib/worktree/docker-audit.js +17 -136
  280. package/src/lib/worktree/env-allocator.js +10 -98
  281. package/src/lib/worktree/feature-truth.js +12 -115
  282. package/src/lib/worktree/finish-backup.js +32 -242
  283. package/src/lib/worktree/fleet-scanner.js +13 -95
  284. package/src/lib/worktree/ignored-triage.js +15 -91
  285. package/src/lib/worktree/vscode-settings.js +2 -3
  286. package/src/lib/worktree/worktree-audit.js +21 -213
  287. package/src/lib/worktree/worktree-include.js +3 -5
  288. package/src/scripts/global-install.js +3 -9
  289. package/src/scripts/install-plugin.js +1 -13
  290. package/src/scripts/setup-infra.js +17 -147
  291. package/src/utils/agents-installer.js +28 -275
  292. package/src/utils/banner.js +4 -25
  293. package/src/utils/claude-md-injector.js +1 -37
  294. package/src/utils/claude-settings-manager.js +1 -52
  295. package/src/utils/file-copier.js +11 -95
  296. package/src/utils/hooks-installer.js +21 -298
  297. package/src/utils/skills-installer.js +4 -101
  298. package/src/utils/version-checker.js +4 -83
  299. package/framework/commands/morph-proposal.md +0 -9
  300. package/src/commands/utils/index.js +0 -3
  301. package/src/lib/detectors/design-system-detector.js +0 -188
  302. package/src/lib/generators/design-system-generator.js +0 -508
  303. package/src/lib/specs/old-format.js +0 -68
  304. package/src/utils/agent-id-mapper.js +0 -11
@@ -1,20 +1,3 @@
1
- /**
2
- * `morph-spec env [feature] [--json|--posix|--powershell]` — print the
3
- * dedicated environment of a worktree (port block + compose project) in a
4
- * shell-loadable form.
5
- *
6
- * Inside Claude Code the `worktree-env-inject` hook applies this block to
7
- * every dev-server / compose launcher automatically. This command is the same
8
- * contract for everything OUTSIDE the harness: a human terminal
9
- * (`eval "$(morph-spec env)"`), a CI step, a sub-agent running without hooks.
10
- * It derives from `buildComposeEnv` — the function the `verify` e2e node and
11
- * `e2e up` already use — so a shell and the stack can never disagree.
12
- *
13
- * Feature resolution: explicit argument, else the `morph/{f}` (or
14
- * `morph-task/{n}`) branch of the cwd. Read-only: allocation is idempotent and
15
- * never moves an existing block.
16
- */
17
-
18
1
  import { execFileSync } from 'child_process';
19
2
  import { readFileSync } from 'fs';
20
3
  import { join, resolve } from 'path';
@@ -49,14 +32,9 @@ function gitCommonDir(cwd) {
49
32
  }
50
33
  }
51
34
 
52
- /** POSIX single-quote. */
53
35
  const shq = (v) => `'${String(v).replace(/'/g, "'\\''")}'`;
54
36
 
55
- /**
56
- * Pure: the env map for a key, or `{ error }`.
57
- * @param {string|null} featureArg
58
- * @param {string} cwd
59
- */
37
+ /** The env map for a key, or `{ error }`. */
60
38
  export function resolveWorktreeEnv(featureArg, cwd = process.cwd()) {
61
39
  const key = featureArg || envKeyFromBranch(currentBranch(cwd));
62
40
  if (!key) {
@@ -78,10 +56,6 @@ export function render(env, format) {
78
56
  return entries.map(([k, v]) => `export ${k}=${shq(v)}`).join('\n');
79
57
  }
80
58
 
81
- /**
82
- * @param {string|undefined} featureArg
83
- * @param {{ json?: boolean, posix?: boolean, powershell?: boolean }} options
84
- */
85
59
  export function envCommand(featureArg, options = {}) {
86
60
  const result = resolveWorktreeEnv(featureArg || null, process.cwd());
87
61
  if (result.error) {
@@ -1,22 +1,7 @@
1
- /**
2
- * `morph-spec fleet [--json]` — the fleet view.
3
- *
4
- * One line per active feature across the primary root and every morph/*
5
- * worktree: phase, pending gates, slice progress, port block, handoff
6
- * freshness, last commit and dirtiness. This is the terminal surface the
7
- * operator scans between sessions ("what is each instance doing, what is
8
- * waiting on me") — `worktree list` remains the lean per-worktree view.
9
- *
10
- * Read-only, always exits 0 (fail-open — an empty fleet is an answer).
11
- */
12
-
13
1
  import chalk from 'chalk';
14
2
  import { scanFleet } from '../../lib/worktree/fleet-scanner.js';
15
3
  import { claimAge } from '../../../framework/hooks/shared/claim-registry.js';
16
4
 
17
- /**
18
- * @param {{ json?: boolean, cwd?: string }} [options]
19
- */
20
5
  export function fleetCommand(options = {}) {
21
6
  const fleet = scanFleet(options.cwd || process.cwd());
22
7
 
@@ -32,22 +17,13 @@ export function fleetCommand(options = {}) {
32
17
 
33
18
  const col = (s, w) => String(s ?? '-').padEnd(w);
34
19
 
35
- /**
36
- * The REMOTO cell. `-` means "unknown" (no origin, or the probe failed) —
37
- * deliberately the same glyph as "nothing there", because both mean "do not
38
- * trust the local view alone". `local` is the confident negative.
39
- */
20
+ /** `-` (unknown) shares the "nothing there" glyph on purpose: both mean "do not trust the local view alone". */
40
21
  const remoteCell = (r) => {
41
22
  if (!r) return '-';
42
23
  if (r.pr) return `PR #${r.pr.number}${r.pr.state && r.pr.state !== 'OPEN' ? ` (${r.pr.state.toLowerCase()})` : ''}`;
43
24
  return r.pushed ? 'pushed' : 'local';
44
25
  };
45
26
 
46
- /**
47
- * The CLAIM cell — who is on this feature right now (B1). A stale claim is
48
- * shown as stale, not hidden: "nobody here" and "somebody died here" are
49
- * different facts for the operator.
50
- */
51
27
  const claimCell = (c) => {
52
28
  if (!c) return '-';
53
29
  const age = claimAge(c);
@@ -55,10 +31,7 @@ export function fleetCommand(options = {}) {
55
31
  };
56
32
 
57
33
  console.log(chalk.white.bold(
58
- // PHASE at 18: `aguardando-merge` (the pr-pending synthesized phase, see
59
- // fleet-scanner.js) is 16 chars — 1 wider than the col width `list.js`
60
- // already uses (17) for the identical string. A narrower column here
61
- // would misalign every column after it just for that one row.
34
+ // PHASE at 18 fits `aguardando-merge`; narrower misaligns every column after it.
62
35
  col('FEATURE', 20) + col('TYPE', 9) + col('PHASE', 18) + col('FATIAS', 8)
63
36
  + col('GATES PEND.', 20) + col('WHERE', 24) + col('REMOTO', 16) + col('CLAIM', 16)
64
37
  + col('PORTS', 12) + col('HANDOFF', 9) + 'ATIVIDADE',
@@ -66,9 +39,7 @@ export function fleetCommand(options = {}) {
66
39
  for (const e of fleet.entries) {
67
40
  const slices = e.slices ? `${e.slices.done}/${e.slices.total}` : '-';
68
41
  const gates = e.pendingGates.length ? e.pendingGates.join(',') : '-';
69
- // pr-pending has no worktree and isn't root-resident either — its branch
70
- // is the only place it exists, so show that instead of the misleading
71
- // 'raiz' a location-blind check would print.
42
+ // pr-pending exists only on its branch, never in a worktree or the root.
72
43
  const where = (e.location === 'worktree' || e.location === 'pr-pending') ? e.branch : 'raiz';
73
44
  const ports = e.env ? `${e.env.range[0]}-${e.env.range[1]}` : '-';
74
45
  const handoff = e.handoff?.exists ? 'sim' : '-';
@@ -37,25 +37,8 @@ import { resolvePrimaryRoot } from './worktree.js';
37
37
  import { registerProject } from '../../lib/projects/registry.js';
38
38
 
39
39
  /**
40
- * Guard against running a full `init` install from inside a secondary
41
- * (linked) git worktree.
42
- *
43
- * A worktree's `.claude/` and `.morph/framework/` are junctions back to the
44
- * primary root (see `worktree.js`'s `setupInfraLinks`), but `.morph/config/`,
45
- * `.morph/context/`, `.morph/checkpoints/`, `.morph/memory/`, `.morph/archive/`
46
- * and `.morph/state.json` are NOT linked — a full `init` there would scaffold
47
- * a second, disconnected install (config, state) inside the worktree, orphaned
48
- * from the primary root's real install.
49
- *
50
- * Fail-SAFE (not fail-open): blocks whenever `resolvePrimaryRoot(targetPath)`
51
- * resolves to a path OTHER than `targetPath` itself. `resolvePrimaryRoot`
52
- * itself fails open to `targetPath` outside a git repo (or on any git error),
53
- * so non-git projects and the primary root itself are never blocked.
54
- * `--force` is the explicit override, mirroring init's own `--force` flag.
55
- *
56
- * @param {string} targetPath - Effective install target (init's targetPath)
57
- * @param {{ force?: boolean }} [options]
58
- * @returns {{ blocked: boolean, root?: string, target?: string }}
40
+ * A linked worktree junctions `.claude/` and `.morph/framework/` but not `.morph/config`/state:
41
+ * a full install there orphans a second, disconnected one. `--force` overrides.
59
42
  */
60
43
  export function checkSecondaryWorktreeGuard(targetPath, options = {}) {
61
44
  if (options.force) return { blocked: false };
@@ -72,9 +55,6 @@ export async function initCommand(options) {
72
55
  logger.dim(`Target: ${targetPath}`);
73
56
  logger.blank();
74
57
 
75
- // Guard: refuse a full install from inside a secondary worktree — it would
76
- // corrupt the shared infra junctioned back to the primary root and scaffold
77
- // a second, disconnected .morph/config + state.json. --force overrides.
78
58
  const worktreeGuard = checkSecondaryWorktreeGuard(targetPath, options);
79
59
  if (worktreeGuard.blocked) {
80
60
  logger.warn(`Você está num worktree secundário (${worktreeGuard.target}).`);
@@ -83,11 +63,9 @@ export async function initCommand(options) {
83
63
  process.exit(0);
84
64
  }
85
65
 
86
- // Check if already initialized
87
66
  const morphPath = join(targetPath, '.morph');
88
67
  if (await pathExists(morphPath)) {
89
68
  if (!options.force) {
90
- // Check if project version is outdated — auto-update instead of blocking
91
69
  const projectCheck = await checkProjectOutdated(targetPath);
92
70
  if (projectCheck.isOutdated) {
93
71
  logger.info(`MORPH already initialized (v${projectCheck.current}). Framework update available (v${projectCheck.cliVersion}).`);
@@ -105,11 +83,8 @@ export async function initCommand(options) {
105
83
 
106
84
  try {
107
85
 
108
- // Steps 1-10: Infrastructure (headless, no prompts)
109
86
  spinner.stop();
110
- // force: true — the secondary-worktree guard already ran above (either we
111
- // ARE the primary root, or the caller explicitly passed --force), so it
112
- // must not be redundantly re-applied inside setupInfra().
87
+ // The secondary-worktree guard already ran above; setupInfra must not re-apply it.
113
88
  const infraResult = await setupInfra(targetPath, { force: true });
114
89
  if (infraResult?.refused) {
115
90
  process.exitCode = 1;
@@ -117,23 +92,18 @@ export async function initCommand(options) {
117
92
  }
118
93
  spinner.start('Continuing...');
119
94
 
120
- // Derive display variables from what setupInfra installed
121
95
  const cliVersion = getInstalledCLIVersion();
122
96
  const commandsCopied = await pathExists(join(targetPath, '.claude', 'commands'));
123
97
  const rulesCopied = await pathExists(join(targetPath, '.claude', 'rules'));
124
- // Re-run installClaudeHooks to get the result object (idempotent — hooks already installed)
125
98
  const hooksResult = await installClaudeHooks(targetPath);
126
99
 
127
- // Re-derive config path for stack detection updates
128
100
  const configDir = join(morphPath, 'config');
129
101
  const configPath = join(configDir, 'config.json');
130
102
  const contextDir = join(morphPath, 'context');
131
103
 
132
- // Read config written by setupInfra so stack detection can update it
133
104
  let config = (await pathExists(configPath)) ? await readJson(configPath) : { project: {} };
134
105
  if (!config.project) config.project = {};
135
106
 
136
- // 11b. Detect Claude Code environment (plugins, MCPs, skills)
137
107
  spinner.text = 'Detecting Claude Code environment...';
138
108
  let claudeConfigDetected = null;
139
109
  let integrationsCreated = false;
@@ -152,14 +122,6 @@ export async function initCommand(options) {
152
122
  logger.info(summary);
153
123
  }
154
124
 
155
- // Show MCP-to-phase mapping.
156
- //
157
- // This called mapMcpsToPhases with one argument where it takes three,
158
- // so `phaseMatrix[currentPhase]` threw a TypeError on every project
159
- // that had any MCP configured. The outer catch reported it as
160
- // "Claude config detection skipped" — which reads like "nothing to
161
- // detect" — and everything below it never ran: integrations.json was
162
- // never written and the optimized settings were never generated.
163
125
  if (claudeConfigDetected.mcpServers.length > 0) {
164
126
  const byPhase = mcpAvailabilityByPhase(
165
127
  claudeConfigDetected.mcpServers,
@@ -195,11 +157,9 @@ export async function initCommand(options) {
195
157
  }
196
158
  }
197
159
  } catch (error) {
198
- // Non-fatal: continue without integrations
199
160
  logger.dim(` Claude config detection skipped: ${error.message}`);
200
161
  }
201
162
 
202
- // 11c. Stack detection (moved before MCP setup so we know the stack)
203
163
  spinner.text = 'Detecting project stack...';
204
164
  let detectedStack = 'unknown';
205
165
  const hasProjectFiles = await pathExists(join(targetPath, 'package.json'))
@@ -214,7 +174,6 @@ export async function initCommand(options) {
214
174
  if (structure?.stack && structure.stack !== 'unknown') {
215
175
  detectedStack = structure.stack;
216
176
 
217
- // Persist detected stack to config.json
218
177
  if (structure?.stack && structure.stack !== 'unknown') {
219
178
  config.project.stack = structure.stack;
220
179
  }
@@ -256,23 +215,19 @@ export async function initCommand(options) {
256
215
  logger.dim('Review and edit .morph/context/standards.md as needed.');
257
216
  }
258
217
 
259
- // Re-install stack-filtered assets now that we know the stack
260
218
  const stackTags = getProjectTags(config);
261
219
  if (stackTags.length > 0) {
262
220
  spinner.start('Re-installing stack-filtered assets...');
263
221
  const frameworkDir = join(targetPath, '.morph', 'framework');
264
222
  const fwSrcDir = join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..', 'framework');
265
223
 
266
- // Rules
267
224
  const rulesSrc = join(fwSrcDir, 'rules');
268
225
  const rulesDest = join(targetPath, '.claude', 'rules');
269
226
  installRulesForStack(rulesSrc, rulesDest, stackTags);
270
227
  installCommandsForStack(join(fwSrcDir, 'commands'), join(targetPath, '.claude', 'commands'), stackTags);
271
228
 
272
- // Skills
273
229
  await installSkills(targetPath, { projectTags: stackTags });
274
230
 
275
- // Agents (domain personas from agents.json)
276
231
  await installAgents(targetPath, fwSrcDir, { projectTags: stackTags });
277
232
  await installDomainAgents(targetPath, fwSrcDir, { projectTags: stackTags });
278
233
 
@@ -286,7 +241,6 @@ export async function initCommand(options) {
286
241
  }
287
242
  }
288
243
 
289
- // 11d. MCP Auto-Setup
290
244
  let mcpSetupResult = null;
291
245
  if (!options.skipMcp) {
292
246
  try {
@@ -304,7 +258,6 @@ export async function initCommand(options) {
304
258
  logger.blank();
305
259
  logger.header('MCP Server Setup');
306
260
 
307
- // Auto-install prompt
308
261
  let autoInstalled = {};
309
262
  if (hasAutoMcps) {
310
263
  const { installAuto } = await inquirer.prompt([{
@@ -322,7 +275,6 @@ export async function initCommand(options) {
322
275
  autoInstalled[name] = orchestration.autoInstallable[name];
323
276
  }
324
277
 
325
- // Install companion skills for MCPs that define them (e.g., Stitch agent skills)
326
278
  const skillResults = installCompanionSkills(orchestration.autoInstallable);
327
279
  for (const r of skillResults) {
328
280
  if (r.success) {
@@ -334,13 +286,11 @@ export async function initCommand(options) {
334
286
  }
335
287
  }
336
288
 
337
- // Credential MCPs — inline setup or instructions
338
289
  const manualInstalled = {};
339
290
  if (hasManualMcps) {
340
291
  for (const [name, entry] of Object.entries(orchestration.needsManualSetup)) {
341
292
  logger.blank();
342
293
 
343
- // Show warnings
344
294
  for (const warning of entry.install.warnings || []) {
345
295
  logger.warn(` ${warning}`);
346
296
  }
@@ -354,7 +304,6 @@ export async function initCommand(options) {
354
304
  }]);
355
305
 
356
306
  if (setupNow) {
357
- // Stitch — automated setup via setupStitch()
358
307
  if (name === 'stitch' && !entry.install.autoInstall) {
359
308
  spinner.start('Setting up Stitch MCP...');
360
309
  const stitchResult = await setupStitch(targetPath);
@@ -374,7 +323,6 @@ export async function initCommand(options) {
374
323
  continue;
375
324
  }
376
325
 
377
- // Remote MCPs — launch OAuth via claude mcp add
378
326
  if (isRemoteMcp(entry.install.config)) {
379
327
  const url = entry.install.config.url;
380
328
  logger.info(` Launching ${capitalizedName} OAuth authentication...`);
@@ -391,7 +339,6 @@ export async function initCommand(options) {
391
339
  continue;
392
340
  }
393
341
 
394
- // Collect credentials
395
342
  const credentialValues = {};
396
343
  for (const cred of entry.install.credentials) {
397
344
  const { value } = await inquirer.prompt([{
@@ -408,7 +355,6 @@ export async function initCommand(options) {
408
355
  spinner.succeed(`${capitalizedName} MCP configured`);
409
356
  manualInstalled[name] = entry;
410
357
  } else {
411
- // Show setup instructions
412
358
  const instructions = generateSetupInstructions(name, entry);
413
359
  logger.blank();
414
360
  logger.dim(' Add to .mcp.json → mcpServers:');
@@ -426,7 +372,6 @@ export async function initCommand(options) {
426
372
  }
427
373
  }
428
374
 
429
- // Summary table
430
375
  const justInstalled = { ...autoInstalled, ...manualInstalled };
431
376
  const statusRows = formatMcpStatusTable(orchestration, justInstalled);
432
377
 
@@ -460,7 +405,6 @@ export async function initCommand(options) {
460
405
  logger.dim('\nSkipped MCP setup (--skip-mcp flag)');
461
406
  }
462
407
 
463
- // Auto-generate architecture context (non-blocking on failure)
464
408
  spinner.text = 'Generating architecture context...';
465
409
  try {
466
410
  const { scanArchitecture, renderArchitectureContext } = await import('../../lib/generators/architecture-scanner.js');
@@ -468,15 +412,12 @@ export async function initCommand(options) {
468
412
  await renderArchitectureContext(targetPath, scanResult);
469
413
  spinner.succeed('Architecture context generated');
470
414
  } catch {
471
- // Non-fatal: placeholder README.md remains
472
415
  spinner.warn('Architecture context generation skipped');
473
416
  }
474
417
 
475
418
  spinner.succeed('MORPH-SPEC installed successfully!');
476
- // The dashboard's portfolio learns about the project here (fail-open).
477
419
  registerProject(targetPath, 'init');
478
420
 
479
- // Show next steps
480
421
  logger.blank();
481
422
  logger.success(`MORPH-SPEC v${cliVersion} installed successfully!`);
482
423
  logger.blank();
@@ -517,7 +458,6 @@ export async function initCommand(options) {
517
458
 
518
459
  logger.dim(' ✓ .claude/skills/ (installed as skill directories)');
519
460
 
520
- // Show agent team breakdown from setup-infra result
521
461
  const agents = infraResult?.agents;
522
462
  if (agents) {
523
463
  const total = (agents.tier1 || 0) + (agents.tier2 || 0) + (agents.specialists || 0) + (agents.personas || 0);
@@ -528,7 +468,6 @@ export async function initCommand(options) {
528
468
 
529
469
  logger.dim(' ✓ ~/.claude/statusline.sh (global statusline installed)');
530
470
 
531
- // Check CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS in ~/.claude/settings.local.json
532
471
  logger.blank();
533
472
  const globalSettingsPath = join(homedir(), '.claude', 'settings.local.json');
534
473
  let agentTeamsEnabled = false;
@@ -536,7 +475,6 @@ export async function initCommand(options) {
536
475
  const globalSettings = await readJson(globalSettingsPath);
537
476
  agentTeamsEnabled = globalSettings?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === '1';
538
477
  } catch {
539
- // File missing or unreadable — treat as not enabled
540
478
  }
541
479
 
542
480
  if (agentTeamsEnabled) {
@@ -548,7 +486,6 @@ export async function initCommand(options) {
548
486
 
549
487
  logger.blank();
550
488
 
551
- // Populate Claude Code persistent memory so future sessions enter contextualized
552
489
  try {
553
490
  const { installProjectMemory } = await import('../../lib/installers/memory-installer.js');
554
491
  const memResult = await installProjectMemory(targetPath, {
@@ -561,10 +498,9 @@ export async function initCommand(options) {
561
498
  logger.dim(` ⚠ Memory install skipped: ${err.message}`);
562
499
  }
563
500
 
564
- // Suggest tutorial for first-time users
565
501
  if (integrationsCreated) {
566
502
  logger.blank();
567
- logger.info('First time using morph-spec? Run `/morph-proposal <feature>` to start a new feature.');
503
+ logger.info('First time using morph-spec? Run `/morph-plan <feature>` to start a new feature.');
568
504
  }
569
505
 
570
506
  logger.blank();
@@ -1,4 +1,3 @@
1
- // src/commands/project/install-plugin-cmd.js
2
1
  import { installPlugin } from '../../scripts/install-plugin.js';
3
2
  import { logger } from '../../utils/logger.js';
4
3
 
@@ -1,30 +1,10 @@
1
- /**
2
- * `morph-spec standards [--find "<query>"] [--show <id>[#<anchor>]] [--category <c>] [--tags <a,b>] [--json]`
3
- *
4
- * `--find` scores the registry server-side and returns the TOP 3 hits with
5
- * digest and anchor keys, so nobody reads the whole registry to pick a
6
- * standard. `--show <id>#<anchor>` prints only that section of the .md;
7
- * `--show <id>` prints the digest and the anchors. Bare call: categories + counts.
8
- *
9
- * A query with no hit exits 0 (advisory, not a gate); under `--json` the
10
- * shape stays `{ query, results: [], suggestion }`.
11
- */
12
-
13
1
  import { existsSync, readFileSync } from 'fs';
14
2
  import { dirname, join } from 'path';
15
3
  import chalk from 'chalk';
16
4
  import { loadStandardsRegistry } from '../../lib/standards/registry.js';
17
5
  import { markdownHeadings, sectionBySlug } from '../../lib/standards/sections.js';
18
6
 
19
- /**
20
- * Resolve STANDARDS.json the same way doctor.js resolves the standards root:
21
- * an installed project first (`.morph/framework/standards/`), falling back
22
- * to this package's own bundled copy (`framework/standards/`) — the framework
23
- * repo in dev, or the npm package's own copy before `setup-infra` has run.
24
- *
25
- * @param {string} targetPath - project root to look for `.morph/` under
26
- * @returns {string|null} absolute path to STANDARDS.json, or null if neither exists
27
- */
7
+ /** Installed project first, else this package's bundled copy (dev repo, or before `setup-infra` ran). */
28
8
  export function resolveStandardsJsonPath(targetPath) {
29
9
  const installed = join(targetPath, '.morph', 'framework', 'standards', 'STANDARDS.json');
30
10
  if (existsSync(installed)) return installed;
@@ -35,13 +15,6 @@ export function resolveStandardsJsonPath(targetPath) {
35
15
  return null;
36
16
  }
37
17
 
38
- /**
39
- * The one section a `--show` target names. `anchor` is an anchor key of the
40
- * registry entry (`regra`) or any heading slug of the .md (`#regra-principal`).
41
- * @returns {{ status: 'ok', section: string, slug: string }
42
- * | { status: 'unknown-anchor', anchors: Record<string, string>, headings: string[] }
43
- * | { status: 'unreadable' }}
44
- */
45
18
  export function resolveStandardSection(standard, mdText, anchor) {
46
19
  if (mdText === null) return { status: 'unreadable' };
47
20
  const anchors = standard.anchors || {};
@@ -98,11 +71,6 @@ function showStandard(standards, standardsJsonPath, target, json) {
98
71
  process.exit(1);
99
72
  }
100
73
 
101
- /**
102
- * category → count, sorted by count desc then name asc.
103
- * @param {object[]} standards
104
- * @returns {{ category: string, count: number }[]}
105
- */
106
74
  export function categoryCounts(standards) {
107
75
  const counts = {};
108
76
  for (const std of standards) {
@@ -114,16 +82,6 @@ export function categoryCounts(standards) {
114
82
  .sort((a, b) => b.count - a.count || a.category.localeCompare(b.category));
115
83
  }
116
84
 
117
- /**
118
- * Simple weighted relevance score for one standard against a query.
119
- * Tiers, as specified: name/id > tags(+aliases) > digest. category/subcategory
120
- * ride alongside the tags tier (lighter). A token-level fallback keeps
121
- * multi-word queries findable even without a verbatim phrase match anywhere.
122
- *
123
- * @param {object} std - one STANDARDS.json entry
124
- * @param {string} query - raw user query (already trimmed, non-empty)
125
- * @returns {number} score, 0 = no match
126
- */
127
85
  export function scoreStandard(std, query) {
128
86
  const q = query.toLowerCase();
129
87
  const tokens = q.split(/\s+/).filter((t) => t.length >= 3);
@@ -138,19 +96,15 @@ export function scoreStandard(std, query) {
138
96
 
139
97
  let score = 0;
140
98
 
141
- // Tier 1: name / id — the strongest signal.
142
99
  if (id === q || name === q) score += 20;
143
100
  else if (id.includes(q) || name.includes(q)) score += 12;
144
101
 
145
- // Tier 2: tags / aliases (curated search terms) + category/subcategory.
146
102
  if (tags.includes(q) || aliases.includes(q)) score += 8;
147
103
  else if (tags.some((t) => t.includes(q)) || aliases.some((a) => a.includes(q))) score += 5;
148
104
  if (category === q || subcategory === q) score += 4;
149
105
 
150
- // Tier 3: digest — weakest signal, full-phrase substring only.
151
106
  if (digest.includes(q)) score += 2;
152
107
 
153
- // Token-level fallback for multi-word queries with no verbatim match above.
154
108
  for (const tok of tokens) {
155
109
  if (name.includes(tok) || id.includes(tok)) score += 2;
156
110
  if (tags.some((t) => t.includes(tok)) || aliases.some((a) => a.includes(tok))) score += 1;
@@ -160,15 +114,6 @@ export function scoreStandard(std, query) {
160
114
  return score;
161
115
  }
162
116
 
163
- /**
164
- * Rank standards against a query, applying optional category/tags filters
165
- * first. Returns the TOP 3 with score > 0, sorted desc (ties broken by id).
166
- *
167
- * @param {object[]} standards
168
- * @param {string} query
169
- * @param {{ category?: string, tags?: string[] }} [filters]
170
- * @returns {Array<object & { score: number }>}
171
- */
172
117
  export function findStandards(standards, query, filters = {}) {
173
118
  const category = filters.category?.toLowerCase();
174
119
  const tags = (filters.tags || []).map((t) => t.toLowerCase());
@@ -189,15 +134,11 @@ export function findStandards(standards, query, filters = {}) {
189
134
  .slice(0, 3);
190
135
  }
191
136
 
192
- /** Parse `--tags a,b,c` into a trimmed, non-empty array. */
193
137
  function parseTagsOption(raw) {
194
138
  if (!raw) return [];
195
139
  return String(raw).split(',').map((t) => t.trim()).filter(Boolean);
196
140
  }
197
141
 
198
- /**
199
- * @param {{ find?: string, show?: string, category?: string, tags?: string, json?: boolean, cwd?: string }} [options]
200
- */
201
142
  export function standardsCommand(options = {}) {
202
143
  const cwd = options.cwd || process.cwd();
203
144
  const standardsJsonPath = resolveStandardsJsonPath(cwd);
@@ -220,7 +161,6 @@ export function standardsCommand(options = {}) {
220
161
  if (options.show) showStandard(standards, standardsJsonPath, options.show, options.json);
221
162
  const query = (options.find || '').trim();
222
163
 
223
- // ── Bare call (no --find): categories + counts, cheap orientation ────────
224
164
  if (!query) {
225
165
  const counts = categoryCounts(standards);
226
166
  if (options.json) {
@@ -236,7 +176,6 @@ export function standardsCommand(options = {}) {
236
176
  process.exit(0);
237
177
  }
238
178
 
239
- // ── --find: score + filter ────────────────────────────────────────────
240
179
  const filters = { category: options.category, tags: parseTagsOption(options.tags) };
241
180
  const results = findStandards(standards, query, filters);
242
181