@polymorphism-tech/morph-spec 8.41.0 → 8.43.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 (102) hide show
  1. package/CLAUDE.md +14 -4
  2. package/README.md +3 -3
  3. package/bin/morph-spec.js +48 -2
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/CLAUDE.md +6 -5
  8. package/framework/MORPH.md +10 -9
  9. package/framework/agents.json +7 -7
  10. package/framework/docs/CLI.md +10 -3
  11. package/framework/evals/proof-rubrics/mutation-proof.md +43 -13
  12. package/framework/hooks/README.md +1 -0
  13. package/framework/hooks/claude-code/core/chain.js +2 -0
  14. package/framework/hooks/claude-code/core/comment-guard.js +107 -0
  15. package/framework/hooks/claude-code/core/heavy-gate.js +72 -0
  16. package/framework/hooks/claude-code/core/heavy-release.js +34 -0
  17. package/framework/hooks/claude-code/core/worktree-context.js +21 -20
  18. package/framework/hooks/claude-code/core/worktree-create.js +4 -4
  19. package/framework/hooks/shared/agent-reap.js +89 -0
  20. package/framework/hooks/shared/comment-rules.js +171 -0
  21. package/{src/lib/validators/code-budget → framework/hooks/shared}/comment-scanner.js +2 -2
  22. package/{src/lib/ai → framework/hooks/shared}/comment-stripper.js +2 -1
  23. package/framework/hooks/shared/e2e-check.js +3 -1
  24. package/framework/hooks/shared/graph-refresh.js +1 -9
  25. package/framework/hooks/shared/heavy-command.js +128 -0
  26. package/framework/hooks/shared/heavy-config.js +65 -0
  27. package/framework/hooks/shared/heavy-holders.js +85 -0
  28. package/framework/hooks/shared/heavy-slots.js +207 -0
  29. package/framework/hooks/shared/process-alive.js +8 -0
  30. package/framework/hooks/shared/source-files.js +34 -0
  31. package/framework/hooks/shared/worktree-root.js +93 -0
  32. package/framework/schemas/config.schema.json +80 -0
  33. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  34. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  35. package/framework/skills/core/morph-apply/SKILL.md +11 -4
  36. package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
  37. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  38. package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
  39. package/framework/skills/core/morph-implement/SKILL.md +12 -5
  40. package/framework/skills/core/morph-machine/SKILL.md +46 -0
  41. package/framework/skills/core/morph-media/SKILL.md +1 -1
  42. package/framework/skills/core/morph-plan/SKILL.md +1 -1
  43. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  44. package/framework/skills/core/morph-review/SKILL.md +45 -16
  45. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  46. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  47. package/framework/skills/core/morph-uiux/SKILL.md +1 -1
  48. package/framework/standards/PROVENANCE.json +10 -10
  49. package/framework/standards/STANDARDS.json +1 -1
  50. package/framework/standards/architecture/code-comments.md +9 -2
  51. package/framework/standards/frontend/design-system/ai-video-generation.md +2 -0
  52. package/framework/standards/frontend/scroll-driven/frame-scrub.md +11 -1
  53. package/package.json +1 -1
  54. package/src/commands/e2e/e2e.js +27 -8
  55. package/src/commands/mcp/mcp-setup.js +10 -9
  56. package/src/commands/project/doctor-procs.js +162 -0
  57. package/src/commands/project/doctor.js +42 -4
  58. package/src/commands/project/heavy.js +61 -0
  59. package/src/commands/project/init.js +1 -1
  60. package/src/commands/project/update.js +4 -0
  61. package/src/commands/project/worktree-reap.js +34 -0
  62. package/src/commands/project/worktree.js +78 -27
  63. package/src/commands/validation/mutate.js +200 -0
  64. package/src/commands/validation/verify.js +26 -1
  65. package/src/dashboard/scanner/features-scanner.js +4 -4
  66. package/src/dashboard/scanner/project-api.js +4 -4
  67. package/src/lib/ai/code-audit.js +1 -1
  68. package/src/lib/ai/registry-audit.js +1 -1
  69. package/src/lib/detectors/claude-config-detector.js +30 -1
  70. package/src/lib/heavy/cleanup.js +70 -0
  71. package/src/lib/heavy/gate.js +96 -0
  72. package/src/lib/installers/mcp-installer.js +15 -2
  73. package/src/lib/mutation/adapters.js +90 -0
  74. package/src/lib/mutation/commands.js +60 -0
  75. package/src/lib/mutation/manifest.js +138 -0
  76. package/src/lib/mutation/plan.js +36 -0
  77. package/src/lib/mutation/report.js +66 -0
  78. package/src/lib/mutation/runner.js +351 -0
  79. package/src/lib/mutation/schemata.js +60 -0
  80. package/src/lib/mutation/snapshot.js +69 -0
  81. package/src/lib/mutation/subset.js +75 -0
  82. package/src/lib/mutation/trx.js +51 -0
  83. package/src/lib/procs/classify.js +91 -0
  84. package/src/lib/procs/list.js +124 -0
  85. package/src/lib/procs/mcp-config.js +103 -0
  86. package/src/lib/procs/prune.js +25 -0
  87. package/src/lib/procs/wslconfig.js +70 -0
  88. package/src/lib/projects/registry.js +6 -2
  89. package/src/lib/tasks/dotnet-test-introspection.js +1 -1
  90. package/src/lib/tasks/linux-runner.js +30 -3
  91. package/src/lib/tasks/test-runner.js +1 -1
  92. package/src/lib/validators/code-budget/code-budget-validator.js +4 -6
  93. package/src/lib/validators/code-budget/index.js +1 -1
  94. package/src/lib/validators/reuse/symbol-scanner.js +1 -28
  95. package/src/lib/validators/verify-runner.js +26 -8
  96. package/src/lib/worktree/agent-reaper.js +247 -0
  97. package/src/lib/worktree/dirs.js +3 -32
  98. package/src/lib/worktree/vscode-settings.js +113 -0
  99. package/src/lib/worktree/worktree-audit.js +49 -5
  100. package/src/lib/worktree/worktree-include.js +46 -0
  101. package/src/scripts/setup-infra.js +4 -0
  102. package/src/utils/hooks-installer.js +14 -6
