@polymorphism-tech/morph-spec 7.7.0 → 7.7.2
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 +2 -2
- package/bin/morph-spec.js +4 -11
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +1 -1
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-implement/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +1 -1
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +1 -1
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/package.json +1 -1
- package/src/commands/project/update.js +26 -2
- package/src/scripts/setup-infra.js +2 -1
- package/src/utils/banner.js +80 -51
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> Spec-driven development framework for multi-stack projects. Turns feature requests into implementation-ready code through structured, AI-orchestrated phases.
|
|
4
4
|
|
|
5
5
|
**Package:** `@polymorphism-tech/morph-spec`
|
|
6
|
-
**Version:** 7.7.
|
|
6
|
+
**Version:** 7.7.2
|
|
7
7
|
**Requires:** Node.js 22+, Claude Code
|
|
8
8
|
|
|
9
9
|
---
|
|
@@ -365,4 +365,4 @@ Code generated by morph-spec (contracts, templates, implementation output) belon
|
|
|
365
365
|
|
|
366
366
|
---
|
|
367
367
|
|
|
368
|
-
*morph-spec v7.7.
|
|
368
|
+
*morph-spec v7.7.2 by [Polymorphism Tech](https://polymorphism.tech)*
|
package/bin/morph-spec.js
CHANGED
|
@@ -14,6 +14,7 @@ import chalk from 'chalk';
|
|
|
14
14
|
import { fileURLToPath } from 'url';
|
|
15
15
|
import { dirname, join } from 'path';
|
|
16
16
|
import { readFileSync } from 'fs';
|
|
17
|
+
import { renderLogo } from '../src/utils/banner.js';
|
|
17
18
|
|
|
18
19
|
// === Project / install ===
|
|
19
20
|
import { initCommand } from '../src/commands/project/init.js';
|
|
@@ -52,17 +53,9 @@ import { dashboardCommand } from '../src/commands/dashboard/dashboard.js';
|
|
|
52
53
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
53
54
|
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
|
|
54
55
|
|
|
55
|
-
const banner =
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
██╔████╔██║██║ ██║██████╔╝██████╔╝███████║
|
|
59
|
-
██║╚██╔╝██║██║ ██║██╔══██╗██╔═══╝ ██╔══██║
|
|
60
|
-
██║ ╚═╝ ██║╚██████╔╝██║ ██║██║ ██║ ██║
|
|
61
|
-
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝
|
|
62
|
-
|
|
63
|
-
Spec-driven development harness for Claude Code
|
|
64
|
-
by Polymorphism Tech | v${pkg.version}
|
|
65
|
-
`);
|
|
56
|
+
const banner = `${renderLogo(pkg.version)}
|
|
57
|
+
${chalk.dim('Spec-driven development harness for Claude Code — by Polymorphism Tech')}
|
|
58
|
+
`;
|
|
66
59
|
|
|
67
60
|
program
|
|
68
61
|
.name('morph-spec')
|
package/claude-plugin.json
CHANGED
package/docs/CHEATSHEET.md
CHANGED
package/docs/QUICKSTART.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Guia a criação de uma landing page nova ponta-a-ponta a partir do
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar um novo projeto de LP com o template Umbraco genérico
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.7.
|
|
7
|
+
cliVersion: "7.7.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# create-umbraco-lp
|
|
@@ -4,7 +4,7 @@ description: Migra uma landing page existente (React/Vite, Next.js estático ou
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber instrução "use /migrate-lp-to-umbraco {projeto}" do usuário, ou quando o usuário descrever necessidade de migrar uma LP para Umbraco
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.7.
|
|
7
|
+
cliVersion: "7.7.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# migrate-lp-to-umbraco
|
|
@@ -4,7 +4,7 @@ description: Orquestra a execução autônoma de tasks de uma feature morph-spec
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: após Gate 2 aprovado, ao receber instrução "use /morph-apply" ou "implementar feature"
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.7.
|
|
7
|
+
cliVersion: "7.7.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-apply
|
|
@@ -4,7 +4,7 @@ description: Entende o negócio, os usuários e a arquitetura antes de qualquer
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber um novo request de feature, antes de morph-plan
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.7.
|
|
7
|
+
cliVersion: "7.7.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-brainstorming
|
|
@@ -4,7 +4,7 @@ description: Avalia a qualidade de uma tarefa ou fase com rubricas graduadas 0-1
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao completar uma tarefa ou ao finalizar uma fase de implementação
|
|
6
6
|
user-invokable: false
|
|
7
|
-
cliVersion: "7.7.
|
|
7
|
+
cliVersion: "7.7.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-eval
|
|
@@ -4,7 +4,7 @@ description: Guia a produção dos três artefatos de planejamento de uma featur
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar a fase plan de uma feature, após o Gate 1 (proposal aprovado)
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.7.
|
|
7
|
+
cliVersion: "7.7.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-plan
|
|
@@ -4,7 +4,7 @@ description: Orquestra a fase de proposta+plano de uma feature morph-spec. Encad
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber instrução "use /morph-proposal" do usuário, ou ao iniciar uma nova feature
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.7.
|
|
7
|
+
cliVersion: "7.7.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-proposal
|
|
@@ -4,7 +4,7 @@ description: Conduz a fase de revisão e produz o review-report.md para o Gate 3
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar a fase review, após todas as tasks de tasks.json estarem com status `done`
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.7.
|
|
7
|
+
cliVersion: "7.7.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-review
|
|
@@ -4,7 +4,7 @@ description: Varre o codebase existente, detecta stack atual, compara com o stac
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar uma feature em projeto brownfield (codebase já existente)
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.7.
|
|
7
|
+
cliVersion: "7.7.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-stack-scan
|
|
@@ -4,7 +4,7 @@ description: Localiza e carrega um standard específico do STANDARDS.json sob de
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: quando precisar consultar um standard específico durante a implementação
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.7.
|
|
7
|
+
cliVersion: "7.7.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-standards
|
package/package.json
CHANGED
|
@@ -30,6 +30,7 @@ import { installSkills } from '../../utils/skills-installer.js';
|
|
|
30
30
|
import { installAgents, installDomainAgents } from '../../utils/agents-installer.js';
|
|
31
31
|
import { injectMorphImport } from '../../utils/claude-md-injector.js';
|
|
32
32
|
import { getProjectTags } from '../../lib/stack-filter.js';
|
|
33
|
+
import { updateClaudeMdAgentsBlock } from '../../scripts/setup-infra.js';
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Backup user's config.json before cleaning
|
|
@@ -60,6 +61,9 @@ async function cleanFrameworkDirs(morphPath, targetPath) {
|
|
|
60
61
|
join(morphPath, 'framework', 'templates'),
|
|
61
62
|
join(morphPath, 'framework', 'standards'),
|
|
62
63
|
join(morphPath, 'framework', 'hooks'),
|
|
64
|
+
join(morphPath, 'framework', 'schemas'),
|
|
65
|
+
join(morphPath, 'framework', 'rubrics'),
|
|
66
|
+
join(morphPath, 'framework', 'evals'),
|
|
63
67
|
join(morphPath, 'config'),
|
|
64
68
|
join(claudeDir, 'commands'),
|
|
65
69
|
join(claudeDir, 'rules'),
|
|
@@ -267,6 +271,24 @@ export async function updateCommand(options) {
|
|
|
267
271
|
await copyFile(agentsSrc, agentsDest);
|
|
268
272
|
}
|
|
269
273
|
|
|
274
|
+
// Update the remaining framework payloads (parity with setup-infra 7b/7c/8b/8c/8d) —
|
|
275
|
+
// MORPH.md, phases.json, schemas/, rubrics/, evals/. Without this, upgrades left
|
|
276
|
+
// the installed charter/rubrics/eval assets stale forever.
|
|
277
|
+
updateSpinner.text = 'Updating charter, schemas, rubrics and evals...';
|
|
278
|
+
const canonicalFrameworkDir = join(__dirname, '..', '..', '..', 'framework');
|
|
279
|
+
for (const file of ['MORPH.md', 'phases.json']) {
|
|
280
|
+
const src = join(canonicalFrameworkDir, file);
|
|
281
|
+
if (await pathExists(src)) {
|
|
282
|
+
await copyFile(src, join(morphPath, 'framework', file));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
for (const dir of ['schemas', 'rubrics', 'evals']) {
|
|
286
|
+
const src = join(canonicalFrameworkDir, dir);
|
|
287
|
+
if (await pathExists(src)) {
|
|
288
|
+
await copyDirectory(src, join(morphPath, 'framework', dir));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
270
292
|
// Regenerate derived files (phase-utils.js, skill output tables) from output-schema.js
|
|
271
293
|
// Only runs when the generator script is present (framework dev installs via npm link)
|
|
272
294
|
updateSpinner.text = 'Syncing generated refs...';
|
|
@@ -313,7 +335,7 @@ export async function updateCommand(options) {
|
|
|
313
335
|
|
|
314
336
|
// Sync native subagents to .claude/agents/
|
|
315
337
|
updateSpinner.text = 'Syncing agents to .claude/agents/...';
|
|
316
|
-
await installAgents(targetPath, frameworkDir, { projectTags });
|
|
338
|
+
const agentsResult = await installAgents(targetPath, frameworkDir, { projectTags });
|
|
317
339
|
await installDomainAgents(targetPath, frameworkDir, { projectTags });
|
|
318
340
|
|
|
319
341
|
// Sync path-scoped rules to .claude/rules/
|
|
@@ -324,12 +346,14 @@ export async function updateCommand(options) {
|
|
|
324
346
|
await copyDirectory(rulesSrc, rulesDest);
|
|
325
347
|
}
|
|
326
348
|
|
|
327
|
-
// Sync runtime CLAUDE.md to .claude/CLAUDE.md
|
|
349
|
+
// Sync runtime CLAUDE.md to .claude/CLAUDE.md and derive the personas
|
|
350
|
+
// block from what installAgents actually installed (managed markers).
|
|
328
351
|
updateSpinner.text = 'Syncing .claude/CLAUDE.md...';
|
|
329
352
|
const runtimeSrc = join(frameworkDir, 'CLAUDE.md');
|
|
330
353
|
const runtimeDest = join(claudeDest, 'CLAUDE.md');
|
|
331
354
|
if (await pathExists(runtimeSrc)) {
|
|
332
355
|
await copyFile(runtimeSrc, runtimeDest);
|
|
356
|
+
await updateClaudeMdAgentsBlock(runtimeDest, agentsResult?.agents ?? []);
|
|
333
357
|
}
|
|
334
358
|
|
|
335
359
|
// Sync statusline globally to ~/.claude/
|
|
@@ -122,11 +122,12 @@ async function installStackAwareAssets(targetPath, log) {
|
|
|
122
122
|
* Rewrite the managed personas block in .claude/CLAUDE.md with the agents
|
|
123
123
|
* ACTUALLY installed (derived list — never a hand-written promise).
|
|
124
124
|
* No markers / no file → no-op (fail-open).
|
|
125
|
+
* Exported so `morph-spec update` derives the same block on upgrades.
|
|
125
126
|
*
|
|
126
127
|
* @param {string} claudeMdPath - Absolute path to the installed .claude/CLAUDE.md
|
|
127
128
|
* @param {Array<{ name: string, title: string, domains: string[] }>} agents
|
|
128
129
|
*/
|
|
129
|
-
async function updateClaudeMdAgentsBlock(claudeMdPath, agents = []) {
|
|
130
|
+
export async function updateClaudeMdAgentsBlock(claudeMdPath, agents = []) {
|
|
130
131
|
if (!(await pathExists(claudeMdPath))) return;
|
|
131
132
|
const START = '<!-- morph-agents:start -->';
|
|
132
133
|
const END = '<!-- morph-agents:end -->';
|
package/src/utils/banner.js
CHANGED
|
@@ -1,51 +1,80 @@
|
|
|
1
|
-
// src/utils/banner.js
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import { type as osType, release as osRelease } from 'os';
|
|
4
|
-
|
|
5
|
-
const BRAND = chalk.hex('#7C3AED');
|
|
6
|
-
const DIM = chalk.dim;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
'',
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
1
|
+
// src/utils/banner.js
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { type as osType, release as osRelease } from 'os';
|
|
4
|
+
|
|
5
|
+
const BRAND = chalk.hex('#7C3AED');
|
|
6
|
+
const DIM = chalk.dim;
|
|
7
|
+
|
|
8
|
+
/** Purple gradient, one tone per logo line (top → bottom). */
|
|
9
|
+
const GRADIENT = ['#6D28D9', '#7C3AED', '#8B5CF6', '#A78BFA', '#C4B5FD', '#DDD6FE'];
|
|
10
|
+
|
|
11
|
+
const LOGO_LINES = [
|
|
12
|
+
'███╗ ███╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗',
|
|
13
|
+
'████╗ ████║██╔═══██╗██╔══██╗██╔══██╗██║ ██║',
|
|
14
|
+
'██╔████╔██║██║ ██║██████╔╝██████╔╝███████║',
|
|
15
|
+
'██║╚██╔╝██║██║ ██║██╔══██╗██╔═══╝ ██╔══██║',
|
|
16
|
+
'██║ ╚═╝ ██║╚██████╔╝██║ ██║██║ ██║ ██║',
|
|
17
|
+
'╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const LOGO_WIDTH = LOGO_LINES[0].length; // 44
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The morph-spec logo: gradient "MORPH" block art with a S P E C + version
|
|
24
|
+
* rule underneath. Single source for the CLI help banner and the install
|
|
25
|
+
* banner — one drawing, everywhere.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} version - e.g. "7.7.2"
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
export function renderLogo(version) {
|
|
31
|
+
const art = LOGO_LINES
|
|
32
|
+
.map((line, i) => ' ' + chalk.hex(GRADIENT[i])(line))
|
|
33
|
+
.join('\n');
|
|
34
|
+
|
|
35
|
+
const label = ` S P E C `;
|
|
36
|
+
const ver = ` v${version} `;
|
|
37
|
+
const plain = `${label}·${ver}`;
|
|
38
|
+
const side = Math.max(2, Math.floor((LOGO_WIDTH - plain.length) / 2));
|
|
39
|
+
const rule =
|
|
40
|
+
' ' +
|
|
41
|
+
DIM('─'.repeat(side)) +
|
|
42
|
+
BRAND.bold(label) +
|
|
43
|
+
DIM('·') +
|
|
44
|
+
chalk.bold.white(ver) +
|
|
45
|
+
DIM('─'.repeat(Math.max(2, LOGO_WIDTH - side - plain.length)));
|
|
46
|
+
|
|
47
|
+
return `\n${art}\n${rule}\n`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function platformLabel() {
|
|
51
|
+
const t = osType();
|
|
52
|
+
const r = osRelease().split('.').slice(0, 2).join('.');
|
|
53
|
+
if (t === 'Windows_NT') return `Windows ${r}`;
|
|
54
|
+
if (t === 'Darwin') return `macOS ${r}`;
|
|
55
|
+
return `Linux ${r}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function printInstallBanner({ version, nodeVersion, results = [] }) {
|
|
59
|
+
const sep = (label) => DIM(` ── ${label} ${'─'.repeat(Math.max(0, 38 - label.length))}`);
|
|
60
|
+
|
|
61
|
+
const itemLines = results.map(r =>
|
|
62
|
+
r.ok
|
|
63
|
+
? ` ${chalk.green('✔')} ${r.label.padEnd(20)} ${DIM(r.path)}`
|
|
64
|
+
: ` ${chalk.red('✖')} ${r.label.padEnd(20)} ${chalk.red(r.error ?? 'failed')}`
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
console.log([
|
|
68
|
+
renderLogo(version),
|
|
69
|
+
` ${DIM('Spec-driven development harness for Claude Code')}`,
|
|
70
|
+
` ${DIM('by Polymorphism Tech')} ${DIM('·')} ${DIM('Node')} ${chalk.white(nodeVersion)} ${DIM('·')} ${chalk.white(platformLabel())}`,
|
|
71
|
+
'',
|
|
72
|
+
sep('Installed'),
|
|
73
|
+
...itemLines,
|
|
74
|
+
'',
|
|
75
|
+
sep('Next'),
|
|
76
|
+
` ${chalk.cyan('1.')} Open your project in Claude Code`,
|
|
77
|
+
` ${chalk.cyan('2.')} Run ${chalk.bold.white('/morph-init')}`,
|
|
78
|
+
'',
|
|
79
|
+
].join('\n'));
|
|
80
|
+
}
|