@polymorphism-tech/morph-spec 8.46.0 → 9.0.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 +53 -44
  2. package/README.md +3 -4
  3. package/bin/morph-spec.js +38 -55
  4. package/bin/validate.js +5 -134
  5. package/claude-plugin.json +1 -1
  6. package/docs/CHEATSHEET.md +2 -2
  7. package/docs/QUICKSTART.md +1 -1
  8. package/framework/CLAUDE.md +41 -101
  9. package/framework/MORPH.md +95 -252
  10. package/framework/agents.json +75 -18
  11. package/framework/commands/create-umbraco-lp.md +2 -0
  12. package/framework/commands/migrate-lp-to-umbraco.md +2 -0
  13. package/framework/commands/morph-apply.md +5 -28
  14. package/framework/commands/morph-archive.md +2 -2
  15. package/framework/commands/morph-hotfix.md +8 -8
  16. package/framework/commands/morph-infra.md +17 -203
  17. package/framework/commands/morph-media.md +3 -0
  18. package/framework/commands/morph-preflight.md +7 -31
  19. package/framework/commands/morph-proposal.md +2 -50
  20. package/framework/commands/morph-status.md +3 -3
  21. package/framework/commands/morph-troubleshoot.md +2 -14
  22. package/framework/docs/CLI.md +585 -286
  23. package/framework/evals/review-checklist.md +82 -41
  24. package/framework/hooks/README.md +10 -11
  25. package/framework/hooks/claude-code/core/comment-guard.js +1 -1
  26. package/framework/hooks/claude-code/core/denylist.json +33 -3
  27. package/framework/hooks/claude-code/core/enforce-phase-writes.js +16 -20
  28. package/framework/hooks/claude-code/core/gate-guard.js +2 -11
  29. package/framework/hooks/claude-code/core/pre-bash-denylist.js +38 -0
  30. package/framework/hooks/claude-code/core/protect-spec-files.js +30 -242
  31. package/framework/hooks/claude-code/core/state-sync.js +17 -19
  32. package/framework/hooks/claude-code/core/telemetry-log.js +3 -3
  33. package/framework/hooks/claude-code/core/validate-completion.js +33 -97
  34. package/framework/hooks/claude-code/core/warn-bash-source-write.js +31 -0
  35. package/framework/hooks/claude-code/core/worktree-context.js +5 -4
  36. package/framework/hooks/claude-code/statusline.py +55 -41
  37. package/framework/hooks/package.json +3 -0
  38. package/framework/hooks/shared/activity-logger.js +1 -1
  39. package/framework/hooks/shared/build-check.js +10 -6
  40. package/framework/hooks/shared/command-tokens.js +169 -0
  41. package/framework/hooks/shared/comment-rules.js +1 -1
  42. package/framework/hooks/shared/comment-scanner.js +10 -23
  43. package/framework/hooks/shared/comment-stripper.js +1 -1
  44. package/framework/hooks/shared/e2e-check.js +67 -31
  45. package/framework/hooks/shared/errata.js +72 -0
  46. package/framework/hooks/shared/feature-locator.js +1 -1
  47. package/framework/hooks/shared/frontend-locations.js +6 -0
  48. package/framework/hooks/shared/gate-question.js +18 -0
  49. package/framework/hooks/shared/phase-utils.js +15 -32
  50. package/framework/hooks/shared/slice-progress.js +118 -0
  51. package/framework/hooks/shared/spawn-command.js +23 -0
  52. package/framework/hooks/shared/state-reader.js +61 -87
  53. package/framework/hooks/shared/state-writer.js +3 -3
  54. package/framework/mcp/registry.json +3 -4
  55. package/framework/phases.json +23 -39
  56. package/framework/rules/ai-agents-standards.md +18 -16
  57. package/framework/rules/asaas-standards.md +3 -1
  58. package/framework/rules/csharp-standards.md +10 -8
  59. package/framework/rules/data-standards.md +5 -5
  60. package/framework/rules/dotnet-templates.md +1 -1
  61. package/framework/rules/frontend-standards.md +4 -2
  62. package/framework/rules/gsap-standards.md +10 -5
  63. package/framework/rules/hangfire-standards.md +3 -1
  64. package/framework/rules/infrastructure-standards.md +4 -2
  65. package/framework/rules/neon-auth-standards.md +3 -1
  66. package/framework/rules/neon-standards.md +6 -4
  67. package/framework/rules/nextjs-standards.md +13 -11
  68. package/framework/rules/nextjs-templates.md +1 -1
  69. package/framework/rules/resend-standards.md +3 -1
  70. package/framework/schemas/config.schema.json +14 -9
  71. package/framework/schemas/feature.schema.json +15 -52
  72. package/framework/skills/README.md +4 -5
  73. package/framework/skills/core/create-umbraco-lp/SKILL.md +3 -3
  74. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +3 -3
  75. package/framework/skills/core/morph-apply/SKILL.md +150 -223
  76. package/framework/skills/core/morph-hotfix/SKILL.md +34 -43
  77. package/framework/skills/core/morph-machine/SKILL.md +4 -4
  78. package/framework/skills/core/morph-media/SKILL.md +3 -3
  79. package/framework/skills/core/morph-plan/SKILL.md +138 -300
  80. package/framework/skills/core/morph-review/SKILL.md +112 -137
  81. package/framework/skills/core/morph-standards/SKILL.md +29 -41
  82. package/framework/skills/core/morph-uiux/SKILL.md +78 -153
  83. package/framework/standards/STANDARDS.json +90 -1219
  84. package/framework/standards/STANDARDS.meta.json +1305 -0
  85. package/framework/standards/ai-agents/evals-with-cache.md +2 -3
  86. package/framework/standards/ai-agents/llm-runtime-defaults.md +1 -1
  87. package/framework/standards/ai-agents/modalities-speech-to-text.md +36 -26
  88. package/framework/standards/ai-agents/prompt-sources.md +6 -4
  89. package/framework/standards/ai-agents/providers/model-registry.md +1 -1
  90. package/framework/standards/ai-agents/rag-custom-pgvector.md +67 -39
  91. package/framework/standards/ai-agents/setup.md +2 -2
  92. package/framework/standards/ai-agents/structured-output.md +1 -1
  93. package/framework/standards/ai-agents/sweet-spot.md +1 -1
  94. package/framework/standards/architecture/code-comments.md +8 -8
  95. package/framework/standards/architecture/vertical-slice/vertical-slice.md +18 -9
  96. package/framework/standards/backend/api/validation.md +135 -47
  97. package/framework/standards/backend/database/postgresql/database.md +11 -7
  98. package/framework/standards/backend/database/vector-search-rag.md +207 -324
  99. package/framework/standards/backend/dotnet/fluent-validation-vsa.md +14 -8
  100. package/framework/standards/backend/dotnet/result-pattern.md +40 -6
  101. package/framework/standards/backend/dotnet/scalar-ui.md +13 -7
  102. package/framework/standards/backend/dotnet/scrutor.md +1 -1
  103. package/framework/standards/backend/dotnet/testing.md +1 -1
  104. package/framework/standards/backend/dotnet/vsa-handler-patterns.md +7 -7
  105. package/framework/standards/backend/integrations/asaas/asaas-api.md +309 -165
  106. package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +134 -154
  107. package/framework/standards/data/nosql/cache/redis.md +120 -44
  108. package/framework/standards/data/nosql/cosmos-db.md +114 -71
  109. package/framework/standards/frontend/design-system/animations.md +1 -1
  110. package/framework/standards/frontend/design-system/naming.md +1 -1
  111. package/framework/standards/frontend/nextjs/motion-patterns.md +45 -29
  112. package/framework/standards/frontend/nextjs/naming-conventions.md +1 -1
  113. package/framework/standards/infrastructure/docker/coolify-deploy.md +8 -6
  114. package/framework/standards/infrastructure/neon/neon-pgvector.md +120 -75
  115. package/framework/standards/infrastructure/neon/neon-setup.md +53 -31
  116. package/framework/standards/integration/mcp/mcp-tools.md +7 -7
  117. package/framework/templates/README.md +2 -3
  118. package/framework/templates/REGISTRY.json +6 -170
  119. package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +2 -2
  120. package/framework/templates/code/dotnet/extensions/database-extensions.cs +1 -1
  121. package/framework/templates/code/dotnet/extensions/result-extensions.cs +27 -0
  122. package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +2 -2
  123. package/framework/templates/docs/plan.md +72 -0
  124. package/framework/templates/dotnet/ai-kit/README.md +1 -9
  125. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +1 -1
  126. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +0 -10
  127. package/framework/templates/infrastructure/docker/coolify.template.json +3 -3
  128. package/framework/templates/infrastructure/github/README.md +2 -1
  129. package/framework/templates/infrastructure/github/workflows/deploy-coolify.yml.hbs +2 -1
  130. package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +1 -1
  131. package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +1 -1
  132. package/framework/templates/meta-prompts/squad-leaders/squad-leader.md +1 -1
  133. package/framework/templates/meta-prompts/validators/pre-commit-validator.md +3 -4
  134. package/package.json +1 -1
  135. package/src/commands/e2e/e2e.js +2 -2
  136. package/src/commands/observability/cost.js +18 -60
  137. package/src/commands/observability/telemetry.js +3 -5
  138. package/src/commands/project/doctor-procs.js +1 -1
  139. package/src/commands/project/doctor.js +9 -9
  140. package/src/commands/project/fleet.js +4 -4
  141. package/src/commands/project/heavy.js +3 -3
  142. package/src/commands/project/init.js +6 -1
  143. package/src/commands/project/setup-infra-cmd.js +2 -1
  144. package/src/commands/project/stack-scan.js +58 -0
  145. package/src/commands/project/standards.js +79 -25
  146. package/src/commands/project/status.js +29 -69
  147. package/src/commands/project/update.js +33 -19
  148. package/src/commands/project/worktree.js +1 -1
  149. package/src/commands/state/advance.js +62 -46
  150. package/src/commands/state/approve.js +95 -138
  151. package/src/commands/state/archive.js +20 -84
  152. package/src/commands/state/auto-approval.js +68 -0
  153. package/src/commands/state/create.js +28 -1
  154. package/src/commands/state/delete.js +1 -1
  155. package/src/commands/state/finish.js +11 -23
  156. package/src/commands/state/gate-check.js +86 -95
  157. package/src/commands/state/gate-decision.js +6 -4
  158. package/src/commands/state/handoff.js +1 -1
  159. package/src/commands/state/list.js +9 -9
  160. package/src/commands/state/report-check.js +157 -311
  161. package/src/commands/state/retype.js +9 -3
  162. package/src/commands/validation/mutate.js +77 -14
  163. package/src/commands/validation/plan-check.js +81 -0
  164. package/src/commands/validation/validate-feature.js +60 -135
  165. package/src/commands/validation/verify.js +41 -82
  166. package/src/core/paths/output-schema.js +20 -67
  167. package/src/core/state/gate-order.js +5 -6
  168. package/src/core/state/lifecycle-audit.js +2 -2
  169. package/src/core/state/state-manager.js +17 -98
  170. package/src/core/templates/template-registry.js +2 -2
  171. package/src/core/templates/template-seed.js +22 -0
  172. package/src/core/work-types.js +10 -10
  173. package/src/dashboard/app/App.jsx +0 -2
  174. package/src/dashboard/app/components/ActivityFeed.jsx +2 -3
  175. package/src/dashboard/app/components/CommandPalette.jsx +7 -8
  176. package/src/dashboard/app/components/EntityLink.jsx +1 -2
  177. package/src/dashboard/app/components/Markdown.jsx +1 -1
  178. package/src/dashboard/app/components/Sidebar.jsx +1 -2
  179. package/src/dashboard/app/hooks/useMorphQuery.js +1 -1
  180. package/src/dashboard/app/lib/phases.js +2 -4
  181. package/src/dashboard/app/pages/Activity.jsx +1 -1
  182. package/src/dashboard/app/pages/FeatureDetail.jsx +139 -129
  183. package/src/dashboard/app/pages/Features.jsx +9 -9
  184. package/src/dashboard/app/pages/Guide.jsx +2 -2
  185. package/src/dashboard/app/pages/PhasePipeline.jsx +3 -4
  186. package/src/dashboard/app/pages/RulesMap.jsx +3 -3
  187. package/src/dashboard/app/pages/SkillsLibrary.jsx +3 -3
  188. package/src/dashboard/app/pages/Standards.jsx +1 -1
  189. package/src/dashboard/scanner/activity-scanner.js +6 -16
  190. package/src/dashboard/scanner/agents-scanner.js +1 -1
  191. package/src/dashboard/scanner/docs-scanner.js +5 -23
  192. package/src/dashboard/scanner/features-scanner.js +95 -60
  193. package/src/dashboard/scanner/index.js +0 -2
  194. package/src/dashboard/scanner/project-api.js +1 -1
  195. package/src/dashboard/scanner/rules-scanner.js +15 -10
  196. package/src/dashboard/scanner/skills-scanner.js +2 -3
  197. package/src/dashboard/scanner/standards-scanner.js +2 -1
  198. package/src/lib/ci/ci-verify.js +17 -1
  199. package/src/lib/ci/github-ci.js +1 -1
  200. package/src/lib/detectors/index.js +3 -8
  201. package/src/lib/generators/handoff-generator.js +34 -65
  202. package/src/lib/generators/settings-generator.js +11 -89
  203. package/src/lib/git/evidence-staleness.js +1 -1
  204. package/src/lib/git/tree-fingerprint.js +19 -7
  205. package/src/lib/git/tree-state.js +2 -2
  206. package/src/lib/heavy/cleanup.js +1 -5
  207. package/src/lib/installers/memory-installer.js +6 -8
  208. package/src/lib/mutation/commands.js +3 -2
  209. package/src/lib/{tasks/dotnet-test-introspection.js → mutation/dotnet-introspection.js} +17 -282
  210. package/src/lib/mutation/plan.js +14 -6
  211. package/src/lib/mutation/runner.js +1 -1
  212. package/src/lib/mutation/subset.js +46 -9
  213. package/src/lib/plan/artifact-vocabulary.js +60 -0
  214. package/src/lib/plan/checks.js +234 -0
  215. package/src/lib/plan/plan-parser.js +209 -0
  216. package/src/lib/plan/plan-template.js +18 -0
  217. package/src/lib/review-reports.js +222 -0
  218. package/src/lib/risk-detector.js +134 -135
  219. package/src/lib/specs/adr-index.js +50 -69
  220. package/src/lib/specs/design-seed.js +18 -0
  221. package/src/lib/specs/frontmatter.js +44 -0
  222. package/src/lib/specs/gfm-table.js +17 -0
  223. package/src/lib/specs/old-format.js +68 -0
  224. package/src/lib/specs/revocations.js +37 -95
  225. package/src/lib/specs/screen-checklist.js +18 -17
  226. package/src/lib/stack/dotnet-build-ignores.js +47 -0
  227. package/src/lib/stack/stack-profile.js +1 -1
  228. package/src/lib/stack/stack-scan.js +267 -0
  229. package/src/lib/standards/registry.js +43 -0
  230. package/src/lib/standards/sections.js +58 -0
  231. package/src/lib/tasks/eval-node.js +4 -12
  232. package/src/lib/tasks/test-nodes.js +1 -74
  233. package/src/lib/tasks/test-runner.js +75 -117
  234. package/src/lib/telemetry/metrics.js +8 -69
  235. package/src/lib/telemetry/telemetry-reader.js +5 -118
  236. package/src/lib/telemetry/verify-event.js +5 -7
  237. package/src/lib/validators/code-budget/code-budget-validator.js +1 -1
  238. package/src/lib/validators/contracts/contract-compliance-validator.js +2 -2
  239. package/src/lib/validators/reuse/reuse-validator.js +24 -48
  240. package/src/lib/validators/reuse/symbol-scanner.js +2 -4
  241. package/src/lib/validators/traceability-check.js +85 -129
  242. package/src/lib/validators/validation-runner.js +8 -88
  243. package/src/lib/validators/verify-runner.js +134 -301
  244. package/src/lib/worktree/docker-audit.js +1 -2
  245. package/src/lib/worktree/fleet-scanner.js +25 -38
  246. package/src/scripts/setup-infra.js +42 -22
  247. package/src/utils/agents-installer.js +92 -13
  248. package/src/utils/claude-settings-manager.js +0 -35
  249. package/src/utils/file-copier.js +34 -6
  250. package/src/utils/hooks-installer.js +16 -9
  251. package/src/utils/skills-installer.js +1 -2
  252. package/framework/commands/commit.md +0 -166
  253. package/framework/evals/trace-schema.md +0 -67
  254. package/framework/hooks/claude-code/core/tasks-json-guard.js +0 -83
  255. package/framework/hooks/claude-code/core/trace-autogen.js +0 -277
  256. package/framework/hooks/git/pre-commit/specs.sh +0 -50
  257. package/framework/hooks/shared/tasks-validator.js +0 -111
  258. package/framework/rubrics/backend.json +0 -41
  259. package/framework/rubrics/default.json +0 -36
  260. package/framework/rubrics/frontend.json +0 -36
  261. package/framework/rules/morph-task-tracking.md +0 -54
  262. package/framework/rules/morph-workflow.md +0 -244
  263. package/framework/schemas/tasks.schema.json +0 -79
  264. package/framework/skills/core/morph-brainstorming/SKILL.md +0 -161
  265. package/framework/skills/core/morph-implement/SKILL.md +0 -194
  266. package/framework/skills/core/morph-proposal/SKILL.md +0 -152
  267. package/framework/skills/core/morph-stack-scan/SKILL.md +0 -145
  268. package/framework/templates/docs/proposal.md +0 -192
  269. package/framework/templates/docs/spec.md +0 -57
  270. package/framework/templates/docs/ui-components.md +0 -52
  271. package/framework/templates/docs/ui-design-system.md +0 -76
  272. package/framework/templates/docs/ui-flows.md +0 -167
  273. package/framework/templates/examples/spec-examples.md +0 -91
  274. package/framework/templates/feature/decisions.md +0 -124
  275. package/framework/templates/feature/recap.md +0 -145
  276. package/framework/templates/project/validate.js +0 -97
  277. package/framework/templates/tasks.template.json +0 -17
  278. package/src/commands/state/usecase.js +0 -143
  279. package/src/commands/tasks/dag.js +0 -181
  280. package/src/dashboard/app/pages/Rubrics.jsx +0 -97
  281. package/src/dashboard/scanner/rubrics-scanner.js +0 -12
  282. package/src/lib/agents/output-collector.js +0 -76
  283. package/src/lib/evaluator-report.js +0 -91
  284. package/src/lib/specs/acervo-format.js +0 -70
  285. package/src/lib/specs/acervo-lifecycle.js +0 -264
  286. package/src/lib/specs/done-criteria-check.js +0 -200
  287. package/src/lib/specs/usecase-check.js +0 -301
  288. package/src/lib/specs/usecase-promoter.js +0 -301
  289. package/src/lib/specs/usecase-registry.js +0 -237
  290. package/src/lib/tasks/dispatch-planner.js +0 -319
  291. package/src/lib/tasks/mermaid-renderer.js +0 -132
  292. package/src/lib/tasks/task-classifier.js +0 -30
  293. package/src/lib/tasks/task-parser.js +0 -209
  294. package/src/lib/tasks/tasks-json-parser.js +0 -296
  295. package/src/lib/tasks/test-scope.js +0 -597
  296. package/src/lib/validators/architecture/architecture-validator.js +0 -270
  297. package/src/lib/validators/architecture/index.js +0 -7
  298. package/src/lib/validators/css/css-validator.js +0 -340
  299. package/src/lib/validators/css/index.js +0 -7
  300. package/src/lib/validators/design-system/design-system-validator.js +0 -237
  301. package/src/lib/validators/design-system/index.js +0 -7
  302. package/src/lib/validators/score-aggregator.js +0 -244
  303. package/src/lib/validators/ui/index.js +0 -7
  304. package/src/lib/validators/ui/ui-contrast-validator.js +0 -422