@@ -0,0 +1,46 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { copyFileSync, existsSync, lstatSync, mkdirSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { isDisposableBuildArtifact } from './ignored-triage.js';
5
+
6
+ const INCLUDE_FILE = '.worktreeinclude';
7
+ const NESTED_GIT = /(^|\/)\.git(\/|$)/;
8
+
9
+ const gitOut = (cwd, args, input) => execFileSync('git', args, { cwd, stdio: ['pipe', 'pipe', 'ignore'], encoding: 'utf8', input });
10
+
11
+ /**
12
+ * Claude Code's `.worktreeinclude` for a worktree morph-spec creates (a WorktreeCreate hook replaces
13
+ * the native creation, so the native copy never runs): files matching a pattern AND gitignored in the
14
+ * tree are copied when the tree lacks them. Real files only; build artifacts and `node_modules` never.
15
+ *
16
+ * @returns {string[]} relative paths copied
17
+ */
18
+ export function copyWorktreeIncludes(worktreePath, root) {
19
+ const file = join(root, INCLUDE_FILE);
20
+ if (!existsSync(file)) return [];
21
+ try {
22
+ // No --exclude-standard: with --ignored it would list every gitignored file, not just the pattern matches.
23
+ const matched = gitOut(root, ['ls-files', '--others', '--ignored', '--exclude-from', file, '-z'])
24
+ .split('\0').filter(Boolean).map((p) => p.replace(/\\/g, '/'))
25
+ .filter((p) => !NESTED_GIT.test(p) && !isDisposableBuildArtifact(p));
26
+ if (!matched.length) return [];
27
+
28
+ const ignoredThere = new Set(gitOut(worktreePath, ['check-ignore', '--stdin', '-z'], `${matched.join('\0')}\0`).split('\0').filter(Boolean));
29
+ const copied = [];
30
+ for (const rel of matched) {
31
+ if (!ignoredThere.has(rel)) continue;
32
+ const src = join(root, rel);
33
+ const dst = join(worktreePath, rel);
34
+ try {
35
+ if (!lstatSync(src).isFile()) continue;
36
+ try { lstatSync(dst); continue; } catch { /* absent, and not a dangling link either */ }
37
+ mkdirSync(dirname(dst), { recursive: true });
38
+ copyFileSync(src, dst);
39
+ copied.push(rel);
40
+ } catch { /* unreadable or unwritable — leave it out */ }
41
+ }
42
+ return copied;
43
+ } catch {
44
+ return [];
45
+ }
46
+ }
@@ -25,6 +25,7 @@ import {
25
25
  ensureGitattributes
26
26
  } from '../utils/file-copier.js';
27
27
  import { parseStacks, getProjectTags, shouldInstall } from '../lib/stack-filter.js';
28
+ import { applyEditorSettings } from '../lib/worktree/vscode-settings.js';
28
29
  import { injectMorphImport } from '../utils/claude-md-injector.js';
29
30
  import { saveProjectMorphVersion, getInstalledCLIVersion, getProjectMorphVersion } from '../utils/version-checker.js';
30
31
  import { installClaudeHooks, installGlobalStatusline } from '../utils/claude-settings-manager.js';
@@ -440,6 +441,9 @@ export async function setupInfra(targetPath, {
440
441
  await updateGitignore(targetPath);
441
442
  await ensureGitattributes(targetPath);
442
443
 
444
+ log('Step 18a: Editor excludes for worktrees...');
445
+ try { applyEditorSettings(targetPath); } catch { /* fail-open */ }
446
+
443
447
  // --- 18b. Codebase graph (graphify) ---
444
448
  // Fail-open por inteiro (ADR-002): sem Python, sem uv e sem pipx, o step
445
449
  // registra e segue. O wrapper de CLI mata o processo em qualquer throw
@@ -52,8 +52,11 @@ import { realEffects } from '../lib/installers/effects.js';
52
52
  * 3.11.0 writes every `timeout` in seconds, the unit Claude Code reads: the
53
53
  * values were milliseconds, so a hung hook held the session for hours (120000
54
54
  * on WorktreeCreate is 33 h) instead of the seconds they meant.
55
+ *
56
+ * 3.12.0 adds heavy-gate to the Bash PreToolUse chain and heavy-release to the
57
+ * PostToolUse and PostToolUseFailure chains: the opt-in `heavy.gateBash`.
55
58
  */
56
- const HOOKS_VERSION = '3.11.0';
59
+ const HOOKS_VERSION = '3.12.0';
57
60
 
58
61
  /** Marker for old dispatch.js (v1) */
59
62
  const OLD_DISPATCH_COMMAND = 'node framework/hooks/agent-teams/dispatch.js';
@@ -165,6 +168,8 @@ const MORPH_HOOKS = [
165
168
  // on someone having read MORPH.md. block-raw-worktree-add is its way-IN
166
169
  // counterpart (a raw `git worktree add` builds a tree with no junctions, no
167
170
  // ports, no identity) — static, so it costs nothing after the first two.
171
+ // heavy-gate comes after every guard — it takes a slot, and a command a guard
172
+ // blocks must not hold one — and before the rewriter.
168
173
  // worktree-env-inject is LAST: it rewrites launcher commands (updatedInput)
169
174
  // with the worktree's port block, and a command a previous link blocked must
170
175
  // never be rewritten. Block-first-wins guarantees it never sees one.
@@ -174,7 +179,7 @@ const MORPH_HOOKS = [
174
179
  hooks: [{
175
180
  type: 'command',
176
181
  command: 'node framework/hooks/claude-code/core/chain.js',
177
- args: ['pre-bash-denylist', 'block-destructive-worktree-removal', 'block-raw-worktree-add', 'worktree-env-inject']
182
+ args: ['pre-bash-denylist', 'block-destructive-worktree-removal', 'block-raw-worktree-add', 'heavy-gate', 'worktree-env-inject']
178
183
  }]
179
184
  },
180
185
 
@@ -216,14 +221,15 @@ const MORPH_HOOKS = [
216
221
  // order as before. post-edit-typecheck declared no timeout of its own (it
217
222
  // can legitimately spend up to its internal TSC_TIMEOUT_MS=30000 running
218
223
  // `npx tsc --noEmit`), so the chain declares none rather than under-
219
- // provisioning it with just the sum of the other two links' 3000ms each. ===
224
+ // provisioning it with just the sum of the other two links' 3000ms each.
225
+ // comment-guard is LAST: it blocks, and a block ends the chain. ===
220
226
  {
221
227
  event: 'PostToolUse',
222
228
  matcher: 'Write|Edit',
223
229
  hooks: [{
224
230
  type: 'command',
225
231
  command: 'node framework/hooks/claude-code/core/chain.js',
226
- args: ['post-edit-typecheck', 'tasks-json-guard', 'trace-autogen']
232
+ args: ['post-edit-typecheck', 'tasks-json-guard', 'trace-autogen', 'comment-guard']
227
233
  }]
228
234
  },
229
235
 
@@ -263,19 +269,21 @@ const MORPH_HOOKS = [
263
269
  hooks: [{
264
270
  type: 'command',
265
271
  command: 'node framework/hooks/claude-code/core/chain.js',
266
- args: ['telemetry-log', 'loop-detect', 'graph-refresh-kick'],
272
+ args: ['telemetry-log', 'loop-detect', 'graph-refresh-kick', 'heavy-release'],
267
273
  timeout: 10
268
274
  }]
269
275
  },
270
276
 
271
277
  // === PostToolUseFailure: All — telemetry of the failed call (exit code,
272
278
  // duration). loop-detect stays out: its warning is shaped for PostToolUse.
279
+ // heavy-release gives back the slot of a heavy Bash call that failed.
273
280
  {
274
281
  event: 'PostToolUseFailure',
275
282
  matcher: null,
276
283
  hooks: [{
277
284
  type: 'command',
278
- command: 'node framework/hooks/claude-code/core/telemetry-log.js',
285
+ command: 'node framework/hooks/claude-code/core/chain.js',
286
+ args: ['telemetry-log', 'heavy-release'],
279
287
  timeout: 5,
280
288
  async: true
281
289
  }]