@polymorphism-tech/morph-spec 7.1.1 → 7.3.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 (66) hide show
  1. package/README.md +2 -2
  2. package/claude-plugin.json +1 -1
  3. package/docs/CHEATSHEET.md +1 -1
  4. package/docs/QUICKSTART.md +1 -1
  5. package/framework/CLAUDE.md +4 -2
  6. package/framework/MORPH.md +3 -3
  7. package/framework/commands/morph-apply.md +1 -1
  8. package/framework/commands/morph-proposal.md +1 -1
  9. package/framework/hooks/README.md +1 -1
  10. package/framework/hooks/claude-code/core/protect-spec-files.js +193 -72
  11. package/framework/hooks/claude-code/core/validate-completion.js +136 -136
  12. package/framework/hooks/shared/phase-utils.js +10 -0
  13. package/framework/phases.json +1 -1
  14. package/framework/rules/morph-workflow.md +16 -9
  15. package/framework/skills/README.md +1 -1
  16. package/framework/skills/core/morph-apply/SKILL.md +1 -0
  17. package/framework/skills/core/morph-brainstorming/SKILL.md +1 -0
  18. package/framework/skills/core/morph-eval/SKILL.md +1 -0
  19. package/framework/skills/core/morph-implement/SKILL.md +7 -0
  20. package/framework/skills/core/morph-plan/SKILL.md +1 -0
  21. package/framework/skills/core/morph-proposal/SKILL.md +1 -0
  22. package/framework/skills/core/morph-review/SKILL.md +1 -0
  23. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -0
  24. package/framework/skills/core/morph-standards/SKILL.md +1 -0
  25. package/framework/templates/README.md +708 -709
  26. package/framework/templates/REGISTRY.json +1 -20
  27. package/framework/templates/context/CONTEXT-FEATURE.md +276 -276
  28. package/framework/templates/docs/proposal.md +171 -171
  29. package/framework/templates/feature/recap.md +145 -145
  30. package/package.json +1 -1
  31. package/src/commands/project/doctor.js +941 -946
  32. package/src/commands/project/status.js +373 -376
  33. package/src/commands/validation/validate-feature.js +315 -287
  34. package/src/core/paths/output-schema.js +18 -1
  35. package/src/core/state/state-manager.js +900 -934
  36. package/src/dashboard/app/App.jsx +29 -31
  37. package/src/dashboard/app/components/Sidebar.jsx +44 -45
  38. package/src/dashboard/scanner/index.js +20 -21
  39. package/src/lib/context/context-builder.js +3 -3
  40. package/src/lib/generators/context-generator.js +2 -3
  41. package/src/lib/generators/mandate-generator.js +48 -92
  42. package/src/lib/generators/metadata-extractor.js +385 -386
  43. package/src/lib/generators/recap-generator.js +285 -285
  44. package/src/lib/validators/content/content-validator.js +89 -286
  45. package/src/lib/validators/content/index.js +0 -1
  46. package/framework/templates/feature/tasks.md +0 -199
  47. package/framework/workflows/README.md +0 -1041
  48. package/framework/workflows/configs/fast-track.json +0 -46
  49. package/framework/workflows/configs/full.json +0 -64
  50. package/framework/workflows/configs/quick.json +0 -32
  51. package/framework/workflows/configs/standard.json +0 -57
  52. package/framework/workflows/docs/STORY-DRIVEN-DEVELOPMENT.md +0 -392
  53. package/framework/workflows/docs/design-impl.md +0 -37
  54. package/framework/workflows/docs/enforcement-pipeline.md +0 -668
  55. package/framework/workflows/docs/fast-track.md +0 -29
  56. package/framework/workflows/docs/full-morph.md +0 -69
  57. package/framework/workflows/docs/standard.md +0 -49
  58. package/framework/workflows/docs/ui-refresh.md +0 -39
  59. package/src/commands/state/index.js +0 -7
  60. package/src/core/workflows/workflow-detector.js +0 -586
  61. package/src/core/workflows/workflow-router.js +0 -204
  62. package/src/dashboard/app/pages/Workflows.jsx +0 -346
  63. package/src/dashboard/scanner/workflows-scanner.js +0 -18
  64. package/src/lib/phase-chain/phase-validator.js +0 -359
  65. package/src/lib/validators/content/cross-phase-validator.js +0 -281
  66. package/src/lib/validators/spec-validator.js +0 -312
