@polymorphism-tech/morph-spec 8.47.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 (222) hide show
  1. package/CLAUDE.md +48 -39
  2. package/README.md +3 -4
  3. package/bin/morph-spec.js +37 -51
  4. package/bin/validate.js +3 -111
  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 +41 -101
  9. package/framework/MORPH.md +95 -252
  10. package/framework/agents.json +75 -18
  11. package/framework/commands/morph-apply.md +5 -28
  12. package/framework/commands/morph-archive.md +1 -1
  13. package/framework/commands/morph-hotfix.md +8 -8
  14. package/framework/commands/morph-infra.md +1 -1
  15. package/framework/commands/morph-preflight.md +2 -3
  16. package/framework/commands/morph-proposal.md +2 -50
  17. package/framework/commands/morph-status.md +3 -3
  18. package/framework/docs/CLI.md +585 -286
  19. package/framework/evals/review-checklist.md +82 -41
  20. package/framework/hooks/README.md +10 -11
  21. package/framework/hooks/claude-code/core/comment-guard.js +1 -1
  22. package/framework/hooks/claude-code/core/denylist.json +33 -3
  23. package/framework/hooks/claude-code/core/enforce-phase-writes.js +16 -20
  24. package/framework/hooks/claude-code/core/gate-guard.js +2 -11
  25. package/framework/hooks/claude-code/core/pre-bash-denylist.js +38 -0
  26. package/framework/hooks/claude-code/core/protect-spec-files.js +30 -242
  27. package/framework/hooks/claude-code/core/state-sync.js +7 -21
  28. package/framework/hooks/claude-code/core/telemetry-log.js +3 -3
  29. package/framework/hooks/claude-code/core/validate-completion.js +33 -97
  30. package/framework/hooks/claude-code/core/warn-bash-source-write.js +31 -0
  31. package/framework/hooks/claude-code/core/worktree-context.js +5 -4
  32. package/framework/hooks/claude-code/statusline.py +55 -41
  33. package/framework/hooks/package.json +3 -0
  34. package/framework/hooks/shared/activity-logger.js +1 -1
  35. package/framework/hooks/shared/build-check.js +10 -6
  36. package/framework/hooks/shared/command-tokens.js +169 -0
  37. package/framework/hooks/shared/comment-rules.js +1 -1
  38. package/framework/hooks/shared/comment-scanner.js +10 -23
  39. package/framework/hooks/shared/comment-stripper.js +1 -1
  40. package/framework/hooks/shared/e2e-check.js +64 -27
  41. package/framework/hooks/shared/errata.js +72 -0
  42. package/framework/hooks/shared/feature-locator.js +1 -1
  43. package/framework/hooks/shared/frontend-locations.js +6 -0
  44. package/framework/hooks/shared/gate-question.js +18 -0
  45. package/framework/hooks/shared/phase-utils.js +15 -32
  46. package/framework/hooks/shared/slice-progress.js +118 -0
  47. package/framework/hooks/shared/spawn-command.js +23 -0
  48. package/framework/hooks/shared/state-reader.js +61 -87
  49. package/framework/hooks/shared/state-writer.js +2 -3
  50. package/framework/mcp/registry.json +3 -4
  51. package/framework/phases.json +23 -39
  52. package/framework/schemas/config.schema.json +14 -9
  53. package/framework/schemas/feature.schema.json +15 -50
  54. package/framework/skills/README.md +3 -4
  55. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  56. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  57. package/framework/skills/core/morph-apply/SKILL.md +149 -222
  58. package/framework/skills/core/morph-hotfix/SKILL.md +33 -42
  59. package/framework/skills/core/morph-machine/SKILL.md +2 -2
  60. package/framework/skills/core/morph-media/SKILL.md +1 -1
  61. package/framework/skills/core/morph-plan/SKILL.md +137 -299
  62. package/framework/skills/core/morph-review/SKILL.md +111 -136
  63. package/framework/skills/core/morph-standards/SKILL.md +27 -39
  64. package/framework/skills/core/morph-uiux/SKILL.md +77 -152
  65. package/framework/standards/STANDARDS.json +86 -1218
  66. package/framework/standards/STANDARDS.meta.json +1305 -0
  67. package/framework/standards/ai-agents/evals-with-cache.md +1 -2
  68. package/framework/standards/ai-agents/setup.md +1 -1
  69. package/framework/standards/architecture/code-comments.md +6 -6
  70. package/framework/standards/integration/mcp/mcp-tools.md +7 -7
  71. package/framework/templates/README.md +2 -3
  72. package/framework/templates/REGISTRY.json +6 -170
  73. package/framework/templates/docs/plan.md +72 -0
  74. package/framework/templates/dotnet/ai-kit/README.md +1 -9
  75. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +0 -10
  76. package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +1 -1
  77. package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +1 -1
  78. package/framework/templates/meta-prompts/squad-leaders/squad-leader.md +1 -1
  79. package/framework/templates/meta-prompts/validators/pre-commit-validator.md +3 -4
  80. package/package.json +1 -1
  81. package/src/commands/e2e/e2e.js +2 -2
  82. package/src/commands/observability/cost.js +18 -60
  83. package/src/commands/project/doctor-procs.js +1 -1
  84. package/src/commands/project/doctor.js +9 -9
  85. package/src/commands/project/fleet.js +4 -4
  86. package/src/commands/project/heavy.js +3 -3
  87. package/src/commands/project/init.js +4 -0
  88. package/src/commands/project/setup-infra-cmd.js +2 -1
  89. package/src/commands/project/stack-scan.js +58 -0
  90. package/src/commands/project/standards.js +79 -25
  91. package/src/commands/project/status.js +29 -69
  92. package/src/commands/project/update.js +17 -1
  93. package/src/commands/project/worktree.js +1 -1
  94. package/src/commands/state/advance.js +62 -46
  95. package/src/commands/state/approve.js +81 -141
  96. package/src/commands/state/archive.js +20 -84
  97. package/src/commands/state/auto-approval.js +68 -0
  98. package/src/commands/state/create.js +28 -1
  99. package/src/commands/state/delete.js +1 -1
  100. package/src/commands/state/finish.js +11 -23
  101. package/src/commands/state/gate-check.js +85 -84
  102. package/src/commands/state/gate-decision.js +6 -4
  103. package/src/commands/state/handoff.js +1 -1
  104. package/src/commands/state/list.js +9 -9
  105. package/src/commands/state/report-check.js +157 -311
  106. package/src/commands/state/retype.js +9 -3
  107. package/src/commands/validation/mutate.js +77 -14
  108. package/src/commands/validation/plan-check.js +81 -0
  109. package/src/commands/validation/validate-feature.js +60 -135
  110. package/src/commands/validation/verify.js +40 -72
  111. package/src/core/paths/output-schema.js +19 -66
  112. package/src/core/state/gate-order.js +5 -6
  113. package/src/core/state/lifecycle-audit.js +2 -2
  114. package/src/core/state/state-manager.js +17 -98
  115. package/src/core/templates/template-registry.js +2 -2
  116. package/src/core/templates/template-seed.js +22 -0
  117. package/src/core/work-types.js +10 -10
  118. package/src/dashboard/app/components/ActivityFeed.jsx +2 -3
  119. package/src/dashboard/app/components/CommandPalette.jsx +5 -5
  120. package/src/dashboard/app/components/EntityLink.jsx +1 -1
  121. package/src/dashboard/app/hooks/useMorphQuery.js +1 -1
  122. package/src/dashboard/app/lib/phases.js +2 -4
  123. package/src/dashboard/app/pages/Activity.jsx +1 -1
  124. package/src/dashboard/app/pages/FeatureDetail.jsx +139 -129
  125. package/src/dashboard/app/pages/Features.jsx +9 -9
  126. package/src/dashboard/app/pages/Guide.jsx +2 -2
  127. package/src/dashboard/app/pages/PhasePipeline.jsx +3 -4
  128. package/src/dashboard/app/pages/Standards.jsx +1 -1
  129. package/src/dashboard/scanner/activity-scanner.js +5 -15
  130. package/src/dashboard/scanner/agents-scanner.js +1 -1
  131. package/src/dashboard/scanner/docs-scanner.js +2 -2
  132. package/src/dashboard/scanner/features-scanner.js +95 -60
  133. package/src/dashboard/scanner/project-api.js +1 -1
  134. package/src/dashboard/scanner/standards-scanner.js +2 -1
  135. package/src/lib/ci/ci-verify.js +17 -1
  136. package/src/lib/ci/github-ci.js +1 -1
  137. package/src/lib/detectors/index.js +3 -8
  138. package/src/lib/generators/handoff-generator.js +34 -65
  139. package/src/lib/generators/settings-generator.js +11 -89
  140. package/src/lib/git/evidence-staleness.js +1 -1
  141. package/src/lib/git/tree-fingerprint.js +19 -7
  142. package/src/lib/git/tree-state.js +2 -2
  143. package/src/lib/heavy/cleanup.js +1 -5
  144. package/src/lib/installers/memory-installer.js +6 -8
  145. package/src/lib/mutation/commands.js +3 -2
  146. package/src/lib/{tasks/dotnet-test-introspection.js → mutation/dotnet-introspection.js} +17 -282
  147. package/src/lib/mutation/plan.js +14 -6
  148. package/src/lib/mutation/runner.js +1 -1
  149. package/src/lib/mutation/subset.js +46 -9
  150. package/src/lib/plan/artifact-vocabulary.js +60 -0
  151. package/src/lib/plan/checks.js +234 -0
  152. package/src/lib/plan/plan-parser.js +209 -0
  153. package/src/lib/plan/plan-template.js +18 -0
  154. package/src/lib/review-reports.js +222 -0
  155. package/src/lib/risk-detector.js +131 -140
  156. package/src/lib/specs/adr-index.js +50 -69
  157. package/src/lib/specs/design-seed.js +18 -0
  158. package/src/lib/specs/frontmatter.js +44 -0
  159. package/src/lib/specs/gfm-table.js +17 -0
  160. package/src/lib/specs/old-format.js +68 -0
  161. package/src/lib/specs/revocations.js +37 -95
  162. package/src/lib/specs/screen-checklist.js +18 -17
  163. package/src/lib/stack/dotnet-build-ignores.js +47 -0
  164. package/src/lib/stack/stack-scan.js +267 -0
  165. package/src/lib/standards/registry.js +43 -0
  166. package/src/lib/standards/sections.js +58 -0
  167. package/src/lib/tasks/eval-node.js +4 -12
  168. package/src/lib/tasks/test-nodes.js +1 -74
  169. package/src/lib/tasks/test-runner.js +75 -117
  170. package/src/lib/telemetry/metrics.js +8 -69
  171. package/src/lib/telemetry/telemetry-reader.js +5 -118
  172. package/src/lib/telemetry/verify-event.js +5 -7
  173. package/src/lib/validators/code-budget/code-budget-validator.js +1 -1
  174. package/src/lib/validators/contracts/contract-compliance-validator.js +2 -2
  175. package/src/lib/validators/reuse/reuse-validator.js +22 -45
  176. package/src/lib/validators/traceability-check.js +85 -129
  177. package/src/lib/validators/verify-runner.js +118 -235
  178. package/src/lib/worktree/docker-audit.js +1 -2
  179. package/src/lib/worktree/fleet-scanner.js +25 -38
  180. package/src/scripts/setup-infra.js +9 -0
  181. package/src/utils/agents-installer.js +76 -9
  182. package/src/utils/claude-settings-manager.js +0 -35
  183. package/src/utils/file-copier.js +27 -1
  184. package/src/utils/hooks-installer.js +16 -9
  185. package/src/utils/skills-installer.js +1 -2
  186. package/framework/evals/trace-schema.md +0 -67
  187. package/framework/hooks/claude-code/core/tasks-json-guard.js +0 -83
  188. package/framework/hooks/claude-code/core/trace-autogen.js +0 -277
  189. package/framework/hooks/git/pre-commit/specs.sh +0 -50
  190. package/framework/hooks/shared/tasks-validator.js +0 -111
  191. package/framework/rules/morph-task-tracking.md +0 -54
  192. package/framework/rules/morph-workflow.md +0 -244
  193. package/framework/schemas/tasks.schema.json +0 -79
  194. package/framework/skills/core/morph-brainstorming/SKILL.md +0 -161
  195. package/framework/skills/core/morph-implement/SKILL.md +0 -194
  196. package/framework/skills/core/morph-proposal/SKILL.md +0 -152
  197. package/framework/skills/core/morph-stack-scan/SKILL.md +0 -145
  198. package/framework/templates/docs/proposal.md +0 -192
  199. package/framework/templates/docs/spec.md +0 -57
  200. package/framework/templates/docs/ui-components.md +0 -52
  201. package/framework/templates/docs/ui-design-system.md +0 -76
  202. package/framework/templates/docs/ui-flows.md +0 -167
  203. package/framework/templates/examples/spec-examples.md +0 -91
  204. package/framework/templates/feature/decisions.md +0 -124
  205. package/framework/templates/feature/recap.md +0 -145
  206. package/framework/templates/tasks.template.json +0 -17
  207. package/src/commands/state/usecase.js +0 -143
  208. package/src/commands/tasks/dag.js +0 -181
  209. package/src/lib/agents/output-collector.js +0 -76
  210. package/src/lib/evaluator-report.js +0 -104
  211. package/src/lib/specs/acervo-format.js +0 -70
  212. package/src/lib/specs/acervo-lifecycle.js +0 -264
  213. package/src/lib/specs/done-criteria-check.js +0 -200
  214. package/src/lib/specs/usecase-check.js +0 -301
  215. package/src/lib/specs/usecase-promoter.js +0 -301
  216. package/src/lib/specs/usecase-registry.js +0 -237
  217. package/src/lib/tasks/dispatch-planner.js +0 -319
  218. package/src/lib/tasks/mermaid-renderer.js +0 -132
  219. package/src/lib/tasks/task-classifier.js +0 -30
  220. package/src/lib/tasks/task-parser.js +0 -209
  221. package/src/lib/tasks/tasks-json-parser.js +0 -296
  222. package/src/lib/tasks/test-scope.js +0 -597
