@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.
- package/README.md +5 -11
- package/bin/morph-spec.js +1 -1
- package/bin/task-manager.js +5 -5
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +2 -8
- package/framework/agents/frontend/css-specialist.md +1 -1
- package/framework/agents/infrastructure/azure-deploy-specialist.md +4 -4
- package/framework/commands/morph-apply.md +18 -18
- package/framework/commands/morph-preflight.md +3 -3
- package/framework/commands/morph-proposal.md +15 -15
- package/framework/commands/morph-status.md +3 -3
- package/framework/commands/morph-troubleshoot.md +1 -1
- package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +2 -2
- package/framework/hooks/claude-code/session-start/inject-morph-context.js +1 -1
- package/framework/hooks/claude-code/teammate-idle/teammate-idle.js +3 -3
- package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +2 -2
- package/framework/hooks/git/pre-commit/agents.sh +1 -1
- package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +8 -8
- package/framework/skills/level-0-meta/morph-checklist/SKILL.md +3 -3
- package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +1 -1
- package/framework/skills/level-0-meta/morph-init/SKILL.md +11 -11
- package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +3 -3
- package/framework/skills/level-0-meta/morph-replicate/SKILL.md +1 -1
- package/framework/skills/level-0-meta/morph-simulation-checklist/SKILL.md +4 -4
- package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +25 -25
- package/framework/skills/level-0-meta/morph-verification-before-completion/SKILL.md +8 -8
- package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +7 -7
- package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +4 -4
- package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +23 -23
- package/framework/skills/level-1-workflows/morph-phase-design/references/architecture-analysis-guide.md +1 -1
- package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +29 -29
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +4 -4
- package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +9 -9
- package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +17 -17
- package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +12 -12
- package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +16 -16
- package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +5 -5
- package/framework/workflows/README.md +18 -18
- package/framework/workflows/docs/enforcement-pipeline.md +1 -1
- package/framework/workflows/docs/full-morph.md +2 -2
- package/package.json +1 -1
- package/src/commands/project/doctor.js +3 -4
- package/src/commands/project/status.js +8 -1
- package/src/commands/scope/escalate.js +5 -3
- package/src/commands/validation/validate-feature.js +32 -3
- package/src/scripts/global-install.js +57 -3
- 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 =
|
|
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 =
|
|
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
|
}
|