@@ -1,136 +1,136 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Stop Hook: Phase Transition Alert + Build Check + Session Snapshot
5
- *
6
- * Event: Stop
7
- *
8
- * 1. Detects transitions into the `implement` phase and recommends /compact.
9
- * 2. Runs stack-aware build check — warns only on failure (silent on pass).
10
- * 3. Saves session snapshot for next-session orientation.
11
- *
12
- * Phase transition tracking: stores last-seen phase per feature in
13
- * .morph/memory/phase-watch.json so the alert fires exactly once.
14
- *
15
- * Fail-open: exits 0 on any error.
16
- */
17
-
18
- import { readFileSync, writeFileSync, existsSync } from 'fs';
19
- import { join } from 'path';
20
- import { runBuildCheck } from '../../shared/build-check.js';
21
- import { saveSessionSnapshot } from '../../shared/session-snapshot.js';
22
- import {
23
- stateExists, getActiveFeature, getMostRecentFeature, derivePhaseForFeature,
24
- } from '../../shared/state-reader.js';
25
- import { injectContext, pass } from '../../shared/hook-response.js';
26
- import { logHookActivity, logEvent } from '../../shared/activity-logger.js';
27
-
28
- // Phases where compaction is strongly recommended before starting
29
- const COMPACT_TRIGGER_PHASES = new Set(['implement']);
30
-
31
- // Phases where compaction is suggested when arriving (heavy spec phases)
32
- const HEAVY_SOURCE_PHASES = new Set(['plan', 'uiux']);
33
-
34
- try {
35
- // Prevent infinite loop
36
- if (process.env.MORPH_STOP_HOOK_ACTIVE === '1') pass();
37
-
38
- if (!stateExists()) pass();
39
-
40
- // getActiveFeature() only returns in_progress/draft features.
41
- // Fall back to the most recently updated feature when all features are 'done'.
42
- let active = getActiveFeature() || getMostRecentFeature();
43
- if (!active) pass();
44
-
45
- const { name, feature } = active;
46
- const cwd = process.cwd();
47
- const warnings = [];
48
-
49
- // ── Phase transition detection ────────────────────────────────────────────
50
- const currentPhase = feature.phase || derivePhaseForFeature(name, cwd);
51
-
52
- const watchPath = join(cwd, '.morph', 'memory', 'phase-watch.json');
53
- let phaseWatch = {};
54
- try {
55
- if (existsSync(watchPath)) phaseWatch = JSON.parse(readFileSync(watchPath, 'utf-8'));
56
- } catch { /* corrupt file — start fresh */ }
57
-
58
- const lastPhase = phaseWatch[name];
59
-
60
- // Update stored phase (always, so the alert only fires once per transition)
61
- try {
62
- phaseWatch[name] = currentPhase;
63
- writeFileSync(watchPath, JSON.stringify(phaseWatch, null, 2), 'utf-8');
64
- } catch { /* non-blocking */ }
65
-
66
- // Alert when entering implement from a heavy spec phase
67
- const isPhaseTransition = lastPhase && lastPhase !== currentPhase;
68
- const enteringImplement = COMPACT_TRIGGER_PHASES.has(currentPhase);
69
- const comingFromHeavyPhase = HEAVY_SOURCE_PHASES.has(lastPhase);
70
-
71
- if (isPhaseTransition && enteringImplement && comingFromHeavyPhase) {
72
- warnings.push(
73
- `⚡ Phase advanced: ${lastPhase} → implement`,
74
- ``,
75
- `💡 Recommended before starting implementation:`,
76
- ` Run /compact to free up context — spec.md, mandate.md and tasks.md`,
77
- ` loaded during planning take significant space. A compact now gives`,
78
- ` Claude a clean slate focused on writing code.`,
79
- ``,
80
- ` After /compact, resume with: /morph-apply ${name}`,
81
- );
82
- }
83
-
84
- // ── Build/typecheck verification ──────────────────────────────────────────
85
- // Stack-aware build check — advisory warning if build fails.
86
- // Success is silent (no output on pass).
87
- try {
88
- const configPath = join(cwd, '.morph', 'config', 'config.json');
89
- if (existsSync(configPath)) {
90
- const config = JSON.parse(readFileSync(configPath, 'utf-8'));
91
- const stack = config?.project?.stack;
92
- if (stack && currentPhase === 'implement') {
93
- const buildResult = runBuildCheck(cwd, stack);
94
- if (buildResult.status === 'fail') {
95
- warnings.push('⚠ Build/typecheck failed:');
96
- warnings.push(buildResult.output);
97
- warnings.push('Fix build errors before ending session.');
98
- }
99
- // pass and skip → silent (success is silent)
100
- }
101
- }
102
- } catch {
103
- // Fail-open — build check must never block Stop
104
- }
105
- // ────────────────────────────────────────────────────────────────────────
106
-
107
- // ── Session snapshot ──────────────────────────────────────────────────────
108
- // Save session state for next session's "getting up to speed" routine.
109
- try {
110
- if (active) {
111
- const { name } = active;
112
- saveSessionSnapshot({
113
- feature: name,
114
- phase: currentPhase,
115
- buildStatus: 'skip',
116
- lastEditedFiles: [],
117
- }, cwd);
118
- }
119
- } catch {
120
- // Fail-open — snapshot save must never block Stop
121
- }
122
- // ────────────────────────────────────────────────────────────────────────
123
-
124
- if (warnings.length === 0) pass();
125
-
126
- const message = [
127
- 'MORPH-SPEC:',
128
- ...warnings.map(w => ` ${w}`),
129
- ].join('\n');
130
-
131
- logHookActivity('validate-completion', 'Stop', `warnings(${warnings.length})`);
132
- logEvent('session_end', { feature: name, phase: currentPhase, warnings: warnings.length });
133
- injectContext(message);
134
- } catch {
135
- process.exit(0);
136
- }
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Stop Hook: Phase Transition Alert + Build Check + Session Snapshot
5
+ *
6
+ * Event: Stop
7
+ *
8
+ * 1. Detects transitions into the `implement` phase and recommends /compact.
9
+ * 2. Runs stack-aware build check — warns only on failure (silent on pass).
10
+ * 3. Saves session snapshot for next-session orientation.
11
+ *
12
+ * Phase transition tracking: stores last-seen phase per feature in
13
+ * .morph/memory/phase-watch.json so the alert fires exactly once.
14
+ *
15
+ * Fail-open: exits 0 on any error.
16
+ */
17
+
18
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
19
+ import { join } from 'path';
20
+ import { runBuildCheck } from '../../shared/build-check.js';
21
+ import { saveSessionSnapshot } from '../../shared/session-snapshot.js';
22
+ import {
23
+ stateExists, getActiveFeature, getMostRecentFeature, derivePhaseForFeature,
24
+ } from '../../shared/state-reader.js';
25
+ import { injectContext, pass } from '../../shared/hook-response.js';
26
+ import { logHookActivity, logEvent } from '../../shared/activity-logger.js';
27
+
28
+ // Phases where compaction is strongly recommended before starting
29
+ const COMPACT_TRIGGER_PHASES = new Set(['implement']);
30
+
31
+ // Phases where compaction is suggested when arriving (heavy spec phases)
32
+ const HEAVY_SOURCE_PHASES = new Set(['plan', 'uiux']);
33
+
34
+ try {
35
+ // Prevent infinite loop
36
+ if (process.env.MORPH_STOP_HOOK_ACTIVE === '1') pass();
37
+
38
+ if (!stateExists()) pass();
39
+
40
+ // getActiveFeature() only returns in_progress/draft features.
41
+ // Fall back to the most recently updated feature when all features are 'done'.
42
+ let active = getActiveFeature() || getMostRecentFeature();
43
+ if (!active) pass();
44
+
45
+ const { name, feature } = active;
46
+ const cwd = process.cwd();
47
+ const warnings = [];
48
+
49
+ // ── Phase transition detection ────────────────────────────────────────────
50
+ const currentPhase = feature.phase || derivePhaseForFeature(name, cwd);
51
+
52
+ const watchPath = join(cwd, '.morph', 'memory', 'phase-watch.json');
53
+ let phaseWatch = {};
54
+ try {
55
+ if (existsSync(watchPath)) phaseWatch = JSON.parse(readFileSync(watchPath, 'utf-8'));
56
+ } catch { /* corrupt file — start fresh */ }
57
+
58
+ const lastPhase = phaseWatch[name];
59
+
60
+ // Update stored phase (always, so the alert only fires once per transition)
61
+ try {
62
+ phaseWatch[name] = currentPhase;
63
+ writeFileSync(watchPath, JSON.stringify(phaseWatch, null, 2), 'utf-8');
64
+ } catch { /* non-blocking */ }
65
+
66
+ // Alert when entering implement from a heavy spec phase
67
+ const isPhaseTransition = lastPhase && lastPhase !== currentPhase;
68
+ const enteringImplement = COMPACT_TRIGGER_PHASES.has(currentPhase);
69
+ const comingFromHeavyPhase = HEAVY_SOURCE_PHASES.has(lastPhase);
70
+
71
+ if (isPhaseTransition && enteringImplement && comingFromHeavyPhase) {
72
+ warnings.push(
73
+ `⚡ Phase advanced: ${lastPhase} → implement`,
74
+ ``,
75
+ `💡 Recommended before starting implementation:`,
76
+ ` Run /compact to free up context — spec.md, mandate.md and tasks.json`,
77
+ ` loaded during planning take significant space. A compact now gives`,
78
+ ` Claude a clean slate focused on writing code.`,
79
+ ``,
80
+ ` After /compact, resume with: /morph-apply ${name}`,
81
+ );
82
+ }
83
+
84
+ // ── Build/typecheck verification ──────────────────────────────────────────
85
+ // Stack-aware build check — advisory warning if build fails.
86
+ // Success is silent (no output on pass).
87
+ try {
88
+ const configPath = join(cwd, '.morph', 'config', 'config.json');
89
+ if (existsSync(configPath)) {
90
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
91
+ const stack = config?.project?.stack;
92
+ if (stack && currentPhase === 'implement') {
93
+ const buildResult = runBuildCheck(cwd, stack);
94
+ if (buildResult.status === 'fail') {
95
+ warnings.push('⚠ Build/typecheck failed:');
96
+ warnings.push(buildResult.output);
97
+ warnings.push('Fix build errors before ending session.');
98
+ }
99
+ // pass and skip → silent (success is silent)
100
+ }
101
+ }
102
+ } catch {
103
+ // Fail-open — build check must never block Stop
104
+ }
105
+ // ────────────────────────────────────────────────────────────────────────
106
+
107
+ // ── Session snapshot ──────────────────────────────────────────────────────
108
+ // Save session state for next session's "getting up to speed" routine.
109
+ try {
110
+ if (active) {
111
+ const { name } = active;
112
+ saveSessionSnapshot({
113
+ feature: name,
114
+ phase: currentPhase,
115
+ buildStatus: 'skip',
116
+ lastEditedFiles: [],
117
+ }, cwd);
118
+ }
119
+ } catch {
120
+ // Fail-open — snapshot save must never block Stop
121
+ }
122
+ // ────────────────────────────────────────────────────────────────────────
123
+
124
+ if (warnings.length === 0) pass();
125
+
126
+ const message = [
127
+ 'MORPH-SPEC:',
128
+ ...warnings.map(w => ` ${w}`),
129
+ ].join('\n');
130
+
131
+ logHookActivity('validate-completion', 'Stop', `warnings(${warnings.length})`);
132
+ logEvent('session_end', { feature: name, phase: currentPhase, warnings: warnings.length });
133
+ injectContext(message);
134
+ } catch {
135
+ process.exit(0);
136
+ }
@@ -65,6 +65,16 @@ export const PROTECTED_SPEC_FILES = {
65
65
  'tasks.json': 'plan',
66
66
  };
