@polymorphism-tech/morph-spec 4.10.10 → 4.11.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 (48) hide show
  1. package/README.md +5 -11
  2. package/bin/morph-spec.js +1 -1
  3. package/bin/task-manager.js +5 -5
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +2 -8
  7. package/framework/agents/frontend/css-specialist.md +1 -1
  8. package/framework/agents/infrastructure/azure-deploy-specialist.md +4 -4
  9. package/framework/commands/morph-apply.md +18 -18
  10. package/framework/commands/morph-preflight.md +3 -3
  11. package/framework/commands/morph-proposal.md +15 -15
  12. package/framework/commands/morph-status.md +3 -3
  13. package/framework/commands/morph-troubleshoot.md +1 -1
  14. package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +2 -2
  15. package/framework/hooks/claude-code/session-start/inject-morph-context.js +1 -1
  16. package/framework/hooks/claude-code/teammate-idle/teammate-idle.js +3 -3
  17. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +2 -2
  18. package/framework/hooks/git/pre-commit/agents.sh +1 -1
  19. package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +8 -8
  20. package/framework/skills/level-0-meta/morph-checklist/SKILL.md +3 -3
  21. package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +1 -1
  22. package/framework/skills/level-0-meta/morph-init/SKILL.md +11 -11
  23. package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +3 -3
  24. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +1 -1
  25. package/framework/skills/level-0-meta/morph-simulation-checklist/SKILL.md +4 -4
  26. package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +25 -25
  27. package/framework/skills/level-0-meta/morph-verification-before-completion/SKILL.md +8 -8
  28. package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +7 -7
  29. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +4 -4
  30. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +23 -23
  31. package/framework/skills/level-1-workflows/morph-phase-design/references/architecture-analysis-guide.md +1 -1
  32. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +29 -29
  33. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +4 -4
  34. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +9 -9
  35. package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +17 -17
  36. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +12 -12
  37. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +16 -16
  38. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +5 -5
  39. package/framework/workflows/README.md +18 -18
  40. package/framework/workflows/docs/enforcement-pipeline.md +1 -1
  41. package/framework/workflows/docs/full-morph.md +2 -2
  42. package/package.json +1 -1
  43. package/src/commands/project/doctor.js +3 -4
  44. package/src/commands/project/status.js +8 -1
  45. package/src/commands/scope/escalate.js +5 -3
  46. package/src/commands/validation/validate-feature.js +32 -3
  47. package/src/scripts/global-install.js +57 -3
  48. package/src/utils/version-checker.js +1 -7
@@ -70,6 +70,19 @@ const PHASE_OUTPUTS = {
70
70
  implement: ['spec.md', 'contracts.cs', 'tasks.md']
71
71
  };
72
72
 
73
+ /**
74
+ * Phase-to-folder mapping (filesystem convention)
75
+ */
76
+ const PHASE_FOLDERS = {
77
+ proposal: '0-proposal',
78
+ uiux: '2-ui',
79
+ design: '1-design',
80
+ clarify: '1-design',
81
+ plan: '3-plan',
82
+ tasks: '4-tasks',
83
+ implement: '5-implement',
84
+ };
85
+
73
86
  /**
74
87
  * Validate a single output file
75
88
  */
@@ -254,12 +267,28 @@ export async function validateFeatureCommand(featureName, options = {}) {
254
267
  process.exit(1);
255
268
  }
256
269
  } else {
257
- // Validate all existing outputs
258
- outputFiles = fs.readdirSync(featurePath).filter(f => f.endsWith('.md') || f.endsWith('.cs'));
270
+ // Validate all existing outputs across all phase folders
271
+ outputFiles = [];
272
+ const entries = fs.readdirSync(featurePath, { withFileTypes: true });
273
+ for (const entry of entries) {
274
+ if (entry.isDirectory()) {
275
+ const subDir = path.join(featurePath, entry.name);
276
+ const files = fs.readdirSync(subDir).filter(f => f.endsWith('.md') || f.endsWith('.cs'));
277
+ outputFiles.push(...files.map(f => ({ file: f, dir: subDir })));
278
+ } else if (entry.name.endsWith('.md') || entry.name.endsWith('.cs')) {
279
+ outputFiles.push({ file: entry.name, dir: featurePath });
280
+ }
281
+ }
259
282
  }
260
283
 
284
+ // Resolve phase folder for path lookup
285
+ const phaseFolder = phase ? PHASE_FOLDERS[phase] : null;
286
+ const searchPath = phaseFolder ? path.join(featurePath, phaseFolder) : featurePath;
287
+
261
288
  // Run validation
262
- const results = outputFiles.map(file => validateOutput(featurePath, file));
289
+ const results = phase
290
+ ? outputFiles.map(file => validateOutput(searchPath, file))
291
+ : outputFiles.map(({ file, dir }) => validateOutput(dir, file));
263
292
  const schemaWarnings = crossValidateSchema(featurePath);