@@ -8,6 +8,7 @@
8
8
  import { readFileSync, writeFileSync, renameSync, unlinkSync, existsSync, mkdirSync, rmdirSync, statSync, readdirSync } from 'fs';
9
9
  import { join, dirname } from 'path';
10
10
  import { getAllOutputPaths, getOutputPath } from '../paths/output-schema.js';
11
+ import { derivePhaseFrom, diskArtifactProbe } from '../../../framework/hooks/shared/state-reader.js';
11
12
 
12
13
  const STATE_FILE_NAME = '.morph/state.json';
13
14
  const FEATURES_DIR_NAME = '.morph/features';
@@ -156,56 +157,19 @@ function scaffoldState() {
156
157
  };
157
158
  }
158
159
  /**
159
- * Derive current phase from filesystem.
160
- *
161
- * Walks the phase map in descending order and returns the first phase whose
162
- * CANONICAL ARTIFACT exists. An empty folder is not enough — `mkdir 2-plan/`
163
- * does not count as "in plan phase" until `spec.md` (the first canonical
164
- * plan-phase output) lands. If no canonical artifact is found anywhere,
165
- * returns `'proposal'` (the starting phase).
166
- *
167
- * This avoids the chicken-and-egg problem where the agent pre-creates all
168
- * phase folders, the derived phase jumps to the highest one, and
169
- * `enforce-phase-writes` then blocks the agent from writing back to the
170
- * prior phase folder.
160
+ * Derive current phase from filesystem — delegates to the hook-side rule
161
+ * (`derivePhaseFrom`) so the CLI and the hooks never disagree on a feature.
171
162
  *
172
163
  * @param {string} featurePath - Absolute path to .morph/features/{feature}/
173
- * @returns {string} Phase name: 'review' | 'implement' | 'plan' | 'uiux' | 'proposal'
164
+ * @returns {string} Phase name: 'review' | 'implement' | 'uiux' | 'plan'
174
165
  */
