@polymorphism-tech/morph-spec 4.7.1 → 4.8.1
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/.morph/analytics/threads-log.jsonl +54 -0
- package/.morph/state.json +198 -0
- package/LICENSE +1 -2
- package/README.md +379 -414
- package/bin/morph-spec.js +57 -403
- package/bin/validate.js +2 -26
- package/claude-plugin.json +2 -2
- package/docs/ARCHITECTURE.md +43 -46
- package/docs/CHEATSHEET.md +203 -221
- package/docs/COMMAND-FLOWS.md +319 -289
- package/docs/QUICKSTART.md +2 -8
- package/docs/plans/2026-02-22-claude-docs-morph-alignment-analysis.md +2 -0
- package/docs/plans/2026-02-22-claude-settings.md +2 -0
- package/docs/plans/2026-02-22-morph-cc-alignment-impl.md +2 -0
- package/docs/plans/2026-02-22-morph-spec-next.md +2 -0
- package/docs/plans/2026-02-22-native-alignment-design.md +2 -0
- package/docs/plans/2026-02-22-native-alignment-impl.md +2 -0
- package/docs/plans/2026-02-22-native-enrichment-design.md +2 -0
- package/docs/plans/2026-02-22-native-enrichment.md +2 -0
- package/docs/plans/2026-02-23-ddd-architecture-refactor.md +2 -0
- package/docs/plans/2026-02-23-ddd-nextsteps.md +2 -0
- package/docs/plans/2026-02-23-infra-architect-refactor.md +2 -0
- package/docs/plans/2026-02-23-nextjs-code-review-design.md +2 -1
- package/docs/plans/2026-02-23-nextjs-code-review-impl.md +2 -0
- package/docs/plans/2026-02-23-nextjs-standards-design.md +2 -1
- package/docs/plans/2026-02-23-nextjs-standards-impl.md +2 -0
- package/docs/plans/2026-02-24-cli-radical-simplification.md +592 -0
- package/docs/plans/2026-02-24-framework-failure-points.md +125 -0
- package/docs/plans/2026-02-24-morph-init-design.md +337 -0
- package/docs/plans/2026-02-24-morph-init-impl.md +1269 -0
- package/docs/plans/2026-02-24-tutorial-command-design.md +71 -0
- package/docs/plans/2026-02-24-tutorial-command.md +298 -0
- package/framework/CLAUDE.md +2 -2
- package/framework/commands/morph-proposal.md +3 -3
- package/framework/hooks/README.md +11 -10
- package/framework/hooks/claude-code/notification/approval-reminder.js +2 -0
- package/framework/hooks/claude-code/post-tool-use/dispatch.js +1 -1
- package/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +4 -55
- package/framework/hooks/claude-code/session-start/inject-morph-context.js +20 -5
- package/framework/hooks/claude-code/statusline.py +6 -1
- package/framework/hooks/claude-code/stop/validate-completion.js +1 -1
- package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +1 -1
- package/framework/hooks/dev/check-sync-health.js +117 -0
- package/framework/hooks/dev/guard-version-numbers.js +57 -0
- package/framework/hooks/dev/sync-standards-registry.js +60 -0
- package/framework/hooks/dev/sync-template-registry.js +60 -0
- package/framework/hooks/dev/validate-skill-format.js +70 -0
- package/framework/hooks/dev/validate-standard-format.js +73 -0
- package/framework/hooks/shared/payload-utils.js +39 -0
- package/framework/hooks/shared/state-reader.js +25 -1
- package/framework/rules/morph-workflow.md +1 -1
- package/framework/skills/level-0-meta/morph-init/SKILL.md +216 -0
- package/framework/skills/level-0-meta/morph-replicate/SKILL.md +4 -4
- package/framework/skills/level-0-meta/tool-usage-guide/SKILL.md +4 -4
- package/framework/skills/level-0-meta/verification-before-completion/SKILL.md +1 -1
- package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +192 -191
- package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +181 -180
- package/framework/skills/level-1-workflows/phase-design/SKILL.md +339 -338
- package/framework/skills/level-1-workflows/phase-implement/SKILL.md +254 -253
- package/framework/skills/level-1-workflows/phase-setup/SKILL.md +168 -170
- package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +284 -283
- package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +246 -245
- package/framework/templates/examples/design-system-examples.md +1 -1
- package/framework/templates/ui/FluentDesignTheme.cs +1 -1
- package/framework/templates/ui/MudTheme.cs +1 -1
- package/framework/templates/ui/design-system.css +1 -1
- package/package.json +4 -2
- package/scripts/bump-version.js +248 -0
- package/scripts/install-dev-hooks.js +138 -0
- package/src/commands/agents/index.js +1 -2
- package/src/commands/index.js +13 -16
- package/src/commands/project/doctor.js +100 -14
- package/src/commands/project/index.js +7 -10
- package/src/commands/project/init.js +398 -555
- package/src/commands/project/install-plugin-cmd.js +28 -0
- package/src/commands/project/setup-infra-cmd.js +12 -0
- package/src/commands/project/tutorial.js +115 -0
- package/src/commands/project/update.js +22 -37
- package/src/commands/state/approve.js +213 -221
- package/src/commands/state/index.js +0 -1
- package/src/commands/state/state.js +337 -365
- package/src/commands/templates/index.js +0 -4
- package/src/commands/trust/trust.js +1 -93
- package/src/commands/utils/index.js +1 -5
- package/src/commands/validation/index.js +1 -5
- package/src/core/registry/command-registry.js +11 -285
- package/src/core/state/state-manager.js +5 -2
- package/src/lib/detectors/index.js +81 -87
- package/src/lib/detectors/structure-detector.js +275 -273
- package/src/lib/generators/recap-generator.js +232 -225
- package/src/lib/installers/mcp-installer.js +18 -3
- package/src/scripts/global-install.js +34 -0
- package/src/scripts/install-plugin.js +126 -0
- package/src/scripts/setup-infra.js +203 -0
- package/src/utils/agents-installer.js +10 -1
- package/src/utils/hooks-installer.js +70 -17
- package/CLAUDE.md +0 -77
- package/docs/claude-alignment-report.md +0 -137
- package/docs/examples/order-management/contracts.cs +0 -84
- package/docs/examples/order-management/proposal.md +0 -24
- package/docs/examples/order-management/spec.md +0 -162
- package/src/commands/feature/create-story.js +0 -362
- package/src/commands/feature/index.js +0 -6
- package/src/commands/feature/shard-spec.js +0 -225
- package/src/commands/feature/sprint-status.js +0 -250
- package/src/commands/generation/generate-onboarding.js +0 -169
- package/src/commands/generation/generate.js +0 -276
- package/src/commands/generation/index.js +0 -5
- package/src/commands/learning/capture-pattern.js +0 -121
- package/src/commands/learning/index.js +0 -5
- package/src/commands/learning/search-patterns.js +0 -126
- package/src/commands/mcp/mcp.js +0 -102
- package/src/commands/project/changes.js +0 -66
- package/src/commands/project/cost.js +0 -179
- package/src/commands/project/detect.js +0 -114
- package/src/commands/project/diff.js +0 -278
- package/src/commands/project/revert.js +0 -173
- package/src/commands/project/standards.js +0 -80
- package/src/commands/project/sync.js +0 -167
- package/src/commands/project/update-agents.js +0 -23
- package/src/commands/state/rollback-phase.js +0 -185
- package/src/commands/templates/template-customize.js +0 -87
- package/src/commands/templates/template-list.js +0 -114
- package/src/commands/templates/template-show.js +0 -129
- package/src/commands/templates/template-validate.js +0 -91
- package/src/commands/utils/troubleshoot.js +0 -222
- package/src/commands/validation/analyze-blazor-concurrency.js +0 -193
- package/src/commands/validation/lint-fluent.js +0 -352
- package/src/commands/validation/validate-blazor-state.js +0 -210
- package/src/commands/validation/validate-blazor.js +0 -156
- package/src/commands/validation/validate-css.js +0 -84
- package/src/lib/detectors/conversation-analyzer.js +0 -163
- package/src/lib/learning/index.js +0 -7
- package/src/lib/learning/learning-system.js +0 -520
- package/src/lib/troubleshooting/index.js +0 -8
- package/src/lib/troubleshooting/troubleshoot-grep.js +0 -198
- package/src/lib/troubleshooting/troubleshoot-index.js +0 -144
- package/src/llm/environment-detector.js +0 -43
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Design: `morph-spec tutorial` Command
|
|
2
|
+
|
|
3
|
+
**Status:** COMPLETE (see implementation plan)
|
|
4
|
+
|
|
5
|
+
**Date:** 2026-02-24
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
After `morph-spec init`, first-time users see a suggestion to run `morph-spec tutorial`, but the command doesn't exist. New users also lack a quick way to understand the spec-first workflow and its phase pipeline.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Goal
|
|
16
|
+
|
|
17
|
+
A self-contained CLI command that teaches the MORPH-SPEC mental model: the phase pipeline, what each phase produces, and how to trigger each phase. Pure stdout, no side effects.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Approach: Workflow Walkthrough
|
|
22
|
+
|
|
23
|
+
A static, colored terminal output that explains the full pipeline top-to-bottom. No arguments, no options, no network calls, no file I/O.
|
|
24
|
+
|
|
25
|
+
Chosen over:
|
|
26
|
+
- **Interactive mode** — risks accidentally modifying project state
|
|
27
|
+
- **Quick reference** — duplicates `--help` with little added value
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Output Structure
|
|
32
|
+
|
|
33
|
+
1. **Header** — title + one-sentence philosophy
|
|
34
|
+
2. **Pipeline diagram** — ASCII showing phase sequence with optional phases bracketed
|
|
35
|
+
3. **Per-phase block** — for each of the 8 phases:
|
|
36
|
+
- Phase name + number
|
|
37
|
+
- What it does (1 sentence)
|
|
38
|
+
- What it produces (output files)
|
|
39
|
+
- How to trigger it (CLI command or `/slash-command` in Claude Code)
|
|
40
|
+
4. **Getting Started** — 3-step CTA ending with `morph-spec doctor` tip
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Implementation
|
|
45
|
+
|
|
46
|
+
| Item | Detail |
|
|
47
|
+
|------|--------|
|
|
48
|
+
| File | `src/commands/project/tutorial.js` |
|
|
49
|
+
| Export | `tutorialCommand` |
|
|
50
|
+
| Registration (index) | `src/commands/project/index.js` |
|
|
51
|
+
| Registration (bin) | `bin/morph-spec.js` |
|
|
52
|
+
| Dependencies | `chalk` (already installed) |
|
|
53
|
+
| Side effects | None — pure stdout |
|
|
54
|
+
| Size | ~100 lines |
|
|
55
|
+
|
|
56
|
+
Also: revert `init.js:518` back to `morph-spec tutorial` (the original intent).
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Phases Covered
|
|
61
|
+
|
|
62
|
+
| Phase | Trigger |
|
|
63
|
+
|-------|---------|
|
|
64
|
+
| 0 · Proposal | `/morph-proposal <feature>` |
|
|
65
|
+
| 1 · Setup | auto-triggered inside `/morph-proposal` |
|
|
66
|
+
| 1.5 · UI/UX (optional) | `/phase-uiux <feature>` |
|
|
67
|
+
| 2 · Design | `/phase-design <feature>` |
|
|
68
|
+
| 3 · Clarify | `/phase-clarify <feature>` |
|
|
69
|
+
| 4 · Tasks | auto-generated, or `/phase-tasks <feature>` |
|
|
70
|
+
| 5 · Implement | `/morph-apply <feature>` |
|
|
71
|
+
| 6 · Sync (optional) | `morph-spec sync <feature>` |
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# Tutorial Command Implementation Plan
|
|
2
|
+
|
|
3
|
+
**Status:** COMPLETE
|
|
4
|
+
|
|
5
|
+
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
6
|
+
|
|
7
|
+
**Goal:** Add a `morph-spec tutorial` command that prints the full MORPH-SPEC phase pipeline and getting-started steps to stdout.
|
|
8
|
+
|
|
9
|
+
**Architecture:** Single new file `src/commands/project/tutorial.js` exporting `tutorialCommand`. Registered in `bin/morph-spec.js` and re-exported from `src/commands/project/index.js`. Pure stdout using `chalk` — no file I/O, no network, no side effects. Also reverts `init.js` to suggest `morph-spec tutorial` (instead of the broken replacement made in a prior session).
|
|
10
|
+
|
|
11
|
+
**Tech Stack:** Node.js ESM, chalk (already installed), node:test + node:assert for tests.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
### Task 1: Create `tutorial.js`
|
|
16
|
+
|
|
17
|
+
**Files:**
|
|
18
|
+
- Create: `src/commands/project/tutorial.js`
|
|
19
|
+
- Test: `test/commands/tutorial.test.js`
|
|
20
|
+
|
|
21
|
+
**Step 1: Write the failing test**
|
|
22
|
+
|
|
23
|
+
Create `test/commands/tutorial.test.js`:
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
import { test, describe } from 'node:test';
|
|
27
|
+
import assert from 'node:assert/strict';
|
|
28
|
+
import { tutorialCommand } from '../../src/commands/project/tutorial.js';
|
|
29
|
+
|
|
30
|
+
describe('tutorialCommand', () => {
|
|
31
|
+
test('tutorialCommand is a function', () => {
|
|
32
|
+
assert.equal(typeof tutorialCommand, 'function');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('tutorialCommand runs without throwing', () => {
|
|
36
|
+
assert.doesNotThrow(() => tutorialCommand());
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('tutorialCommand returns undefined (pure side-effect)', () => {
|
|
40
|
+
const result = tutorialCommand();
|
|
41
|
+
assert.equal(result, undefined);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Step 2: Run test to verify it fails**
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node --test test/commands/tutorial.test.js
|
|
50
|
+
```
|
|
51
|
+
Expected: FAIL — "Cannot find module"
|
|
52
|
+
|
|
53
|
+
**Step 3: Write the implementation**
|
|
54
|
+
|
|
55
|
+
Create `src/commands/project/tutorial.js`:
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
/**
|
|
59
|
+
* Tutorial Command
|
|
60
|
+
*
|
|
61
|
+
* Prints the MORPH-SPEC workflow pipeline and getting-started steps.
|
|
62
|
+
* Pure stdout — no file I/O, no network, no side effects.
|
|
63
|
+
*
|
|
64
|
+
* Usage: morph-spec tutorial
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
import chalk from 'chalk';
|
|
68
|
+
|
|
69
|
+
const PHASES = [
|
|
70
|
+
{
|
|
71
|
+
label: 'FASE 0 · PROPOSAL',
|
|
72
|
+
what: 'Captures user story + acceptance criteria.',
|
|
73
|
+
produces: '0-proposal/proposal.md',
|
|
74
|
+
how: '/morph-proposal <feature> (in Claude Code)',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
label: 'FASE 1 · SETUP',
|
|
78
|
+
what: 'Detects stack, activates agents, confirms environment.',
|
|
79
|
+
produces: '.morph/state.json initialized',
|
|
80
|
+
how: 'auto-triggered inside /morph-proposal',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
label: 'FASE 1.5 · UI/UX',
|
|
84
|
+
what: 'Design system, mockups, component specs, user flows.',
|
|
85
|
+
produces: '2-ui/{design-system,mockups,components,flows}.md',
|
|
86
|
+
how: '/phase-uiux <feature> (in Claude Code)',
|
|
87
|
+
optional: true,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
label: 'FASE 2 · DESIGN',
|
|
91
|
+
what: 'Technical spec + C# contracts + architecture decisions.',
|
|
92
|
+
produces: '1-design/{spec.md, contracts-level{N}.cs, decisions.md}',
|
|
93
|
+
how: '/phase-design <feature> (in Claude Code)',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
label: 'FASE 3 · CLARIFY',
|
|
97
|
+
what: 'Reviews spec for ambiguities, adds edge cases.',
|
|
98
|
+
produces: '1-design/spec.md (updated with clarifications)',
|
|
99
|
+
how: '/phase-clarify <feature> (in Claude Code)',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
label: 'FASE 4 · TASKS',
|
|
103
|
+
what: 'Atomic task breakdown, DDD-aware.',
|
|
104
|
+
produces: '3-tasks/tasks.md',
|
|
105
|
+
how: 'auto-generated during /morph-proposal, or /phase-tasks <feature>',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
label: 'FASE 5 · IMPLEMENT',
|
|
109
|
+
what: 'Code implementation with checkpoints every 3 tasks.',
|
|
110
|
+
produces: '4-implement/recap.md + source code',
|
|
111
|
+
how: '/morph-apply <feature> (in Claude Code)',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
label: 'FASE 6 · SYNC',
|
|
115
|
+
what: 'Syncs decisions back to project standards.',
|
|
116
|
+
produces: '.morph/framework/standards/ (updated)',
|
|
117
|
+
how: 'morph-spec sync <feature>',
|
|
118
|
+
optional: true,
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
const SEP = chalk.dim('─'.repeat(58));
|
|
123
|
+
|
|
124
|
+
export function tutorialCommand() {
|
|
125
|
+
console.log('');
|
|
126
|
+
console.log(chalk.cyan.bold(' MORPH-SPEC Workflow Tutorial'));
|
|
127
|
+
console.log(SEP);
|
|
128
|
+
console.log('');
|
|
129
|
+
console.log(
|
|
130
|
+
chalk.white(
|
|
131
|
+
' MORPH-SPEC is spec-first: every feature goes through phases\n' +
|
|
132
|
+
' before any code is written. Each phase produces structured\n' +
|
|
133
|
+
' outputs that feed the next.'
|
|
134
|
+
)
|
|
135
|
+
);
|
|
136
|
+
console.log('');
|
|
137
|
+
console.log(SEP);
|
|
138
|
+
console.log(chalk.cyan.bold(' PIPELINE'));
|
|
139
|
+
console.log(SEP);
|
|
140
|
+
console.log('');
|
|
141
|
+
console.log(
|
|
142
|
+
chalk.white(' proposal → setup → ') +
|
|
143
|
+
chalk.dim('[uiux]') +
|
|
144
|
+
chalk.white(' → design → clarify → tasks → implement → ') +
|
|
145
|
+
chalk.dim('[sync]')
|
|
146
|
+
);
|
|
147
|
+
console.log(chalk.dim(' (phases in brackets are optional)'));
|
|
148
|
+
console.log('');
|
|
149
|
+
|
|
150
|
+
for (const phase of PHASES) {
|
|
151
|
+
console.log(SEP);
|
|
152
|
+
const label = phase.optional
|
|
153
|
+
? chalk.cyan.bold(` ${phase.label}`) + chalk.dim(' [optional]')
|
|
154
|
+
: chalk.cyan.bold(` ${phase.label}`);
|
|
155
|
+
console.log(label);
|
|
156
|
+
console.log(chalk.white(` What: ${phase.what}`));
|
|
157
|
+
console.log(chalk.dim(` Produces: ${phase.produces}`));
|
|
158
|
+
console.log(chalk.green(` How: ${phase.how}`));
|
|
159
|
+
console.log('');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
console.log(SEP);
|
|
163
|
+
console.log(chalk.cyan.bold(' GETTING STARTED'));
|
|
164
|
+
console.log(SEP);
|
|
165
|
+
console.log('');
|
|
166
|
+
console.log(chalk.white(' 1. Open Claude Code in your project'));
|
|
167
|
+
console.log(chalk.white(' 2. Run: ') + chalk.green('/morph-proposal <your-feature-name>'));
|
|
168
|
+
console.log(chalk.white(' 3. Answer the questions — morph-spec handles the rest'));
|
|
169
|
+
console.log('');
|
|
170
|
+
console.log(chalk.dim(' Tip: run `morph-spec doctor` to verify your installation first.'));
|
|
171
|
+
console.log('');
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Step 4: Run test to verify it passes**
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
node --test test/commands/tutorial.test.js
|
|
179
|
+
```
|
|
180
|
+
Expected: 3 passing
|
|
181
|
+
|
|
182
|
+
**Step 5: Commit**
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
git add src/commands/project/tutorial.js test/commands/tutorial.test.js
|
|
186
|
+
git commit -m "feat(tutorial): add tutorial command with phase pipeline walkthrough"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### Task 2: Wire into project index and bin
|
|
192
|
+
|
|
193
|
+
**Files:**
|
|
194
|
+
- Modify: `src/commands/project/index.js`
|
|
195
|
+
- Modify: `bin/morph-spec.js`
|
|
196
|
+
|
|
197
|
+
**Step 1: Add export to `src/commands/project/index.js`**
|
|
198
|
+
|
|
199
|
+
After the existing `export { updateCommand }` line, add:
|
|
200
|
+
|
|
201
|
+
```js
|
|
202
|
+
export { tutorialCommand } from './tutorial.js';
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Step 2: Add import to `bin/morph-spec.js`**
|
|
206
|
+
|
|
207
|
+
After the `import { doctorCommand }` line (line ~13), add:
|
|
208
|
+
|
|
209
|
+
```js
|
|
210
|
+
import { tutorialCommand } from '../src/commands/project/tutorial.js';
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Step 3: Register the command in `bin/morph-spec.js`**
|
|
214
|
+
|
|
215
|
+
After the `doctor` command block (~line 128), add:
|
|
216
|
+
|
|
217
|
+
```js
|
|
218
|
+
program
|
|
219
|
+
.command('tutorial')
|
|
220
|
+
.description('Learn the MORPH-SPEC workflow — phase pipeline and getting started')
|
|
221
|
+
.action(tutorialCommand);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Step 4: Smoke-test the CLI**
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
node bin/morph-spec.js tutorial
|
|
228
|
+
```
|
|
229
|
+
Expected: Full pipeline output printed to terminal without errors.
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
node bin/morph-spec.js --help | grep tutorial
|
|
233
|
+
```
|
|
234
|
+
Expected: `tutorial Learn the MORPH-SPEC workflow...`
|
|
235
|
+
|
|
236
|
+
**Step 5: Commit**
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
git add src/commands/project/index.js bin/morph-spec.js
|
|
240
|
+
git commit -m "feat(tutorial): register tutorial command in CLI"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
### Task 3: Restore the `init.js` suggestion message
|
|
246
|
+
|
|
247
|
+
**Files:**
|
|
248
|
+
- Modify: `src/commands/project/init.js:518`
|
|
249
|
+
|
|
250
|
+
**Step 1: Revert the message**
|
|
251
|
+
|
|
252
|
+
Find line 518 in `src/commands/project/init.js`. Replace:
|
|
253
|
+
|
|
254
|
+
```js
|
|
255
|
+
logger.info('First time using morph-spec? Run `morph-spec doctor` to verify your setup, then `/morph-proposal <feature>` to start.');
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
With:
|
|
259
|
+
|
|
260
|
+
```js
|
|
261
|
+
logger.info('First time using morph-spec? Run `morph-spec tutorial` to get started.');
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Step 2: Verify the change**
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
grep -n "tutorial" src/commands/project/init.js
|
|
268
|
+
```
|
|
269
|
+
Expected: line 518 shows `morph-spec tutorial`
|
|
270
|
+
|
|
271
|
+
**Step 3: Commit**
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
git add src/commands/project/init.js
|
|
275
|
+
git commit -m "fix(init): restore morph-spec tutorial suggestion after command now exists"
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
### Task 4: Run full test suite
|
|
281
|
+
|
|
282
|
+
**Step 1: Run all tests**
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
node --test
|
|
286
|
+
```
|
|
287
|
+
Expected: all existing tests pass + 3 new tutorial tests pass, 0 failures.
|
|
288
|
+
|
|
289
|
+
**Step 2: If any failures, fix before continuing**
|
|
290
|
+
|
|
291
|
+
Do not proceed until `node --test` shows 0 failures.
|
|
292
|
+
|
|
293
|
+
**Step 3: Commit if any fixes were needed**
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
git add -p
|
|
297
|
+
git commit -m "fix(tutorial): address test suite issues"
|
|
298
|
+
```
|
package/framework/CLAUDE.md
CHANGED
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
proposal → setup → [uiux] → design → clarify → tasks → implement → [sync]
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
Use `morph-spec
|
|
59
|
+
Use `morph-spec status {feature}` to see current phase and pending approval gates.
|
|
60
60
|
|
|
61
61
|
---
|
|
62
62
|
|
|
@@ -74,4 +74,4 @@ MCP tools load on-demand instead of all at startup — keeps context clean for a
|
|
|
74
74
|
|
|
75
75
|
---
|
|
76
76
|
|
|
77
|
-
*MORPH-SPEC
|
|
77
|
+
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -22,9 +22,9 @@ npx morph-spec state get {feature-name}
|
|
|
22
22
|
### Workflow
|
|
23
23
|
|
|
24
24
|
1. **Detecte agentes automaticamente:**
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
- Read `.morph/framework/agents.json`
|
|
26
|
+
- Para cada agente, compare `domains` e `keywords` com a feature solicitada
|
|
27
|
+
- Registre os agentes relevantes: `npx morph-spec state add-agent {feature-name} {agent-id}`
|
|
28
28
|
|
|
29
29
|
2. **Invoque skills dos agentes detectados:**
|
|
30
30
|
- Para agentes com `skillPath` em agents.json, consulte o Skill correspondente
|
|
@@ -12,12 +12,10 @@ framework/hooks/
|
|
|
12
12
|
│ ├── user-prompt/
|
|
13
13
|
│ │ └── enrich-prompt.js # Context-aware prompt enrichment
|
|
14
14
|
│ ├── pre-tool-use/
|
|
15
|
-
│ │ ├── protect-readonly-files.js # Block edits to state.json & framework/
|
|
16
15
|
│ │ ├── protect-spec-files.js # Block edits to approved spec artifacts
|
|
17
16
|
│ │ └── enforce-phase-writes.js # Enforce writes to correct phase dir
|
|
18
17
|
│ ├── post-tool-use/
|
|
19
|
-
│ │
|
|
20
|
-
│ │ └── dispatch.js # Dispatch on CLI commands
|
|
18
|
+
│ │ └── dispatch.js # Dispatch on CLI commands (auto-checkpoint)
|
|
21
19
|
│ ├── stop/
|
|
22
20
|
│ │ └── validate-completion.js # Advisory: warn about incomplete work
|
|
23
21
|
│ ├── pre-compact/
|
|
@@ -47,13 +45,13 @@ framework/hooks/
|
|
|
47
45
|
|-------|------|------|---------|
|
|
48
46
|
| **SessionStart** | inject-morph-context.js | Inject context | Shows active feature, phase, pending approvals |
|
|
49
47
|
| **UserPromptSubmit** | enrich-prompt.js | Inject context | Warns about wrong-phase work, injects commands |
|
|
50
|
-
| **PreToolUse** (Write\|Edit) |
|
|
48
|
+
| **PreToolUse** (Write\|Edit) | _(native permissions.deny)_ | Block | Blocks edits to state.json and .morph/framework/ |
|
|
51
49
|
| **PreToolUse** (Write\|Edit) | protect-spec-files.js | Block | Blocks edits to spec files after approval |
|
|
52
50
|
| **PreToolUse** (Write\|Edit) | enforce-phase-writes.js | Block | Ensures writes go to current phase directory |
|
|
53
51
|
| **PreToolUse** (Bash) | _(prompt-type inline guard)_ | Block | Blocks `rm -rf .morph/` and direct state edits via Claude's reasoning |
|
|
54
|
-
| **PostToolUse** (Write) | track-output-creation.js | Auto-state | Marks outputs as created when files are written |
|
|
55
52
|
| **PostToolUse** (Bash) | dispatch.js | Dispatch | Triggers checkpoints on task completion |
|
|
56
|
-
| **
|
|
53
|
+
| **PostToolUseFailure** | handle-tool-failure.js | Logging | Appends structured JSON to .morph/logs/tool-failures.log |
|
|
54
|
+
| **Stop** | validate-completion.js | Advisory | Warns about incomplete tasks/missing outputs/pending gates |
|
|
57
55
|
| **PreCompact** | save-morph-context.js | Snapshot | Saves state to .morph/memory/ before compaction |
|
|
58
56
|
| **Notification** | approval-reminder.js | Advisory | Reminds about pending approval gates |
|
|
59
57
|
|
|
@@ -69,6 +67,10 @@ framework/hooks/
|
|
|
69
67
|
|
|
70
68
|
Hooks are automatically installed by `morph-spec init` and updated by `morph-spec update`.
|
|
71
69
|
|
|
70
|
+
During init/update, the entire `framework/hooks/` directory is copied to `.morph/framework/hooks/`.
|
|
71
|
+
Hook commands in `.claude/settings.local.json` reference `$CLAUDE_PROJECT_DIR/.morph/framework/hooks/`
|
|
72
|
+
so they work correctly in any project regardless of how morph-spec was installed.
|
|
73
|
+
|
|
72
74
|
The installer writes to `.claude/settings.local.json`:
|
|
73
75
|
|
|
74
76
|
```json
|
|
@@ -81,7 +83,6 @@ The installer writes to `.claude/settings.local.json`:
|
|
|
81
83
|
{ "matcher": "Bash", "hooks": [...] }
|
|
82
84
|
],
|
|
83
85
|
"PostToolUse": [
|
|
84
|
-
{ "matcher": "Write", "hooks": [...] },
|
|
85
86
|
{ "matcher": "Bash", "hooks": [...] }
|
|
86
87
|
],
|
|
87
88
|
"Stop": [{ "hooks": [...] }],
|
|
@@ -122,10 +123,10 @@ Claude calls Write/Edit tool
|
|
|
122
123
|
↓
|
|
123
124
|
Claude Code sends JSON to stdin: { tool_input: { file_path: "..." } }
|
|
124
125
|
↓
|
|
125
|
-
|
|
126
|
+
[native permissions.deny]
|
|
126
127
|
├── Is .morph/state.json? → BLOCK (use CLI)
|
|
127
128
|
├── Is .morph/framework/**? → BLOCK (read-only)
|
|
128
|
-
└── Other →
|
|
129
|
+
└── Other → continue
|
|
129
130
|
↓
|
|
130
131
|
protect-spec-files.js
|
|
131
132
|
├── Is in .morph/features/{feature}/?
|
|
@@ -198,4 +199,4 @@ morph-spec doctor --reset
|
|
|
198
199
|
|
|
199
200
|
---
|
|
200
201
|
|
|
201
|
-
*MORPH-SPEC
|
|
202
|
+
*MORPH-SPEC by Polymorphism Tech — Hooks Architecture v2.5*
|
|
@@ -46,7 +46,7 @@ function dispatch(command) {
|
|
|
46
46
|
const completed = (feature.tasks.completed || 0) + 1; // +1 because task-done hasn't executed yet
|
|
47
47
|
if (completed > 0 && completed % 3 === 0) {
|
|
48
48
|
const checkpointNum = Math.floor(completed / 3);
|
|
49
|
-
run(`
|
|
49
|
+
run(`morph-spec checkpoint-save ${featureName} --note "Auto-checkpoint #${checkpointNum} at task ${completed}"`);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
} catch {
|
|
@@ -1,58 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
2
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Blocks direct edits to:
|
|
9
|
-
* - .morph/state.json → must use CLI commands
|
|
10
|
-
* - .morph/framework/** → read-only framework files
|
|
11
|
-
*
|
|
12
|
-
* Fail-open: exits 0 on any error.
|
|
3
|
+
* DEPRECATED — This hook has been replaced by native permissions.deny in settings.local.json.
|
|
4
|
+
* The file is kept as an empty stub. It is NOT registered in hooks-installer.js.
|
|
5
|
+
* Safe to delete.
|
|
13
6
|
*/
|
|
14
|
-
|
|
15
|
-
import { readStdin } from '../../shared/stdin-reader.js';
|
|
16
|
-
import { stateExists } from '../../shared/state-reader.js';
|
|
17
|
-
import { isStatePath, isFrameworkPath } from '../../shared/phase-utils.js';
|
|
18
|
-
import { block, pass } from '../../shared/hook-response.js';
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
// Skip if not a morph-spec project
|
|
22
|
-
if (!stateExists()) {
|
|
23
|
-
pass();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const payload = await readStdin();
|
|
27
|
-
if (!payload) pass();
|
|
28
|
-
|
|
29
|
-
const filePath = payload?.tool_input?.file_path || payload?.tool_input?.path || '';
|
|
30
|
-
if (!filePath) pass();
|
|
31
|
-
|
|
32
|
-
// Block edits to state.json
|
|
33
|
-
if (isStatePath(filePath)) {
|
|
34
|
-
block(
|
|
35
|
-
'MORPH-SPEC: Direct edits to .morph/state.json are blocked.\n' +
|
|
36
|
-
'Use CLI commands instead:\n' +
|
|
37
|
-
' morph-spec state set <feature> <key> <value>\n' +
|
|
38
|
-
' morph-spec phase advance <feature>\n' +
|
|
39
|
-
' morph-spec task done <feature> <taskId>\n' +
|
|
40
|
-
' morph-spec approve <feature> <gate>'
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Block edits to framework files
|
|
45
|
-
if (isFrameworkPath(filePath)) {
|
|
46
|
-
block(
|
|
47
|
-
'MORPH-SPEC: Files in .morph/framework/ are read-only.\n' +
|
|
48
|
-
'These files are managed by the framework and overwritten on update.\n' +
|
|
49
|
-
'To customize, create project-specific overrides in .morph/context/ or .morph/config/.'
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// All other files are allowed
|
|
54
|
-
pass();
|
|
55
|
-
} catch {
|
|
56
|
-
// Fail-open
|
|
57
|
-
process.exit(0);
|
|
58
|
-
}
|
|
7
|
+
process.exit(0);
|
|
@@ -11,13 +11,26 @@
|
|
|
11
11
|
* Fail-open: exits 0 on any error.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { loadState, getActiveFeature, getPendingGates, getMissingOutputs } from '../../shared/state-reader.js';
|
|
14
|
+
import { loadState, getActiveFeature, getPendingGates, getMissingOutputs, derivePhaseForFeature } from '../../shared/state-reader.js';
|
|
15
15
|
import { stateExists } from '../../shared/state-reader.js';
|
|
16
16
|
import { injectContext, pass } from '../../shared/hook-response.js';
|
|
17
17
|
import { readFileSync, existsSync } from 'fs';
|
|
18
18
|
import { join } from 'path';
|
|
19
19
|
|
|
20
|
-
const
|
|
20
|
+
const DEFAULT_SPEC_MAX_CHARS = 3000;
|
|
21
|
+
|
|
22
|
+
function getSpecMaxChars() {
|
|
23
|
+
try {
|
|
24
|
+
const configPath = join(process.cwd(), '.morph/config/config.json');
|
|
25
|
+
if (!existsSync(configPath)) return DEFAULT_SPEC_MAX_CHARS;
|
|
26
|
+
const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
27
|
+
return cfg?.hooks?.specInjectionLimit ?? DEFAULT_SPEC_MAX_CHARS;
|
|
28
|
+
} catch {
|
|
29
|
+
return DEFAULT_SPEC_MAX_CHARS;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const SPEC_MAX_CHARS = getSpecMaxChars();
|
|
21
34
|
|
|
22
35
|
try {
|
|
23
36
|
if (!stateExists()) pass();
|
|
@@ -30,7 +43,8 @@ try {
|
|
|
30
43
|
|
|
31
44
|
if (active) {
|
|
32
45
|
const { name, feature } = active;
|
|
33
|
-
|
|
46
|
+
const phase = derivePhaseForFeature(name);
|
|
47
|
+
lines.push(`- Active feature: ${name} (phase: ${phase}, workflow: ${feature.workflow || 'auto'})`);
|
|
34
48
|
lines.push(`- Status: ${feature.status}`);
|
|
35
49
|
|
|
36
50
|
// Task progress
|
|
@@ -78,8 +92,9 @@ try {
|
|
|
78
92
|
const featureNames = Object.keys(state.features);
|
|
79
93
|
lines.push(`- Features: ${featureNames.length} (${featureNames.join(', ')})`);
|
|
80
94
|
|
|
81
|
-
for (const [
|
|
82
|
-
|
|
95
|
+
for (const [fname, feat] of Object.entries(state.features)) {
|
|
96
|
+
const fPhase = derivePhaseForFeature(fname);
|
|
97
|
+
lines.push(` - ${fname}: phase=${fPhase}, status=${feat.status}`);
|
|
83
98
|
}
|
|
84
99
|
}
|
|
85
100
|
|
|
@@ -347,7 +347,12 @@ def get_session_name(entries):
|
|
|
347
347
|
def get_block_start(transcript_path, entries):
|
|
348
348
|
"""Find start of current 5-hour billing block. Cached per transcript."""
|
|
349
349
|
h = hashlib.sha256(transcript_path.encode()).hexdigest()[:16]
|
|
350
|
-
|
|
350
|
+
# Use platform-appropriate cache directory
|
|
351
|
+
if os.name == 'nt':
|
|
352
|
+
base = Path(os.environ.get('LOCALAPPDATA', str(Path.home() / 'AppData' / 'Local')))
|
|
353
|
+
cache_dir = base / 'morph-spec' / 'cache'
|
|
354
|
+
else:
|
|
355
|
+
cache_dir = Path.home() / '.cache' / 'morph-spec'
|
|
351
356
|
cache_file = cache_dir / f'block-{h}.json'
|
|
352
357
|
now = time.time()
|
|
353
358
|
block_s = 5 * 3600
|
|
@@ -58,7 +58,7 @@ try {
|
|
|
58
58
|
// Check pending approval gates
|
|
59
59
|
if (feature.approvalGates) {
|
|
60
60
|
const pendingGates = Object.entries(feature.approvalGates)
|
|
61
|
-
.filter(([, gate]) => !gate.approved && gate.timestamp
|
|
61
|
+
.filter(([, gate]) => !gate.approved && !gate.timestamp)
|
|
62
62
|
.map(([name]) => name);
|
|
63
63
|
|
|
64
64
|
// Only warn about gates relevant to current/past phases
|
|
@@ -24,7 +24,7 @@ try {
|
|
|
24
24
|
const payload = await readStdin();
|
|
25
25
|
if (!payload) pass();
|
|
26
26
|
|
|
27
|
-
const userPrompt = payload?.user_prompt || payload?.content || '';
|
|
27
|
+
const userPrompt = payload?.prompt || payload?.user_prompt || payload?.content || '';
|
|
28
28
|
if (!userPrompt || userPrompt.length < 3) pass();
|
|
29
29
|
|
|
30
30
|
const promptLower = userPrompt.toLowerCase();
|