264
293
 
265
294
  // Aggregate results
@@ -1,9 +1,10 @@
1
1
  // src/scripts/global-install.js
2
2
  import { join, dirname } from 'path';
3
3
  import { fileURLToPath } from 'url';
4
- import { homedir } from 'os';
5
- import { mkdir, copyFile } from 'fs/promises';
4
+ import { homedir, platform } from 'os';
5
+ import { mkdir, copyFile, readFile, writeFile } from 'fs/promises';
6
6
  import { existsSync } from 'fs';
7
+ import { execSync } from 'child_process';
7
8
  import { installGlobalStatusline } from '../utils/hooks-installer.js';
8
9
 
9
10
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -27,15 +28,62 @@ export async function installGlobalSkill(claudeDir = join(homedir(), '.claude'))
27
28
  await copyFile(src, dest);
28
29
  }
29
30
 
31
+ /**
32
+ * Ensure the npm global bin directory is in the user's PATH on Windows.
33
+ * Adds it to the PowerShell $PROFILE so new terminals find `morph-spec`.
34
+ */
35
+ export async function ensureNpmGlobalInPath() {
36
+ if (platform() !== 'win32') return;
37
+
38
+ let npmGlobalDir;
39
+ try {
40
+ npmGlobalDir = execSync('npm prefix -g', { encoding: 'utf8' }).trim();
41
+ } catch {
42
+ return; // can't determine npm global dir
43
+ }
44
+
45
+ if (!npmGlobalDir || !existsSync(npmGlobalDir)) return;
46
+
47
+ // --- PowerShell $PROFILE ---
48
+ const psProfile = join(homedir(), 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1');
49
+ const psProfileLegacy = join(homedir(), 'Documents', 'WindowsPowerShell', 'Microsoft.PowerShell_profile.ps1');
50
+
51
+ const marker = '# morph-spec: ensure npm global in PATH';
52
+ const snippet = [
53
+ marker,
54
+ `if ($env:PATH -notlike "*${npmGlobalDir.replace(/\\/g, '\\\\')}*") {`,
55
+ ` $env:PATH += ";${npmGlobalDir}"`,
56
+ '}',
57
+ '# end morph-spec PATH',
58
+ ].join('\n');
59
+
60
+ for (const profilePath of [psProfile, psProfileLegacy]) {
61
+ try {
62
+ let content = '';
63
+ if (existsSync(profilePath)) {
64
+ content = await readFile(profilePath, 'utf8');
65
+ if (content.includes(marker)) continue; // already patched
66
+ } else {
67
+ await mkdir(dirname(profilePath), { recursive: true });
68
+ }
69
+ const newContent = content ? `${content}\n\n${snippet}\n` : `${snippet}\n`;
70
+ await writeFile(profilePath, newContent, 'utf8');
71
+ } catch {
72
+ // non-critical — skip silently
73
+ }
74
+ }
75
+ }
76
+
30
77
  // Run as postinstall script
31
78
  if (process.argv[1] === fileURLToPath(import.meta.url)) {
32
79
  const HOOKS_SRC = join(FRAMEWORK_DIR, 'hooks', 'claude-code');
33
80
  const { readFileSync } = await import('fs');
34
81
  const pkg = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8'));
35
82
 
36
- const [skillResult, statuslineResult] = await Promise.allSettled([
83
+ const [skillResult, statuslineResult, pathResult] = await Promise.allSettled([
37
84
  installGlobalSkill(),
38
85
  installGlobalStatusline(HOOKS_SRC),
86
+ ensureNpmGlobalInPath(),
39
87
  ]);
40
88
 
41
89
  const results = [
@@ -51,6 +99,12 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
51
99
  path: '~/.claude/',
52
100
  error: statuslineResult.reason?.message,
53
101
  },
102
+ {
103
+ ok: pathResult.status === 'fulfilled',
104
+ label: 'PATH (npm global)',
105
+ path: '$PROFILE',
106
+ error: pathResult.reason?.message,
107
+ },
54
108
  ];
55
109
 
56
110
  const { printInstallBanner } = await import('../utils/banner.js');
@@ -125,16 +125,10 @@ export function getUpdateInstructions(method) {
125
125
  'morph-spec update'
126
126
  ];
127
127
  case 'npx':
128
- return [
129
- 'npx @polymorphism-tech/morph-spec@latest update'
130
- ];
131
128
  default:
132
129
  return [
133
130
  'npm install -g @polymorphism-tech/morph-spec@latest',
134
- 'morph-spec update',
135
- '',
136
- 'Or use npx:',
137
- 'npx @polymorphism-tech/morph-spec@latest update'
131
+ 'morph-spec update'
138
132
  ];
139
133
  }
140
134
  }