67
67
 
68
+ /**
69
+ * For protected files that carry mutable progress fields: filename → the
70
+ * top-level array-item fields that may change after the gate is approved.
71
+ * When a protected file is listed here, the protect-spec-files hook does a
72
+ * semantic diff (allowing only these fields to change) instead of a blanket block.
73
+ */
74
+ export const MUTABLE_SPEC_FIELDS = {
75
+ 'tasks.json': ['status', 'outputs', 'notes'],
76
+ };
77
+
68
78
  /**
69
79
  * Extract feature name from a .morph/features/{feature}/... path
70
80
  * @param {string} filePath - File path to analyze
@@ -43,7 +43,7 @@
43
43
  "goals": [
44
44
  "Write spec.md (technical spec)",
45
45
  "Write mandate.md (implementation contract with stack defaults + forbidden patterns)",
46
- "Write tasks.md (ordered task breakdown)"
46
+ "Write tasks.json (ordered task breakdown)"
47
47
  ],
48
48
  "requiredOutputs": ["spec", "mandate", "tasks"],
49
49
  "optionalOutputs": ["decisions"],
@@ -125,19 +125,26 @@ After making structural changes (new packages, dependencies, project config chan
125
125
 
126
126
  BEFORE implementing ANY task during the implement phase:
127
127
 
128
- 1. **Read tasks.md** → identify the FR references for the current task (e.g., `[FR001, FR003]`)
129
- 2. **Read spec.md** → the sections for those specific FRs
130
- 3. **Read contracts.cs/.ts** → the DTOs/interfaces referenced by those FRs
128
+ 1. **Read tasks.json** → identify the current task object (`id`, `description`, `doneCriteria`, `dependencies`)
129
+ 2. **Read spec.md** → the FR sections that the task `description` references
130
+ 3. **Read the contracts** → the DTOs/interfaces are defined inside `spec.md` (v5 keeps contracts in the spec, not separate files)
131
131
  4. Only then begin implementation
132
132
 
133
133
  This is **NON-NEGOTIABLE**. The spec is the source of truth. Code that doesn't match the spec is a bug.
134
134
 
135
- Every task in `tasks.md` MUST have FR cross-references in this format:
136
- ```
137
- ### T001: Create user endpoint [FR001, FR003]
138
- - **Spec refs:** FR001 (user CRUD), FR003 (input validation)
139
- - **Contracts:** CreateUserRequest, CreateUserResponse, UserErrors
140
- - **Files:** Features/UserFeature/Create/Handler.cs, Validator.cs, Endpoint.cs
135
+ Every task in `tasks.json` MUST reference its FR(s) in the `description` field so the link to the spec is explicit:
136
+ ```json
137
+ {
138
+ "id": "T1",
139
+ "title": "Create user endpoint",
140
+ "description": "Implement user CRUD (FR001) and input validation (FR003). Contracts: CreateUserRequest, CreateUserResponse, UserErrors.",
141
+ "dependencies": [],
142
+ "effort": "M",
143
+ "doneCriteria": "POST /users creates a user and rejects invalid input",
144
+ "status": "pending",
145
+ "outputs": ["Features/UserFeature/Create/Handler.cs", "Validator.cs", "Endpoint.cs"],
146
+ "group": "backend"
147
+ }
141
148
  ```
142
149
 
143
150
  ---
@@ -14,7 +14,7 @@ These are the only skills the harness needs. MORPH.md references them by path.
14
14
  |----------------------|----------------------------------------------------------------------|----------------|
15
15
  | `morph-brainstorming` | Business understanding + brownfield scan → proposal.md (Gate 1) | yes |
16
16
  | `morph-stack-scan` | Detect stack drift in existing projects, generate migration-plan.md | yes |
17
- | `morph-plan` | Produce spec.md + mandate.md + tasks.md (Gate 2) | yes |
17
+ | `morph-plan` | Produce spec.md + mandate.md + tasks.json (Gate 2) | yes |
18
18
  | `morph-implement` | Execute each task with standard + persona, auto-advance between tasks| no |
19
19
  | `morph-eval` | Score work 0-10 across 4 dimensions, silence on score >= 8 | no |
20
20
  | `morph-review` | Final review report with scores + recommendation (Gate 3) | yes |
@@ -4,6 +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.3.0"
7
8
  ---
8
9
 
9
10
  # morph-apply
@@ -4,6 +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.3.0"
7
8
  ---
8
9
 
9
10
  # morph-brainstorming
@@ -4,6 +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.3.0"
7
8
  ---
8
9
 
9
10
  # morph-eval
@@ -4,6 +4,7 @@ description: Guia a execução de cada tarefa de implementação com standard e
4
4
  version: core
5
5
  when-to-invoke: ao iniciar cada task de implementação listada em tasks.json
6
6
  user-invokable: false
7
+ cliVersion: "7.3.0"
7
8
  ---
8
9
 
9
10
  # morph-implement
@@ -78,6 +79,12 @@ Ao iniciar cada task de `tasks.json` — antes de escrever qualquer código. Nor
78
79
  await writeTasksJson(tasksPath, data);
79
80
  ```
80
81
 
82
+ `tasks.json` é protegido após o Gate 2, mas os campos de progresso (`status`,
83
+ `outputs`, `notes`) continuam graváveis durante a fase implement. `writeTasksJson`
84
+ grava o arquivo **inteiro** (Write) — esse é o caminho permitido. Nunca use a
85
+ tool `Edit` em `tasks.json` após o Gate 2: o hook `protect-spec-files` bloqueia
86
+ Edit e qualquer mudança em campos de plano (`title`, `dependencies`, `doneCriteria`…).
87
+
81
88
  9. Quando invocada por `morph-apply`, retornar o controle à skill orquestradora — ela decide qual task vem em seguida via `getReadyTasks(data)`. Quando invocada manualmente, verificar se há próxima task ready e iniciá-la imediatamente aplicando esta skill desde o passo 1 (auto-advance). Pause apenas se encontrar ambiguidade bloqueante não coberta pelo mandate.
82
89
 
83
90
  ## Output esperado
@@ -4,6 +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.3.0"
7
8
  ---
8
9
 
9
10
  # morph-plan
@@ -4,6 +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.3.0"
7
8
  ---
8
9
 
9
10
  # morph-proposal
@@ -4,6 +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.3.0"
7
8
  ---
8
9
 
9
10
  # morph-review
@@ -4,6 +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.3.0"
7
8
  ---
8
9
 
9
10
  # morph-stack-scan
@@ -4,6 +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.3.0"
7
8
  ---
8
9
 
9
10
  # morph-standards