175
- const PHASE_INDEX = { proposal: 0, uiux: 1, plan: 2, implement: 3, review: 4 };
176
-
177
- /** Phase implied purely by approved gates (mirrors hook-side gateImpliedPhase). */
178
- function gateImpliedPhaseFromGates(gates) {
179
- const ok = (g) => gates?.[g]?.approved === true;
180
- if (ok('review')) return 'review';
181
- if (ok('plan')) return 'implement';
182
- if (ok('uiux')) return 'plan';
183
- return 'proposal';
184
- }
185
-
186
166
  export function derivePhase(featurePath) {
187
- const phaseMap = [
188
- ['4-review', 'review', 'review-report.md'],
189
- ['3-implement', 'implement', 'recap.md'],
190
- ['2-plan', 'plan', 'spec.md'],
191
- ['1-design', 'uiux', 'design-system.md'],
192
- ['0-proposal', 'proposal', 'proposal.md'],
193
- ];
194
- let artifactPhase = 'proposal';
195
- for (const [folder, phase, canonical] of phaseMap) {
196
- if (existsSync(join(featurePath, folder, canonical))) { artifactPhase = phase; break; }
197
- }
198
-
199
- // Gate-aware (same rule as the hook-side derivePhaseForFeature): an approved
200
- // gate advances the phase before the next phase's canonical artifact exists,
201
- // so the agent can actually write that first artifact.
202
- let gates = null;
167
+ let feature = null;
203
168
  try {
204
169
  const fjPath = join(featurePath, 'feature.json');
205
- if (existsSync(fjPath)) gates = JSON.parse(readFileSync(fjPath, 'utf8'))?.approvalGates;
206
- } catch { gates = null; }
207
- const implied = gateImpliedPhaseFromGates(gates);
208
- return PHASE_INDEX[implied] > PHASE_INDEX[artifactPhase] ? implied : artifactPhase;
170
+ if (existsSync(fjPath)) feature = JSON.parse(readFileSync(fjPath, 'utf8'));
171
+ } catch { feature = null; }
172
+ return derivePhaseFrom(feature, diskArtifactProbe(featurePath));
209
173
  }