@@ -23,25 +23,12 @@ export async function generateSettings(targetPath, detectedConfig, morphConfig =
23
23
  const claudeDir = join(targetPath, '.claude');
24
24
  const settingsPath = join(claudeDir, 'settings.local.json');
25
25
 
26
- // Read existing settings
27
- const existing = await readSettingsSafe(settingsPath);
28
-
29
- // Build stack-based permissions
30
- const stack = morphConfig?.project?.architecture || 'unknown';
31
- const permissions = buildPermissions(stack, detectedConfig);
32
-
33
- // Build generated settings
26
+ const existing = withoutLegacyPermissions(await readSettingsSafe(settingsPath));
34
27
  const generated = {};
35
28
 
36
- if (permissions.length > 0) {
37
- generated.permissions = permissions;
38
- }
39
-
40
- // Track what we manage
41
29
  const managed = {
42
- permissions_added: permissions,
43
30
  mcps_detected: detectedConfig.mcpServers.map(s => s.name),
44
- plugins_detected: detectedConfig.plugins.map(p => p.name),
31
+ plugins_detected: detectedConfig.plugins.map(p => (typeof p === 'string' ? p : p?.name)),
45
32
  generated_at: new Date().toISOString()
46
33
  };
47
34
 
@@ -58,44 +45,10 @@ export async function generateSettings(targetPath, detectedConfig, morphConfig =
58
45
 
59
46
  return {
60
47
  settingsPath,
61
- permissionsAdded: permissions.length,
62
48
  managed
63
49
  };
64
50
  }
65
51
 
66
- /**
67
- * Build permission rules based on detected stack
68
- * @param {string} stack - Detected project stack
69
- * @param {Object} detectedConfig - Detected Claude config
70
- * @returns {Array<string>} Permission patterns
71
- */
72
- export function buildPermissions(stack, detectedConfig = {}) {
73
- const permissions = [];
74
-
75
- // Stack-based permissions
76
- const stackPermissions = {
77
- nodejs: ['Bash(node:*)', 'Bash(npm:*)', 'Bash(npx:*)'],
78
- typescript: ['Bash(node:*)', 'Bash(npm:*)', 'Bash(npx:*)', 'Bash(tsc:*)'],
79
- nextjs: ['Bash(node:*)', 'Bash(npm:*)', 'Bash(npx:*)'],
80
- react: ['Bash(node:*)', 'Bash(npm:*)', 'Bash(npx:*)'],
81
- vue: ['Bash(node:*)', 'Bash(npm:*)', 'Bash(npx:*)'],
82
- dotnet: ['Bash(dotnet:*)', 'Bash(nuget:*)'],
83
- python: ['Bash(python:*)', 'Bash(pip:*)', 'Bash(pytest:*)'],
84
- go: ['Bash(go:*)']
85
- };
86
-
87
- if (stackPermissions[stack]) {
88
- permissions.push(...stackPermissions[stack]);
89
- }
90
-
91
- // morph-spec CLI always needs node/npx
92
- if (!permissions.includes('Bash(npx:*)')) {
93
- permissions.push('Bash(npx:*)');
94
- }
95
-
96
- return permissions;
97
- }
98
-
99
52
  /**
100
53
  * Deep merge settings without overwriting user entries
101
54
  * @param {Object} existing - Current settings.local.json
@@ -127,46 +80,6 @@ export function mergeSettings(existing, generated) {
127
80
  return result;
128
81
  }
129
82
 
130
- /**
131
- * Remove only morph-spec managed entries from settings
132
- * @param {string} settingsPath - Path to settings.local.json
133
- * @returns {Promise<Object>} Summary of what was removed
134
- */
135
- export async function resetMorphSettings(settingsPath) {
136
- if (!existsSync(settingsPath)) {
137
- return { removed: false, reason: 'file not found' };
138
- }
139
-
140
- const settings = await readSettingsSafe(settingsPath);
141
- const managed = settings[MORPH_MANAGED_KEY];
142
-
143
- if (!managed) {
144
- return { removed: false, reason: 'no _morph_managed section found' };
145
- }
146
-
147
- // Remove managed permissions
148
- if (managed.permissions_added && Array.isArray(settings.permissions)) {
149
- settings.permissions = settings.permissions.filter(
150
- p => !managed.permissions_added.includes(p)
151
- );
152
- if (settings.permissions.length === 0) {
153
- delete settings.permissions;
154
- }
155
- }
156
-
157
- // Remove the managed marker itself
158
- delete settings[MORPH_MANAGED_KEY];
159
-
160
- // Write back
161
- await writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
162
-
163
- return {
164
- removed: true,
165
- permissionsRemoved: managed.permissions_added || [],
166
- previouslyGenerated: managed.generated_at
167
- };
168
- }
169
-
170
83
  /**
171
84
  * Save integrations.json with detected config
172
85
  * @param {string} targetPath - Project root directory
@@ -198,6 +111,15 @@ export async function saveIntegrations(targetPath, detectedConfig) {
198
111
  // Helpers
199
112
  // ============================================================================
200
113
 
114
+ // Claude Code reads only `permissions: { allow, deny }`; a bare array (older generator) is ignored.
115
+ // Versões antigas gravavam regras curinga (node:*, npm:*, npx:*…) como array, forma que o
116
+ // Claude Code ignora: nunca valeram. Converter para { allow } as ligaria em silêncio.
117
+ function withoutLegacyPermissions(settings) {
118
+ if (!Array.isArray(settings.permissions)) return settings;
119
+ const { permissions, ...rest } = settings;
120
+ return rest;
121
+ }
122
+
201
123
  async function readSettingsSafe(settingsPath) {
202
124
  try {
203
125
  if (!existsSync(settingsPath)) return {};
@@ -7,7 +7,7 @@ const CONFIG_PATH = '.morph/config/config.json';
7
7
 
8
8
  const gitOut = (cwd, args) => execFileSync('git', args, { cwd, stdio: 'pipe', maxBuffer: 64 * 1024 * 1024 }).toString();
9
9
 
10
- function withoutBaseline(text) {
10
+ export function withoutBaseline(text) {
11
11
  const config = JSON.parse(text);
12
12
  if (Array.isArray(config?.project?.tests)) {
13
13
  for (const node of config.project.tests) delete node?.expectedCount;
@@ -1,15 +1,15 @@
1
1
  /**
2
- * A hash of what a verify run reads: the commit, the uncommitted changes and
3
- * the untracked files, plus the project's `config.json` (it names the test
4
- * commands). Everything else under `.morph/` stays out — verify itself writes
5
- * feature.json and the logs on every run, and counting that would make two
6
- * runs over the same code look different.
2
+ * A hash of what a verify run reads: the committed tree, the uncommitted changes and the
3
+ * untracked files, plus `config.json` without `expectedCount` (it names the test commands).
4
+ * The rest of `.morph/` stays out, as in `treeMovedSince`: committing verify's own
5
+ * bookkeeping must not make the same code look different.
7
6
  */
8
7
 
9
8
  import { execFileSync } from 'child_process';
10
9
  import { createHash } from 'crypto';
11
10
  import { existsSync, readFileSync, statSync } from 'fs';
12
11
  import { join } from 'path';
12
+ import { withoutBaseline } from './evidence-staleness.js';
13
13
 
14
14
  /** Pathspec for "the project minus its `.morph/` bookkeeping". */
15
15
  export const OUTSIDE_MORPH = ['--', '.', ':(exclude).morph'];
@@ -31,7 +31,11 @@ export function treeFingerprint(projectPath) {
31
31
  const hash = createHash('sha256');
32
32
  let head = null;
33
33
  try { head = git(projectPath, ['rev-parse', 'HEAD']).toString().trim(); } catch { /* no commit yet */ }
34
- hash.update(`head\0${head ?? 'no-commit'}\0`);
34
+ // Tree ids are content-addressed: the top-level entries minus .morph change only with code.
35
+ const tree = head
36
+ ? git(projectPath, ['ls-tree', '-z', 'HEAD']).toString().split('\0').filter((e) => e && e.split('\t')[1] !== '.morph')
37
+ : ['no-commit'];
38
+ hash.update(`tree\0${tree.join('\0')}\0`);
35
39
  // Before the first commit there is no HEAD to diff against: every file is
36
40
  // untracked, and the listing below covers them.
37
41
  if (head) hash.update(git(projectPath, ['diff', 'HEAD', '--binary', ...OUTSIDE_MORPH]));
@@ -50,9 +54,17 @@ export function treeFingerprint(projectPath) {
50
54
  }
51
55
  const config = join(projectPath, '.morph', 'config', 'config.json');
52
56
  hash.update('\0config\0');
53
- if (existsSync(config)) hash.update(readFileSync(config));
57
+ if (existsSync(config)) hash.update(normalizedConfig(readFileSync(config, 'utf8')));
54
58
  return hash.digest('hex');
55
59
  } catch {
56
60
  return null;
57
61
  }
58
62
  }
63
+
64
+ function normalizedConfig(text) {
65
+ try {
66
+ return JSON.stringify(withoutBaseline(text));
67
+ } catch {
68
+ return text;
69
+ }
70
+ }
@@ -11,7 +11,7 @@ import { OUTSIDE_MORPH, treeFingerprint, git as gitBuffer } from './tree-fingerp
11
11
  import { detectDefaultBranch } from './default-branch.js';
12
12
  import { resolveBaseRef } from './branch-classifier.js';
13
13
 
14
- /** What an evaluator writes next to a mutation it has not reverted yet. */
14
+ /** What the verifier writes next to a mutation it has not reverted yet. */
15
15
  export const MUTATION_MARKER = 'MUTACAO';
16
16
  const MAX_LISTED = 50;
17
17
  const MAX_COMMITS = 10;
@@ -50,7 +50,7 @@ function commitBlobs(cwd, commit, paths) {
50
50
 
51
51
  /**
52
52
  * What the tree is before a dispatch whose work must leave it unchanged (the
53
- * evaluator mutates and reverts): HEAD plus the blob of every file that
53
+ * verifier mutates and reverts): HEAD plus the blob of every file that
54
54
  * differs from it. Kept on disk, so a session that resumes after the agent
55
55
  * died compares against the tree before the dispatch, not its own start.
56
56
  * @returns {{ at: string, head: string|null, files: Object<string, string|null> }|null}
@@ -6,7 +6,6 @@ import { heavyDir, runExclusive } from '../../../framework/hooks/shared/heavy-sl
6
6
 
7
7
  const DOTNET_ACTIVE = /\bdotnet(?:\.exe)?["']?\s+(?:build|test|publish|pack|msbuild|restore|run|watch|vstest)\b/i;
8
8
  const IDLE_WORKER = /\/nodemode:\d|vbcscompiler|razorserver/i;
9
- const SHUTDOWN_SCOPES = new Set(['feature', 'e2e-down', 'prune']);
10
9
  const SHUTDOWN_TIMEOUT_MS = 30_000;
11
10
  const TAIL_CHARS = 400;
12
11
 
@@ -33,16 +32,13 @@ export function dotnetBusy(procs) {
33
32
  });
34
33
  }
35
34
 
36
- export function afterHeavyRun({ projectPath, config, scope, env = process.env, deps = {} }) {
35
+ export function afterHeavyRun({ projectPath, config, env = process.env, deps = {} }) {
37
36
  const {
38
37
  exec = defaultProcExec, list = listProcesses, dotnet = hasDotnet, exclusive = runExclusive,
39
38
  } = deps;
40
39
 
41
40
  if (!config.enabled) return { status: 'skipped', reason: 'semáforo desligado: sem ele nada prova que outra sessão não está compilando' };
42
41
  if (!config.shutdownBuildServer) return { status: 'skipped', reason: 'desligado em heavy.shutdownBuildServer' };
43
- if (!SHUTDOWN_SCOPES.has(scope)) {
44
- return { status: 'skipped', reason: 'escopo de task: o servidor de compilação segue quente para a próxima task' };
45
- }
46
42
  if (!dotnet(projectPath)) return { status: 'skipped', reason: 'projeto sem .NET' };
47
43
 
48
44
  const guarded = exclusive({
@@ -41,8 +41,7 @@ metadata:
41
41
  - \`.morph/framework/MORPH.md\` — NLH charter (read once per session)
42
42
  - \`.morph/framework/agents.json\` — 8 agents: 7 domain personas + 1 stage persona (\`scout\`, read-only)
43
43
  - \`.morph/framework/standards/STANDARDS.json\` — standards index (load on demand)
44
- - \`.morph/framework/schemas/tasks.schema.json\` — JSON Schema for tasks.json
45
- - \`.morph/features/{feature}/\` — feature artifacts: 0-proposal / 1-design / 2-plan / 3-implement / 4-review
44
+ - \`.morph/features/{feature}/\` — feature artifacts: 2-plan / 1-design / 3-implement / 4-review
46
45
  - \`.morph/context/\` — long-lived architectural context (design-system, decisions)
47
46
  - \`.morph/state.json\` — feature state (managed by state-sync hook; Edit fallback allowed)
48
47
 
@@ -50,8 +49,8 @@ metadata:
50
49
 
51
50
  | Command | Skill invoked |
52
51
  |---------|---------------|
53
- | \`/morph-proposal {feature}\` | \`Skill(morph-proposal)\` — brainstorming → Gate 1 → plan → Gate 2 |
54
- | \`/morph-apply {feature}\` | \`Skill(morph-apply)\` — DAG-adaptive implement loop → review → Gate 3 |
52
+ | \`/morph-proposal {feature}\` | \`Skill(morph-plan)\` — entrevista → plan.md → plan-check → gate do plano |
53
+ | \`/morph-apply {feature}\` | \`Skill(morph-apply)\` — fatias do plano → verify → review → Gate 3 |
55
54
  | \`/morph-status [feature]\` | inspect state.json |
56
55
  | \`/morph-archive {feature}\` | move completed feature to .morph/archive/ |
57
56
  | \`/morph-preflight\` | pre-deploy validation |
@@ -59,13 +58,13 @@ metadata:
59
58
 
60
59
  ## Core skills
61
60
 
62
- \`morph-proposal\`, \`morph-apply\`, \`morph-brainstorming\`, \`morph-plan\`, \`morph-implement\`, \`morph-review\`, \`morph-stack-scan\`, \`morph-standards\`
61
+ \`morph-plan\`, \`morph-apply\`, \`morph-uiux\`, \`morph-review\`, \`morph-hotfix\`, \`morph-standards\`
63
62
 
64
63
  **Why:** This project is managed by morph-spec — spec-driven autonomous development with trust-aware gates.
65
64
 
66
65
  **How to apply:**
67
66
  - When user mentions a feature, check \`.morph/features/\` first.
68
- - When user types \`/morph-proposal\`, invoke \`Skill(morph-proposal)\` directly.
67
+ - When user types \`/morph-proposal\`, invoke \`Skill(morph-plan)\` directly.
69
68
  - In \`trust: "auto"\`, gates auto-pass; only AskUserQuestion on risk signals.
70
69
  `;
71
70
  }
@@ -83,10 +82,9 @@ metadata:
83
82
  - \`.morph/context/design-system.md\` — design tokens and components (source of truth)
84
83
  - \`.morph/framework/MORPH.md\` — NLH charter, Trust Mode rules, gates, skills table
85
84
  - \`.morph/framework/standards/STANDARDS.json\` — index; load specific standard via \`path\` field
86
- - \`.morph/framework/schemas/tasks.schema.json\` — tasks.json schema reference
87
85
  - \`.morph/framework/phases.json\` — phase folder mapping and skill associations
88
86
  - \`.morph/framework/agents.json\` — domain persona definitions (dotnet-senior, ef-modeler, etc.)
89
- - \`.morph/framework/evals/review-checklist.md\` — what the Gate 3 evaluator checks (verdict SHIP/FIX + evidence-typed blockers)
87
+ - \`.morph/framework/evals/review-checklist.md\` — what the Gate 3 verifier, reviewer and security check (verdict SHIP/FIX + evidence-typed blockers)
90
88
  `;
91
89
 
92
90
  /**
@@ -1,4 +1,5 @@
1
- import { dotnetBuildCommandFor, resolveTestBuildTargets } from '../tasks/test-runner.js';
1
+ import { resolve } from 'node:path';
2
+ import { discoverDotnetBuildTargets, dotnetBuildCommandFor } from '../tasks/test-runner.js';
2
3
 
3
4
  const FILTER = /--filter(?:[ =:])(?:"([^"]*)"|'([^']*)'|(\S+))/;
4
5
  const quote = (s) => `"${String(s).replace(/"/g, '\\"')}"`;
@@ -32,7 +33,7 @@ const VERBOSITY = /\s(?:-v|--verbosity)[ =:]?\S+/g;
32
33
  export function dotnetBuildCommands(node, projectPath) {
33
34
  const configuration = CONFIGURATION.exec(node.command ?? '');
34
35
  const flag = configuration ? ` -c ${configuration[1] ?? configuration[2]}` : '';
35
- return resolveTestBuildTargets(node)
36
+ return discoverDotnetBuildTargets(node, resolve(projectPath || '.', node.cwd || '.'))
36
37
  .map((target) => dotnetBuildCommandFor(target, projectPath))
37
38
  .filter(Boolean)
38
39
  .map((command) => `${command.replace(VERBOSITY, '')} -v m${flag}`);