210
174
 
211
175
  /**
@@ -498,7 +462,7 @@ export function getFeature(featureName) {
498
462
  /**
499
463
  * Create or get feature with default structure.
500
464
  * v5: every feature follows the fixed phase sequence
501
- * (proposal → uiux → plan → implement → review). No workflow selection.
465
+ * (plan → [uiux] → implement → review). No workflow selection.
502
466
  * @param {string} featureName - Feature name
503
467
  * @returns {Promise<Object>} Feature object
504
468
  */
@@ -511,17 +475,10 @@ async function ensureFeature(featureName) {
511
475
  createdAt: new Date().toISOString(),
512
476
  updatedAt: new Date().toISOString(),
513
477
  approvalGates: {
514
- proposal: { approved: false, timestamp: null, approvedBy: null },
515
- uiux: { approved: false, timestamp: null, approvedBy: null },
516
478
  plan: { approved: false, timestamp: null, approvedBy: null },
479
+ uiux: { approved: false, timestamp: null, approvedBy: null },
517
480
  review: { approved: false, timestamp: null, approvedBy: null }
518
481
  },
519
- tasks: {
520
- total: 0,
521
- completed: 0,
522
- inProgress: 0,
523
- pending: 0
524
- },
525
482
  checkpoints: [],
526
483
  trustConfig: {},
527
484
  contextBundles: [],
@@ -575,18 +532,11 @@ export async function createFeature(featureName, options = {}) {
575
532
  createdAt: now,
576
533
  updatedAt: now,
577
534
  approvalGates: {
578
- proposal: { approved: false, timestamp: null, approvedBy: null },
579
- uiux: { approved: false, timestamp: null, approvedBy: null },
580
535
  plan: { approved: false, timestamp: null, approvedBy: null },
536
+ uiux: { approved: false, timestamp: null, approvedBy: null },
581
537
  review: { approved: false, timestamp: null, approvedBy: null }
582
538
  },
583
539
  gateDecisions: {},
584
- tasks: {
585
- total: 0,
586
- completed: 0,
587
- inProgress: 0,
588
- pending: 0
589
- },
590
540
  checkpoints: [],
591
541
  trustConfig: {},
592
542
  contextBundles: [],
@@ -603,7 +553,7 @@ export async function createFeature(featureName, options = {}) {
603
553
  }
604
554
 
605
555
  /**
606
- * Update feature property (supports nested keys like "tasks.completed")
556
+ * Update feature property (supports nested keys like "approvalGates.plan.approved")
607
557
  * @param {string} featureName - Feature name
608
558
  * @param {string} key - Property key (supports dot notation)
609
559
  * @param {any} value - Value to set
@@ -657,36 +607,6 @@ export async function updateFeatureMultiple(featureName, updates) {
657
607
  saveState(state);
658
608
  }
659
609
 
660
- /**
661
- * Add checkpoint to feature
662
- * @param {string} featureName - Feature name
663
- * @param {string} note - Checkpoint note
664
- * @returns {Object} Checkpoint object
665
- */
666
- export async function addCheckpoint(featureName, note) {
667
- await ensureFeature(featureName);
668
- const state = loadState();
669
- const feature = state.features[featureName];
670
-
671
- const checkpoint = {
672
- passed: true,
673
- checkpointNum: feature.checkpoints.length + 1,
674
- timestamp: new Date().toISOString(),
675
- phase: feature.phase || 'proposal',
676
- results: [],
677
- summary: {
678
- note: note,
679
- completedTasks: feature.tasks.completed
680
- }
681
- };
682
-
683
- feature.checkpoints.push(checkpoint);
684
- feature.updatedAt = new Date().toISOString();
685
-
686
- saveState(state);
687
- return checkpoint;
688
- }
689
-
690
610
  /**
691
611
  * Normalize output type from kebab-case to camelCase (BUG-002 fix - Enhanced)
692
612
  * Supports both kebab-case and camelCase input formats for all output types
@@ -781,7 +701,7 @@ function findClosestMatch(inputType, validTypes) {
781
701
  /**
782
702
  * Mark output as created
783
703
  * @param {string} featureName - Feature name
784
- * @param {string} outputType - Output type (proposal, spec, tasks, etc.)
704
+ * @param {string} outputType - Output type (plan, checks, verifierReport, etc.)
785
705
  */
786
706
  export async function markOutput(featureName, outputType) {
787
707
  await ensureFeature(featureName);
@@ -860,7 +780,7 @@ export async function trackFileChange(featureName, filePath, action, phase) {
860
780
  state.features[featureName].fileChanges.push({
861
781
  path: filePath,
862
782
  action,
863
- phase: phase || state.features[featureName].phase || 'proposal',
783
+ phase: phase || state.features[featureName].phase || 'plan',
864
784
  timestamp: new Date().toISOString()
865
785
  });
866
786
 
@@ -968,7 +888,7 @@ export function getSummary() {
968
888
  /**
969
889
  * Set approval gate status
970
890
  * @param {string} featureName - Feature name
971
- * @param {string} gate - Gate name (proposal, uiux, plan, review)
891
+ * @param {string} gate - Gate name (plan, uiux, review)
972
892
  * @param {boolean} approved - Approval status
973
893
  * @param {Object} metadata - Additional metadata (approvedBy, reason, etc.)
974
894
  */
@@ -978,9 +898,8 @@ export async function setApprovalGate(featureName, gate, approved, metadata = {}
978
898
 
979
899
  if (!feature.approvalGates) {
980
900
  feature.approvalGates = {
981
- proposal: { approved: false, timestamp: null, approvedBy: null },
982
- uiux: { approved: false, timestamp: null, approvedBy: null },
983
901
  plan: { approved: false, timestamp: null, approvedBy: null },
902
+ uiux: { approved: false, timestamp: null, approvedBy: null },
984
903
  review: { approved: false, timestamp: null, approvedBy: null }
985
904
  };
986
905
  }
@@ -1026,7 +945,7 @@ export function isPendingApproval(featureName) {
1026
945
  return false;
1027
946
  }
1028
947
 
1029
- const currentPhase = feature.phase || 'proposal';
948
+ const currentPhase = feature.phase || 'plan';
1030
949
 
1031
950
  // Check if current phase has an approval gate
1032
951
  const phaseGateMap = {
@@ -76,7 +76,7 @@ export function getAllTemplates(projectPath = null) {
76
76
  /**
77
77
  * Get template by ID.
78
78
  *
79
- * @param {string} templateId - Template identifier (e.g., 'proposal', 'spec')
79
+ * @param {string} templateId - Template identifier (e.g., 'plan')
80
80
  * @param {string} [projectPath] - Optional project path
81
81
  * @returns {Object|null} Template object or null if not found
82
82
  */
@@ -100,7 +100,7 @@ export function getTemplatesByCategory(category, projectPath = null) {
100
100
  /**
101
101
  * Get templates by phase.
102
102
  *
103
- * @param {string} phase - Phase name (e.g., 'proposal', 'design', 'implement')
103
+ * @param {string} phase - Phase name (e.g., 'plan', 'uiux', 'implement')
104
104
  * @param {string} [projectPath] - Optional project path
105
105
  * @returns {Array} Filtered template array
106
106
  */
@@ -0,0 +1,22 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
2
+ import { dirname, join } from 'path';
3
+ import { getTemplateById, resolveFrameworkTemplatePath } from './template-registry.js';
4
+
5
+ /** The project-local override (same relative path as in the package) wins over the package copy. */
6
+ export function templateSourcePath(templateId, cwd = process.cwd()) {
7
+ const template = getTemplateById(templateId);
8
+ const local = template ? join(cwd, '.morph', 'framework', 'templates', template.path) : null;
9
+ return local && existsSync(local) ? local : resolveFrameworkTemplatePath(templateId);
10
+ }
11
+
12
+ /** @returns {{ path: string, written: boolean }} `written: false` when the file already existed. */
13
+ export function writeIfAbsent(path, content) {
14
+ mkdirSync(dirname(path), { recursive: true });
15
+ try {
16
+ writeFileSync(path, content, { encoding: 'utf8', flag: 'wx' });
17
+ return { path, written: true };
18
+ } catch (err) {
19
+ if (err.code === 'EEXIST') return { path, written: false };
20
+ throw err;
21
+ }
22
+ }
@@ -13,7 +13,7 @@
13
13
  * Fields per type:
14
14
  * label - Human-readable name
15
15
  * scaffold - Phase folders created at feature birth (subset of
16
- * 0-proposal/1-design/2-plan/3-implement/4-review)
16
+ * 2-plan/1-design/3-implement/4-review)
17
17
  * skippedGates - Gates stamped `policy:{type}`-approved at birth
18
18
  * instead of waiting for human approval
19
19
  * forcedPauseGates - Gates that ALWAYS pause for a human, regardless of
@@ -27,29 +27,29 @@ export const POLICY_APPROVER_PREFIX = 'policy:';
27
27
  export const WORK_TYPES = {
28
28
  feature: {
29
29
  label: 'Feature',
30
- scaffold: ['0-proposal'],
30
+ scaffold: ['2-plan'],
31
31
  skippedGates: [],
32
32
  forcedPauseGates: [],
33
- entrySkill: 'morph-proposal',
33
+ entrySkill: 'morph-plan',
34
34
  },
35
35
  bug: {
36
36
  label: 'Bug fix',
37
- scaffold: ['0-proposal'],
37
+ scaffold: ['2-plan'],
38
38
  skippedGates: [],
39
39
  forcedPauseGates: [],
40
- entrySkill: 'morph-proposal',
40
+ entrySkill: 'morph-plan',
41
41
  },
42
42
  chore: {
43
43
  label: 'Chore',
44
- scaffold: ['0-proposal', '2-plan', '3-implement'],
45
- skippedGates: ['proposal', 'plan'],
44
+ scaffold: ['2-plan', '3-implement'],
45
+ skippedGates: ['plan'],
46
46
  forcedPauseGates: [],
47
- entrySkill: 'morph-proposal',
47
+ entrySkill: 'morph-plan',
48
48
  },
49
49
  hotfix: {
50
50
  label: 'Hotfix',
51
- scaffold: ['0-proposal', '2-plan', '3-implement'],
52
- skippedGates: ['proposal', 'plan'],
51
+ scaffold: ['2-plan', '3-implement'],
52
+ skippedGates: ['plan'],
53
53
  forcedPauseGates: ['review'],
54
54
  entrySkill: 'morph-hotfix',
55
55
  },
@@ -14,7 +14,6 @@ import SkillsLibrary from './pages/SkillsLibrary.jsx';
14
14
  import RulesMap from './pages/RulesMap.jsx';
15
15
  import Standards from './pages/Standards.jsx';
16
16
  import Guide from './pages/Guide.jsx';
17
- import Rubrics from './pages/Rubrics.jsx';
18
17
  import { useNow } from './hooks/usePref.js';
19
18
  import { useProjects, useCurrentProject, projectHref } from './lib/project.js';
20
19
 
@@ -77,7 +76,6 @@ export default function App() {
77
76
  <Route path="/p/:project/activity" element={<Activity />} />
78
77
  <Route path="/guide" element={<Guide />} />
79
78
  <Route path="/guide/:doc" element={<Guide />} />
80
- <Route path="/rubrics" element={<Rubrics />} />
81
79
  <Route path="/agents" element={<AgentMap />} />
82
80
  <Route path="/phases" element={<PhasePipeline />} />
83
81
  <Route path="/hooks" element={<HookInspector />} />
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useState } from 'react';
2
2
  import { Link } from 'react-router-dom';
3
3
  import {
4
- ChatCircleText, Question, BookOpenText, PaperPlaneTilt, ArrowBendDownLeft, CheckSquare, ShieldCheck, Flag, WarningOctagon,
4
+ ChatCircleText, Question, BookOpenText, PaperPlaneTilt, ArrowBendDownLeft, ShieldCheck, Flag, WarningOctagon,
5
5
  PencilSimpleLine, Eye, TerminalWindow, Wrench,
6
6
  } from '@phosphor-icons/react';
7
7
  import { useMorphQuery } from '../hooks/useMorphQuery.js';
@@ -16,7 +16,6 @@ export const KIND_META = {
16
16
  skill: { label: 'Skills', icon: BookOpenText },
17
17
  dispatch: { label: 'Despachos', icon: PaperPlaneTilt },
18
18
  handback: { label: 'Retornos', icon: ArrowBendDownLeft },
19
- task: { label: 'Tasks', icon: CheckSquare },
20
19
  verify: { label: 'Verify', icon: ShieldCheck },
21
20
  gate: { label: 'Gates', icon: Flag },
22
21
  failure: { label: 'Falhas', icon: WarningOctagon },
@@ -25,7 +24,7 @@ export const KIND_META = {
25
24
  command: { label: 'Comandos', icon: TerminalWindow },
26
25
  tool: { label: 'Outras tools', icon: Wrench },
27
26
  };
28
- const DEFAULT = ['prompt', 'question', 'skill', 'dispatch', 'handback', 'task', 'verify', 'gate', 'failure'];
27
+ const DEFAULT = ['prompt', 'question', 'skill', 'dispatch', 'handback', 'verify', 'gate', 'failure'];
29
28
 
30
29
  const NODE_TONE = { pass: 'text-[var(--color-ok)]', fail: 'text-[var(--color-bad)]', skip: 'text-[var(--color-faint)]' };
31
30
 
@@ -8,13 +8,13 @@ import { useMorphQuery } from '../hooks/useMorphQuery.js';
8
8
  import { apiBase, projectHref, featureHref } from '../lib/project.js';
9
9
 
10
10
  const KIND_LABEL = {
11
- page: 'Página', project: 'Projeto', feature: 'Feature', task: 'Task', skill: 'Skill', persona: 'Persona',
12
- standard: 'Standard', rule: 'Rule', hook: 'Hook', guide: 'Guia', rubric: 'Rubrica',
11
+ page: 'Página', project: 'Projeto', feature: 'Feature', slice: 'Fatia', skill: 'Skill', persona: 'Persona',
12
+ standard: 'Standard', rule: 'Rule', hook: 'Hook', guide: 'Guia',
13
13
  };
14
14
 
15
15
  const PAGES = [
16
16
  ['Portfólio', '/'], ['Guia', '/guide'], ['Fases', '/phases'], ['Skills', '/skills'],
17
- ['Personas', '/agents'], ['Standards', '/standards'], ['Rules', '/rules'], ['Hooks', '/hooks'], ['Rubricas', '/rubrics'],
17
+ ['Personas', '/agents'], ['Standards', '/standards'], ['Rules', '/rules'], ['Hooks', '/hooks'],
18
18
  ];
19
19
 
20
20
  /** Everything the framework knows that has a page — built once. */
@@ -35,7 +35,6 @@ function knowledgeIndex() {
35
35
  out.push({ kind: 'guide', title: h.text, hint: d.title, to: `/guide/${d.id}#${h.slug}`, hay: `${h.text} ${d.title}` });
36
36
  }
37
37
  }
38
- for (const r of morphData.docs?.rubrics || []) out.push({ kind: 'rubric', title: r.title, to: `/rubrics?sel=${encodeURIComponent(`dim:${r.id}`)}`, hay: r.title });
39
38
  return out;
40
39
  }
41
40
 
@@ -44,7 +43,7 @@ function projectIndex(portfolio) {
44
43
  }
45
44
 
46
45
  /**
47
- * Features and their tasks. `projectName` is set for another project's
46
+ * Features and their slices. `projectName` is set for another project's
48
47
  * features, so a hit says where it lives.
49
48
  */
50
49
  function featureIndex(project, features, projectName = null) {
@@ -52,8 +51,8 @@ function featureIndex(project, features, projectName = null) {
52
51
  const where = (text) => (projectName ? (text ? `${projectName}: ${text}` : projectName) : text);
53
52
  for (const f of features || []) {
54
53
  out.push({ kind: 'feature', title: f.name, hint: where(f.description), to: featureHref(project, f.name), hay: `${f.name} ${f.description || ''} ${projectName || ''}` });
55
- for (const t of f.taskIndex || []) {
56
- out.push({ kind: 'task', title: `${t.id} ${t.title}`, hint: where(f.name), to: featureHref(project, f.name, '?tab=tasks'), hay: `${t.id} ${t.title} ${f.name} ${projectName || ''}` });
54
+ for (const sl of f.sliceIndex || []) {
55
+ out.push({ kind: 'slice', title: `${sl.id} ${sl.title}`, hint: where(f.name), to: featureHref(project, f.name, '?tab=slices'), hay: `${sl.id} ${sl.title} ${f.name} ${projectName || ''}` });
57
56
  }
58
57
  }
59
58
  return out;
@@ -120,7 +119,7 @@ export default function CommandPalette({ open, onClose, portfolio, project }) {
120
119
  value={query}
121
120
  onChange={(e) => setQuery(e.target.value)}
122
121
  onKeyDown={onKey}
123
- placeholder="Buscar features, tasks, skills, personas, standards, seções do guia…"
122
+ placeholder="Buscar features, fatias, skills, personas, standards, seções do guia…"
124
123
  className="w-full bg-transparent text-base text-[var(--color-fg)] outline-none focus-visible:outline-none placeholder:text-[var(--color-faint)]"
125
124
  aria-controls="palette-results"
126
125
  aria-activedescendant={results[active] ? `palette-${active}` : undefined}
@@ -16,12 +16,11 @@ export function entityHref(kind, id) {
16
16
  case 'hook': return q('hooks');
17
17
  case 'phase': return q('phases');
18
18
  case 'guide': return `/guide/${encodeURIComponent(id)}`;
19
- case 'rubric': return q('rubrics');
20
19
  default: return '#';
21
20
  }
22
21
  }
23
22
 
24
- /** `standards/backend/dotnet/testing.md` (as tasks.json cites it) → the registry `path`. */
23
+ // `standards/backend/dotnet/testing.md` (as a plan may cite it) → the registry `path`.
25
24
  export function standardKey(ref) {
26
25
  return String(ref).replace(/^\.?\/?(\.morph\/framework\/)?standards\//, '');
27
26
  }
@@ -7,7 +7,7 @@ const REMARK = [remarkGfm];
7
7
  const REHYPE = [rehypeSlug];
8
8
 
9
9
  /** Frontmatter keys worth showing, in the order a reader wants them. */
10
- const META_ORDER = ['name', 'description', 'when-to-invoke', 'user-invokable', 'stacks', 'version', 'cliVersion'];
10
+ const META_ORDER = ['name', 'description', 'when_to_use', 'user-invocable', 'stacks', 'version', 'cliVersion'];
11
11
 
12
12
  function MetaBlock({ meta }) {
13
13
  const keys = Object.keys(meta).sort((a, b) => {
@@ -1,6 +1,6 @@
1
1
  import { NavLink, useLocation, useNavigate } from 'react-router-dom';
2
2
  import {
3
- MagnifyingGlass, SquaresFour, Kanban, Pulse, BookOpen, FlowArrow, PuzzlePiece, UsersThree, Books, Ruler, Plug, Scales,
3
+ MagnifyingGlass, SquaresFour, Kanban, Pulse, BookOpen, FlowArrow, PuzzlePiece, UsersThree, Books, Ruler, Plug,
4
4
  } from '@phosphor-icons/react';
5
5
  import { projectHref } from '../lib/project.js';
6
6
 
@@ -12,7 +12,6 @@ const KNOWLEDGE = [
12
12
  { to: '/standards', label: 'Standards', icon: Books },
13
13
  { to: '/rules', label: 'Rules', icon: Ruler },
14
14
  { to: '/hooks', label: 'Hooks', icon: Plug },
15
- { to: '/rubrics', label: 'Rubricas', icon: Scales },
16
15
  ];
17
16
 
18
17
  function Badge({ pulse }) {
@@ -5,7 +5,7 @@ import { useEffect, useRef, useState } from 'react';
5
5
  * reports that the project's `.morph/` changed in the given scope.
6
6
  *
7
7
  * `scope` matches the server's invalidation: 'features' (feature.json,
8
- * tasks.json, artifacts) or 'activity' (events.jsonl). A refetch keeps the old
8
+ * slice reports, artifacts) or 'activity' (events.jsonl). A refetch keeps the old
9
9
  * data on screen until the new one arrives — no flash of "loading" while an
10
10
  * agent is working.
11
11
  *
@@ -6,9 +6,8 @@
6
6
  import morphData from 'virtual:morph-data';
7
7
 
8
8
  const LABELS = {
9
- proposal: 'Proposta',
10
- uiux: 'UI/UX',
11
9
  plan: 'Plano',
10
+ uiux: 'UI/UX',
12
11
  implement: 'Implementação',
13
12
  review: 'Revisão',
14
13
  };
@@ -29,9 +28,8 @@ export function phaseMeta(id) {
29
28
  }
30
29
 
31
30
  export const GATE_LABEL = {
32
- proposal: 'Gate 1 (proposta)',
31
+ plan: 'Gate do plano',
33
32
  uiux: 'Gate UI/UX',
34
- plan: 'Gate 2 (plano)',
35
33
  review: 'Gate 3 (revisão)',
36
34
  };
37
35
 
@@ -13,7 +13,7 @@ export default function Activity() {
13
13
  <h1 className="mt-1 text-4xl font-semibold tracking-tight">Atividade</h1>
14
14
  <p className="mt-3 max-w-2xl text-sm leading-relaxed text-[var(--color-dim)]">
15
15
  O que o Claude fez no projeto, contado a partir da telemetria dos hooks: suas mensagens, as skills carregadas,
16
- os sub-agents despachados, as tasks, os verifies e os gates. Atualiza sozinho enquanto ele trabalha.
16
+ os sub-agents despachados, os verifies e os gates. Atualiza sozinho enquanto ele trabalha.
17
17
  </p>
18
18
  </header>
19
19
  <div className="rise-2 bezel">