@polymorphism-tech/morph-spec 8.33.0 → 8.34.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/CLAUDE.md +3 -0
- package/README.md +2 -2
- package/bin/morph-spec.js +25 -1
- package/bin/validate.js +379 -379
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +2 -2
- package/framework/MORPH.md +4 -5
- package/framework/agents.json +1 -0
- package/framework/docs/CLI.md +5 -2
- package/framework/hooks/README.md +11 -1
- package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +5 -8
- package/framework/hooks/claude-code/core/block-raw-worktree-add.js +79 -0
- package/framework/hooks/claude-code/core/chain.js +27 -7
- package/framework/hooks/claude-code/core/worktree-context.js +83 -14
- package/framework/hooks/claude-code/core/worktree-create.js +206 -0
- package/framework/hooks/claude-code/core/worktree-env-inject.js +87 -0
- package/framework/hooks/claude-code/core/worktree-remove.js +81 -0
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/hooks/git/commit-msg/conventional-commits.sh +33 -33
- package/framework/hooks/git/pre-commit/agents.sh +25 -25
- package/framework/hooks/git/pre-commit/orchestrator.sh +64 -64
- package/framework/hooks/git/pre-commit/specs.sh +50 -50
- package/framework/hooks/git/pre-push/run-tests.sh +44 -44
- package/framework/hooks/shared/command-tokens.js +23 -0
- package/framework/hooks/shared/e2e-check.js +0 -0
- package/framework/hooks/shared/git-paths.js +25 -0
- package/framework/hooks/shared/hook-response.js +17 -0
- package/framework/hooks/shared/morph-cli.js +134 -0
- package/framework/hooks/shared/stdin-reader.js +26 -26
- package/framework/rules/infrastructure-standards.md +3 -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 +3 -3
- 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-hotfix/SKILL.md +1 -1
- package/framework/skills/core/morph-implement/SKILL.md +3 -1
- package/framework/skills/core/morph-plan/SKILL.md +6 -3
- 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/framework/skills/core/morph-uiux/SKILL.md +1 -1
- package/framework/standards/STANDARDS.json +30 -0
- package/framework/standards/ai-agents/agent-session.md +160 -160
- package/framework/standards/ai-agents/batching.md +193 -193
- package/framework/standards/ai-agents/context-providers.md +188 -188
- package/framework/standards/ai-agents/mcp-server.md +250 -250
- package/framework/standards/ai-agents/mcp-tools.md +197 -197
- package/framework/standards/ai-agents/middleware-patterns.md +207 -207
- package/framework/standards/ai-agents/modalities-image-gen.md +173 -173
- package/framework/standards/ai-agents/modalities-speech-to-text.md +171 -171
- package/framework/standards/ai-agents/modalities-text-to-speech.md +181 -181
- package/framework/standards/ai-agents/modalities-vision.md +201 -201
- package/framework/standards/ai-agents/multi-agent-patterns.md +155 -155
- package/framework/standards/ai-agents/production.md +231 -231
- package/framework/standards/ai-agents/prompts-in-db.md +214 -214
- package/framework/standards/ai-agents/providers/model-registry.md +158 -158
- package/framework/standards/ai-agents/service-tier-flex.md +135 -135
- package/framework/standards/ai-agents/structured-output.md +249 -249
- package/framework/standards/ai-agents/sweet-spot.md +109 -109
- package/framework/standards/infrastructure/docker/local-compose-isolation.md +88 -0
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- package/framework/templates/REGISTRY.json +1 -1
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -39
- package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -68
- package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -117
- package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -95
- package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -61
- package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -107
- package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -58
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +281 -281
- package/framework/templates/code/dotnet/database/migration.cs +83 -83
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -15
- package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -58
- package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
- package/framework/templates/code/typescript/contracts.ts +167 -167
- package/framework/templates/docs/clarifications.md +253 -253
- package/framework/templates/docs/schema-analysis.md +119 -119
- package/framework/templates/docs/ui-components.md +52 -52
- package/framework/templates/docs/ui-design-system.md +76 -76
- package/framework/templates/docs/ui-flows.md +167 -167
- package/framework/templates/docs/ui-mockups.md +98 -98
- package/framework/templates/feature/decisions.md +122 -122
- package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -43
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/env.mjs.hbs +32 -32
- package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
- package/framework/templates/frontend/nextjs/page.tsx.hbs +22 -22
- package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
- package/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -54
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
- package/framework/templates/infrastructure/docker/docker-compose.template.yml +24 -14
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/github/README.md +56 -56
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
- package/framework/templates/integrations/asaas-client.cs +387 -387
- package/framework/templates/integrations/asaas-webhook.cs +351 -351
- package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -95
- package/framework/templates/project/validate.js +120 -120
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +1 -1
- package/src/commands/dashboard/dashboard.js +53 -53
- package/src/commands/e2e/e2e.js +77 -39
- package/src/commands/index.js +13 -13
- package/src/commands/project/checkpoint.js +209 -209
- package/src/commands/project/doctor.js +8 -6
- package/src/commands/project/env.js +95 -0
- package/src/commands/project/worktree.js +266 -52
- package/src/commands/state/delete.js +8 -0
- package/src/commands/state/finish.js +29 -34
- package/src/core/state/phase-state-machine.js +197 -197
- package/src/core/templates/template-renderer.js +477 -477
- package/src/dashboard/app/components/DetailPanel.jsx +11 -11
- package/src/dashboard/app/components/FlowGraph.jsx +17 -17
- package/src/dashboard/app/components/SearchFilter.jsx +22 -22
- package/src/dashboard/app/hooks/useDetailPanel.js +15 -15
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/AgentMap.jsx +370 -370
- package/src/dashboard/app/pages/HookInspector.jsx +430 -418
- package/src/dashboard/app/pages/PhasePipeline.jsx +408 -408
- package/src/dashboard/app/pages/RulesMap.jsx +273 -273
- package/src/dashboard/app/pages/SkillsLibrary.jsx +366 -366
- package/src/dashboard/app/pages/Standards.jsx +332 -332
- package/src/dashboard/app/styles/index.css +47 -47
- package/src/dashboard/index.html +12 -12
- package/src/dashboard/package.json +24 -24
- package/src/dashboard/scanner/hooks-scanner.js +5 -1
- package/src/dashboard/scanner/phases-scanner.js +15 -15
- package/src/dashboard/scanner/rubrics-scanner.js +12 -12
- package/src/dashboard/scanner/rules-scanner.js +37 -37
- package/src/dashboard/scanner/skills-scanner.js +43 -43
- package/src/dashboard/scanner/squads-scanner.js +13 -13
- package/src/dashboard/vite-plugin-morph-data.js +17 -17
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/detectors/design-system-detector.js +188 -188
- package/src/lib/detectors/index.js +217 -217
- package/src/lib/e2e/compose-env.js +6 -11
- package/src/lib/e2e/stack-teardown.js +115 -0
- package/src/lib/generators/architecture-scanner.js +2 -1
- package/src/lib/generators/design-system-generator.js +508 -508
- package/src/lib/generators/settings-generator.js +209 -209
- package/src/lib/graph/graphifyignore.js +2 -1
- package/src/lib/hooks/hook-executor.js +167 -167
- package/src/lib/installers/mcp-installer.js +719 -719
- package/src/lib/tasks/task-classifier.js +30 -30
- package/src/lib/tasks/task-parser.js +209 -209
- package/src/lib/tasks/test-runner.js +21 -4
- package/src/lib/validators/checkpoint-persistence.js +39 -39
- package/src/lib/validators/css/css-validator.js +340 -340
- package/src/lib/validators/shared/emit-validator-dispatch.js +14 -14
- package/src/lib/validators/shared/issue-counter.js +14 -14
- package/src/lib/validators/verify-runner.js +7 -0
- package/src/lib/worktree/dirs.js +32 -0
- package/src/lib/worktree/env-allocator.js +45 -11
- package/src/lib/worktree/worktree-audit.js +40 -2
- package/src/utils/agent-id-mapper.js +11 -11
- package/src/utils/claude-settings-manager.js +300 -300
- package/src/utils/file-copier.js +18 -13
- package/src/utils/hooks-installer.js +46 -3
- package/src/utils/skills-installer.js +187 -187
- package/framework/templates/.idea/morph-templates.xml +0 -92
- package/framework/templates/.vscode/morph-templates.code-snippets +0 -186
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Scope: universal | Validates spec.md required sections
|
|
3
|
-
# MORPH-SPEC Pre-Commit Hook: Spec Validation
|
|
4
|
-
# Validates that spec.md files have required sections
|
|
5
|
-
|
|
6
|
-
echo "🔍 Validating spec files..."
|
|
7
|
-
|
|
8
|
-
# Find modified spec.md files
|
|
9
|
-
SPEC_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep 'spec\.md$')
|
|
10
|
-
|
|
11
|
-
if [ -z "$SPEC_FILES" ]; then
|
|
12
|
-
echo "✓ No spec files modified"
|
|
13
|
-
exit 0
|
|
14
|
-
fi
|
|
15
|
-
|
|
16
|
-
HAS_ERRORS=false
|
|
17
|
-
|
|
18
|
-
for spec_file in $SPEC_FILES; do
|
|
19
|
-
echo "Checking: $spec_file"
|
|
20
|
-
|
|
21
|
-
# Required sections
|
|
22
|
-
REQUIRED_SECTIONS=(
|
|
23
|
-
"## 📋 Metadata"
|
|
24
|
-
"## 🎯 Overview"
|
|
25
|
-
"## 🏗️ Technical Design"
|
|
26
|
-
"## ✅ Acceptance Criteria"
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
for section in "${REQUIRED_SECTIONS[@]}"; do
|
|
30
|
-
if ! grep -q "$section" "$spec_file"; then
|
|
31
|
-
echo " ❌ Missing section: $section"
|
|
32
|
-
HAS_ERRORS=true
|
|
33
|
-
fi
|
|
34
|
-
done
|
|
35
|
-
|
|
36
|
-
# Check if has at least one user story or requirement
|
|
37
|
-
if ! grep -qi "user story\|requirement\|acceptance criteria" "$spec_file"; then
|
|
38
|
-
echo " ⚠️ Warning: No user stories or requirements found"
|
|
39
|
-
fi
|
|
40
|
-
done
|
|
41
|
-
|
|
42
|
-
if [ "$HAS_ERRORS" = true ]; then
|
|
43
|
-
echo ""
|
|
44
|
-
echo "❌ COMMIT BLOCKED: spec.md files are incomplete"
|
|
45
|
-
echo " Add missing sections before committing"
|
|
46
|
-
exit 1
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
echo "✓ All spec files are valid"
|
|
50
|
-
exit 0
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Scope: universal | Validates spec.md required sections
|
|
3
|
+
# MORPH-SPEC Pre-Commit Hook: Spec Validation
|
|
4
|
+
# Validates that spec.md files have required sections
|
|
5
|
+
|
|
6
|
+
echo "🔍 Validating spec files..."
|
|
7
|
+
|
|
8
|
+
# Find modified spec.md files
|
|
9
|
+
SPEC_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep 'spec\.md$')
|
|
10
|
+
|
|
11
|
+
if [ -z "$SPEC_FILES" ]; then
|
|
12
|
+
echo "✓ No spec files modified"
|
|
13
|
+
exit 0
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
HAS_ERRORS=false
|
|
17
|
+
|
|
18
|
+
for spec_file in $SPEC_FILES; do
|
|
19
|
+
echo "Checking: $spec_file"
|
|
20
|
+
|
|
21
|
+
# Required sections
|
|
22
|
+
REQUIRED_SECTIONS=(
|
|
23
|
+
"## 📋 Metadata"
|
|
24
|
+
"## 🎯 Overview"
|
|
25
|
+
"## 🏗️ Technical Design"
|
|
26
|
+
"## ✅ Acceptance Criteria"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
for section in "${REQUIRED_SECTIONS[@]}"; do
|
|
30
|
+
if ! grep -q "$section" "$spec_file"; then
|
|
31
|
+
echo " ❌ Missing section: $section"
|
|
32
|
+
HAS_ERRORS=true
|
|
33
|
+
fi
|
|
34
|
+
done
|
|
35
|
+
|
|
36
|
+
# Check if has at least one user story or requirement
|
|
37
|
+
if ! grep -qi "user story\|requirement\|acceptance criteria" "$spec_file"; then
|
|
38
|
+
echo " ⚠️ Warning: No user stories or requirements found"
|
|
39
|
+
fi
|
|
40
|
+
done
|
|
41
|
+
|
|
42
|
+
if [ "$HAS_ERRORS" = true ]; then
|
|
43
|
+
echo ""
|
|
44
|
+
echo "❌ COMMIT BLOCKED: spec.md files are incomplete"
|
|
45
|
+
echo " Add missing sections before committing"
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
echo "✓ All spec files are valid"
|
|
50
|
+
exit 0
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Scope: universal | Runs test suite before push
|
|
3
|
-
# MORPH-SPEC Pre-Push Hook
|
|
4
|
-
# Ensures all tests pass before pushing to remote
|
|
5
|
-
|
|
6
|
-
echo "🧪 Running test suite before push..."
|
|
7
|
-
echo ""
|
|
8
|
-
|
|
9
|
-
# Detect project type and run appropriate tests
|
|
10
|
-
if [[ -f *.csproj ]] || find . -maxdepth 2 -name "*.csproj" 2>/dev/null | grep -q .; then
|
|
11
|
-
# .NET project detected
|
|
12
|
-
echo "📦 Detected .NET project"
|
|
13
|
-
|
|
14
|
-
if ! dotnet test --verbosity minimal --no-build --no-restore 2>/dev/null; then
|
|
15
|
-
echo ""
|
|
16
|
-
echo "❌ .NET tests failed!"
|
|
17
|
-
echo ""
|
|
18
|
-
echo "Fix failing tests before pushing."
|
|
19
|
-
echo "Override with: git push --no-verify"
|
|
20
|
-
exit 1
|
|
21
|
-
fi
|
|
22
|
-
|
|
23
|
-
elif [[ -f package.json ]]; then
|
|
24
|
-
# Node.js project detected
|
|
25
|
-
echo "📦 Detected Node.js project"
|
|
26
|
-
|
|
27
|
-
if ! npm test 2>/dev/null; then
|
|
28
|
-
echo ""
|
|
29
|
-
echo "❌ Node.js tests failed!"
|
|
30
|
-
echo ""
|
|
31
|
-
echo "Fix failing tests before pushing."
|
|
32
|
-
echo "Override with: git push --no-verify"
|
|
33
|
-
exit 1
|
|
34
|
-
fi
|
|
35
|
-
|
|
36
|
-
else
|
|
37
|
-
echo "⚠️ No recognized test framework found"
|
|
38
|
-
echo " Skipping test execution"
|
|
39
|
-
exit 0
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
echo ""
|
|
43
|
-
echo "✅ All tests passed - safe to push"
|
|
44
|
-
exit 0
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Scope: universal | Runs test suite before push
|
|
3
|
+
# MORPH-SPEC Pre-Push Hook
|
|
4
|
+
# Ensures all tests pass before pushing to remote
|
|
5
|
+
|
|
6
|
+
echo "🧪 Running test suite before push..."
|
|
7
|
+
echo ""
|
|
8
|
+
|
|
9
|
+
# Detect project type and run appropriate tests
|
|
10
|
+
if [[ -f *.csproj ]] || find . -maxdepth 2 -name "*.csproj" 2>/dev/null | grep -q .; then
|
|
11
|
+
# .NET project detected
|
|
12
|
+
echo "📦 Detected .NET project"
|
|
13
|
+
|
|
14
|
+
if ! dotnet test --verbosity minimal --no-build --no-restore 2>/dev/null; then
|
|
15
|
+
echo ""
|
|
16
|
+
echo "❌ .NET tests failed!"
|
|
17
|
+
echo ""
|
|
18
|
+
echo "Fix failing tests before pushing."
|
|
19
|
+
echo "Override with: git push --no-verify"
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
elif [[ -f package.json ]]; then
|
|
24
|
+
# Node.js project detected
|
|
25
|
+
echo "📦 Detected Node.js project"
|
|
26
|
+
|
|
27
|
+
if ! npm test 2>/dev/null; then
|
|
28
|
+
echo ""
|
|
29
|
+
echo "❌ Node.js tests failed!"
|
|
30
|
+
echo ""
|
|
31
|
+
echo "Fix failing tests before pushing."
|
|
32
|
+
echo "Override with: git push --no-verify"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
else
|
|
37
|
+
echo "⚠️ No recognized test framework found"
|
|
38
|
+
echo " Skipping test execution"
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
echo ""
|
|
43
|
+
echo "✅ All tests passed - safe to push"
|
|
44
|
+
exit 0
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* command-tokens.js — shell-ish tokenizer shared by the PreToolUse Bash guards.
|
|
3
|
+
*
|
|
4
|
+
* Lives in shared/ (not inside a hook) on purpose: every core hook ends in a
|
|
5
|
+
* standalone tail that reads stdin and exits, so a hook importing a sibling
|
|
6
|
+
* hook for a helper would fire THAT tail in its own process — consuming the
|
|
7
|
+
* payload and exiting before the importer ever ran. block-raw-worktree-add
|
|
8
|
+
* and block-destructive-worktree-removal both read paths off these tokens,
|
|
9
|
+
* so they agree on what a quoted path is.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Split a shell-ish command into tokens, honoring single and double quotes.
|
|
14
|
+
* @param {string} command
|
|
15
|
+
* @returns {string[]}
|
|
16
|
+
*/
|
|
17
|
+
export function tokenize(command) {
|
|
18
|
+
const tokens = [];
|
|
19
|
+
const re = /"([^"]*)"|'([^']*)'|(\S+)/g;
|
|
20
|
+
let m;
|
|
21
|
+
while ((m = re.exec(String(command || ''))) !== null) tokens.push(m[1] ?? m[2] ?? m[3]);
|
|
22
|
+
return tokens;
|
|
23
|
+
}
|
|
Binary file
|
|
@@ -58,6 +58,31 @@ function findDotGit(startDir) {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Is `startDir` inside a LINKED (secondary) worktree?
|
|
63
|
+
*
|
|
64
|
+
* Same on-disk fact `resolveGitCommonDir` reads: git represents a linked
|
|
65
|
+
* worktree's `.git` as a FILE holding a `gitdir:` pointer, and a primary
|
|
66
|
+
* checkout's `.git` as a DIRECTORY. The e2e isolation rule keys on this —
|
|
67
|
+
* a compose that cannot be isolated is a hard failure only where a second
|
|
68
|
+
* stack could actually collide with the primary's (see e2e-check.js
|
|
69
|
+
* `decideIsolation`).
|
|
70
|
+
*
|
|
71
|
+
* Fail-open: outside any repo, or on an unreadable path, answers `false` —
|
|
72
|
+
* the lenient direction (warn instead of fail).
|
|
73
|
+
*
|
|
74
|
+
* @param {string} startDir
|
|
75
|
+
* @returns {boolean}
|
|
76
|
+
*/
|
|
77
|
+
export function isSecondaryWorktree(startDir) {
|
|
78
|
+
try {
|
|
79
|
+
const found = findDotGit(startDir);
|
|
80
|
+
return Boolean(found && !found.isDirectory);
|
|
81
|
+
} catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
61
86
|
/**
|
|
62
87
|
* Resolve the git COMMON dir for `startDir` — pure filesystem, no subprocess.
|
|
63
88
|
* Always returns an absolute path (unlike `git rev-parse --git-common-dir`,
|
|
@@ -122,3 +122,20 @@ export async function runStandalone(run) {
|
|
|
122
122
|
}
|
|
123
123
|
process.exit(0);
|
|
124
124
|
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Pure builder for a PreToolUse rewrite: Claude Code runs the tool with
|
|
128
|
+
* `updatedInput` in place of the original `tool_input`, and the decision is
|
|
129
|
+
* an explicit `allow` (a rewrite without a decision is ignored). Use it ONLY
|
|
130
|
+
* when the hook actually changed something — an unconditional `allow` would
|
|
131
|
+
* skip the permission prompt for every call it touches.
|
|
132
|
+
*
|
|
133
|
+
* @param {object} updatedInput - the full replacement tool_input
|
|
134
|
+
* @param {string} eventName - 'PreToolUse'
|
|
135
|
+
* @param {string} [context] - optional additionalContext (what was changed)
|
|
136
|
+
*/
|
|
137
|
+
export function updatedInputResult(updatedInput, eventName, context) {
|
|
138
|
+
const out = { hookEventName: eventName, permissionDecision: 'allow', updatedInput };
|
|
139
|
+
if (context) out.additionalContext = context;
|
|
140
|
+
return { hookSpecificOutput: out };
|
|
141
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* morph-cli.js — run the morph-spec CLI from inside a hook.
|
|
3
|
+
*
|
|
4
|
+
* Hooks are installed STANDALONE into `.morph/framework/hooks/` and may never
|
|
5
|
+
* import from `src/`; the only way for a hook to reuse a CLI command (the
|
|
6
|
+
* WorktreeCreate hook needs `worktree setup`/`provision`, WorktreeRemove needs
|
|
7
|
+
* `worktree remove --if-clean`) is to spawn the CLI as a subprocess. This
|
|
8
|
+
* module is the ONE place that knows how to find it.
|
|
9
|
+
*
|
|
10
|
+
* Resolution order:
|
|
11
|
+
* 1. `MORPH_SPEC_BIN` — an explicit command, possibly with leading args and
|
|
12
|
+
* quoted paths (`node "R:/my repo/bin/morph-spec.js"`). What tests and a
|
|
13
|
+
* framework checkout use.
|
|
14
|
+
* 2. `morph-spec` on PATH — the npm-installed bin. On win32 the shim is
|
|
15
|
+
* `morph-spec.cmd`, which Node refuses to spawn without a shell, so it is
|
|
16
|
+
* located by scanning PATH ourselves and then run through the shell with
|
|
17
|
+
* each arg quoted; on POSIX a plain `shell:false` spawn.
|
|
18
|
+
* 3. `npx --no-install morph-spec` — a project-local dependency.
|
|
19
|
+
*
|
|
20
|
+
* ENOENT (or the shell's "not recognized"/"could not determine executable")
|
|
21
|
+
* everywhere → `{ unavailable: true }`, never a throw: the caller decides what
|
|
22
|
+
* degraded behavior looks like.
|
|
23
|
+
*
|
|
24
|
+
* `json` is the LAST line of stdout that parses as a JSON object (the CLI's
|
|
25
|
+
* commands print exactly one JSON line; anything a stray console.log adds
|
|
26
|
+
* before it is skipped), or null.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { spawnSync } from 'child_process';
|
|
30
|
+
import { existsSync } from 'fs';
|
|
31
|
+
import { delimiter, join } from 'path';
|
|
32
|
+
|
|
33
|
+
/** Split a command string into argv, honoring single and double quotes. */
|
|
34
|
+
function splitCommand(command) {
|
|
35
|
+
const tokens = [];
|
|
36
|
+
const re = /"([^"]*)"|'([^']*)'|(\S+)/g;
|
|
37
|
+
let m;
|
|
38
|
+
while ((m = re.exec(command)) !== null) tokens.push(m[1] ?? m[2] ?? m[3]);
|
|
39
|
+
return tokens;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Quote one argument for cmd.exe (the only shell path this module uses). */
|
|
43
|
+
function quoteForCmd(arg) {
|
|
44
|
+
if (arg === '') return '""';
|
|
45
|
+
if (!/[\s"&|<>^()]/.test(arg)) return arg;
|
|
46
|
+
return `"${arg.replace(/"/g, '""')}"`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** First PATH entry holding `file`, or null. */
|
|
50
|
+
function findOnPath(file, env) {
|
|
51
|
+
const raw = env.PATH || env.Path || env.path || '';
|
|
52
|
+
for (const dir of raw.split(delimiter)) {
|
|
53
|
+
if (!dir) continue;
|
|
54
|
+
const candidate = join(dir, file);
|
|
55
|
+
try { if (existsSync(candidate)) return candidate; } catch { /* unreadable entry */ }
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Last stdout line that parses as a JSON object, or null. */
|
|
61
|
+
export function lastJsonLine(stdout) {
|
|
62
|
+
const lines = String(stdout || '').split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
63
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
64
|
+
if (!lines[i].startsWith('{')) continue;
|
|
65
|
+
try {
|
|
66
|
+
const parsed = JSON.parse(lines[i]);
|
|
67
|
+
if (parsed && typeof parsed === 'object') return parsed;
|
|
68
|
+
} catch { /* not this line */ }
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The candidates to try, in order. Each is `{ file, args, shell }`.
|
|
75
|
+
* @param {NodeJS.ProcessEnv} env
|
|
76
|
+
*/
|
|
77
|
+
function candidates(env) {
|
|
78
|
+
const list = [];
|
|
79
|
+
const explicit = env.MORPH_SPEC_BIN && splitCommand(env.MORPH_SPEC_BIN);
|
|
80
|
+
if (explicit && explicit.length) {
|
|
81
|
+
list.push({ file: explicit[0], args: explicit.slice(1), shell: false, kind: 'env' });
|
|
82
|
+
}
|
|
83
|
+
if (process.platform === 'win32') {
|
|
84
|
+
const cmd = findOnPath('morph-spec.cmd', env);
|
|
85
|
+
if (cmd) list.push({ file: cmd, args: [], shell: true, kind: 'path' });
|
|
86
|
+
const npx = findOnPath('npx.cmd', env);
|
|
87
|
+
if (npx) list.push({ file: npx, args: ['--no-install', 'morph-spec'], shell: true, kind: 'npx' });
|
|
88
|
+
} else {
|
|
89
|
+
list.push({ file: 'morph-spec', args: [], shell: false, kind: 'path' });
|
|
90
|
+
list.push({ file: 'npx', args: ['--no-install', 'morph-spec'], shell: false, kind: 'npx' });
|
|
91
|
+
}
|
|
92
|
+
return list;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const NOT_FOUND_RE = /not recognized as an internal or external command|could not determine executable to run|command not found|ENOENT/i;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Run `morph-spec <args>` and return its result.
|
|
99
|
+
*
|
|
100
|
+
* @param {string[]} args - CLI argv after the program name
|
|
101
|
+
* @param {{ cwd?: string, timeoutMs?: number, env?: NodeJS.ProcessEnv }} [opts]
|
|
102
|
+
* @returns {{ ok: boolean, code: number|null, stdout: string, stderr: string, json: object|null, unavailable: boolean }}
|
|
103
|
+
*/
|
|
104
|
+
export function runMorphSpec(args, { cwd, timeoutMs = 120000, env } = {}) {
|
|
105
|
+
const runEnv = env || process.env;
|
|
106
|
+
const argv = Array.isArray(args) ? args.map(String) : [];
|
|
107
|
+
|
|
108
|
+
for (const cand of candidates(runEnv)) {
|
|
109
|
+
let r;
|
|
110
|
+
try {
|
|
111
|
+
const full = [...cand.args, ...argv];
|
|
112
|
+
r = cand.shell
|
|
113
|
+
? spawnSync(quoteForCmd(cand.file), full.map(quoteForCmd), { cwd, env: runEnv, encoding: 'utf8', timeout: timeoutMs, shell: true, stdio: ['ignore', 'pipe', 'pipe'] })
|
|
114
|
+
: spawnSync(cand.file, full, { cwd, env: runEnv, encoding: 'utf8', timeout: timeoutMs, shell: false, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
115
|
+
} catch (err) {
|
|
116
|
+
if (err?.code === 'ENOENT') continue;
|
|
117
|
+
return { ok: false, code: null, stdout: '', stderr: String(err?.message || err), json: null, unavailable: false };
|
|
118
|
+
}
|
|
119
|
+
if (r.error) {
|
|
120
|
+
if (r.error.code === 'ENOENT') continue;
|
|
121
|
+
return { ok: false, code: null, stdout: r.stdout || '', stderr: String(r.error.message || r.error), json: null, unavailable: false };
|
|
122
|
+
}
|
|
123
|
+
const stdout = r.stdout || '';
|
|
124
|
+
const stderr = r.stderr || '';
|
|
125
|
+
// The npx/shell paths cannot surface ENOENT: the shell (or npx itself)
|
|
126
|
+
// reports "not found" as a non-zero exit with a message. Only those two
|
|
127
|
+
// kinds are read that way — a real morph-spec failure is never mistaken
|
|
128
|
+
// for absence.
|
|
129
|
+
if (cand.kind !== 'env' && r.status !== 0 && !stdout.trim() && NOT_FOUND_RE.test(stderr)) continue;
|
|
130
|
+
return { ok: r.status === 0, code: r.status, stdout, stderr, json: lastJsonLine(stdout), unavailable: false };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return { ok: false, code: null, stdout: '', stderr: 'morph-spec CLI not found (MORPH_SPEC_BIN, PATH, npx)', json: null, unavailable: true };
|
|
134
|
+
}
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared stdin reader for Claude Code hooks.
|
|
3
|
-
*
|
|
4
|
-
* Reads JSON payload from stdin (provided by Claude Code to hooks).
|
|
5
|
-
* Returns parsed object or null on failure.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Read and parse JSON from stdin
|
|
10
|
-
* @returns {Promise<Object|null>} Parsed JSON or null
|
|
11
|
-
*/
|
|
12
|
-
export function readStdin() {
|
|
13
|
-
return new Promise((resolve) => {
|
|
14
|
-
let input = '';
|
|
15
|
-
process.stdin.setEncoding('utf-8');
|
|
16
|
-
process.stdin.on('data', (chunk) => { input += chunk; });
|
|
17
|
-
process.stdin.on('end', () => {
|
|
18
|
-
try {
|
|
19
|
-
resolve(JSON.parse(input || '{}'));
|
|
20
|
-
} catch {
|
|
21
|
-
resolve(null);
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
process.stdin.on('error', () => resolve(null));
|
|
25
|
-
});
|
|
26
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Shared stdin reader for Claude Code hooks.
|
|
3
|
+
*
|
|
4
|
+
* Reads JSON payload from stdin (provided by Claude Code to hooks).
|
|
5
|
+
* Returns parsed object or null on failure.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Read and parse JSON from stdin
|
|
10
|
+
* @returns {Promise<Object|null>} Parsed JSON or null
|
|
11
|
+
*/
|
|
12
|
+
export function readStdin() {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
let input = '';
|
|
15
|
+
process.stdin.setEncoding('utf-8');
|
|
16
|
+
process.stdin.on('data', (chunk) => { input += chunk; });
|
|
17
|
+
process.stdin.on('end', () => {
|
|
18
|
+
try {
|
|
19
|
+
resolve(JSON.parse(input || '{}'));
|
|
20
|
+
} catch {
|
|
21
|
+
resolve(null);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
process.stdin.on('error', () => resolve(null));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -11,6 +11,8 @@ stacks:
|
|
|
11
11
|
# Infrastructure Standards
|
|
12
12
|
|
|
13
13
|
@.morph/framework/standards/infrastructure/docker/coolify-deploy.md
|
|
14
|
+
@.morph/framework/standards/infrastructure/docker/local-compose-isolation.md
|
|
15
|
+
@.morph/framework/standards/infrastructure/docker/local-compose-isolation.md
|
|
14
16
|
|
|
15
17
|
## Infrastructure Templates
|
|
16
18
|
|
|
@@ -18,7 +20,7 @@ stacks:
|
|
|
18
20
|
|----------|------|---------|
|
|
19
21
|
| .NET API Dockerfile | `.morph/framework/templates/infrastructure/docker/dockerfile-api.dockerfile` | Multi-stage .NET |
|
|
20
22
|
| Next.js Dockerfile | `.morph/framework/templates/infrastructure/docker/dockerfile-web.dockerfile` | Multi-stage Next.js |
|
|
21
|
-
| Docker Compose | `.morph/framework/templates/infrastructure/docker/docker-compose.template.yml` | Local dev env |
|
|
23
|
+
| Docker Compose | `.morph/framework/templates/infrastructure/docker/docker-compose.template.yml` | Local dev env — one isolated stack per worktree (ports from the block, no `container_name`) |
|
|
22
24
|
| Coolify Config | `.morph/framework/templates/infrastructure/docker/coolify.template.json` | Deployment config |
|
|
23
25
|
| .NET Build CI | `.morph/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs` | CI workflow |
|
|
24
26
|
| Docker Push CI | `.morph/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs` | Build & push |
|
|
@@ -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: "8.
|
|
7
|
+
cliVersion: "8.34.2"
|
|
8
8
|
stacks:
|
|
9
9
|
- umbraco
|
|
10
10
|
---
|
|
@@ -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: "8.
|
|
7
|
+
cliVersion: "8.34.2"
|
|
8
8
|
stacks:
|
|
9
9
|
- umbraco
|
|
10
10
|
---
|
|
@@ -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: "8.
|
|
7
|
+
cliVersion: "8.34.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-apply
|
|
@@ -202,10 +202,10 @@ Depois do batch paralelo, executar o restante em modo sequencial (passo 3a).
|
|
|
202
202
|
|
|
203
203
|
Quando o `morph-spec dag {feature}` reporta `isolation.recommended: "worktree"` (dois fluxos paralelos planejam escrever no mesmo path — colisão de `outputs`), despache cada fluxo com o parâmetro `isolation: "worktree"` do tool Agent. Cada agente trabalha numa working tree própria; build/test rodam lá dentro sem colidir.
|
|
204
204
|
|
|
205
|
-
1. **Dispatch:** mesmo `subagent_type: "morph-{id}"` e standards de §3b, mais `isolation: "worktree"`.
|
|
205
|
+
1. **Dispatch:** mesmo `subagent_type: "morph-{id}"` e standards de §3b, mais `isolation: "worktree"`. O worktree vem do hook `WorktreeCreate` do morph: nasce em `worktrees/<n>` na branch `morph-task/<n>`, com junctions (`node_modules`, `.claude`, `.morph/framework`) e `.morph/worktree.env` já prontos — se faltar infra mesmo assim, o agente roda `morph-spec worktree link --all` (fail-open); se ainda impossível, reporta "verificação: não executada" (o verify pós-merge cobre). Dev server/compose dentro do worktree já sai nas portas do bloco (o hook `worktree-env-inject` prefixa o comando; fora do Claude, `eval "$(morph-spec env)"`). O agente commita na branch do worktree como último ato e reporta a branch.
|
|
206
206
|
2. **Integração (orquestrador, após todos os relatórios):** faça o merge de cada branch reportada, uma por vez, na ordem de chegada — `git merge --no-ff <branch>`. Conflito → `git merge --abort`, marque a task de volta a `pending` com nota "merge conflict — reexecutar sequencial", siga para a próxima branch. Os paths em conflito são exatamente os de `isolation.collisions` do dag.
|
|
207
207
|
3. **Pós-merge:** rode `morph-spec verify {feature} --json` UMA vez (o merge é o novo ponto de integração — verificação compartilhada obrigatória), depois `morph-eval` + `morph-spec score` por relatório, como em §3b.
|
|
208
|
-
4. **Cleanup:** `morph-spec worktree remove --target <path>` por worktree (NUNCA `git worktree remove` cru —
|
|
208
|
+
4. **Cleanup:** o hook `WorktreeRemove` remove o worktree **limpo** ao fim do subagent (branch sobrevive) — mas não conte com ele: rode `morph-spec worktree remove --target <path>` por worktree que sobrou (NUNCA `git worktree remove` cru — as junctions do passo 1 seriam atravessadas e o `node_modules`/`.claude` da raiz apagados) + `git branch -d morph-task/<n>` das branches integradas + `git worktree prune` (fail-open). Worktree sujo (subagent não commitou) fica, vira `unintegrated-work` no `doctor --worktrees`, e a task volta a `pending`. Branches não integradas ficam e são registradas no recap com o motivo.
|
|
209
209
|
5. **Agente morto no meio:** se commitou, a branch sobrevive (retomável); senão, a task volta a `pending` na lane sequencial. Registre a falha de protocolo no recap.
|
|
210
210
|
|
|
211
211
|
> Anti-padrões: não misture unidades isoladas e não-isoladas no mesmo batch; o subagent nunca faz merge (integração é exclusiva do orquestrador).
|
|
@@ -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: "8.
|
|
7
|
+
cliVersion: "8.34.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: "8.
|
|
7
|
+
cliVersion: "8.34.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-eval
|
|
@@ -4,7 +4,7 @@ description: ADW cirúrgico de hotfix — resolve uma queda/bug crítico de prod
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber "/morph-hotfix {feature}", quando a morph-proposal classifica o pedido como workType hotfix (Passo 0), ou o usuário diz "produção caiu / hotfix / urgente"
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.34.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-hotfix
|
|
@@ -4,7 +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: "8.
|
|
7
|
+
cliVersion: "8.34.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-implement
|
|
@@ -84,6 +84,8 @@ Ao iniciar cada task de `tasks.json` — antes de escrever qualquer código. Nor
|
|
|
84
84
|
(`morph-spec verify`) é do orquestrador, pós-batch. Em batch COM
|
|
85
85
|
`isolation: "worktree"`, rode build/test no seu worktree, commite na
|
|
86
86
|
branch do worktree como último ato antes do relatório — nunca faça merge.
|
|
87
|
+
Worktree não commitado NÃO é removido pelo hook e vira pendência do
|
|
88
|
+
`doctor`; o commit é o que torna o seu trabalho integrável.
|
|
87
89
|
|
|
88
90
|
Seu relatório (no arquivo, e na mensagem final quando ela chega) deve conter
|
|
89
91
|
APENAS: (1) o que foi feito em 2-3 frases, (2) arquivos modificados,
|
|
@@ -4,7 +4,7 @@ description: Guia a produção dos artefatos de planejamento de uma feature (use
|
|
|
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: "8.
|
|
7
|
+
cliVersion: "8.34.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-plan
|
|
@@ -138,8 +138,11 @@ Ao iniciar a fase plan — após o `proposal.md` ser aprovado e antes de qualque
|
|
|
138
138
|
- **Base URL vinda do ambiente:** o harness dá a cada feature um bloco de portas próprio (para
|
|
139
139
|
duas worktrees não brigarem pela porta 3000), então o `playwright.config.ts` **não pode**
|
|
140
140
|
cravar a URL — leia `process.env.PLAYWRIGHT_BASE_URL ?? \`http://localhost:${process.env.PORT ?? 3000}\``
|
|
141
|
-
e faça o compose publicar `"${PORT:-3000}:3000"
|
|
142
|
-
|
|
141
|
+
e faça o compose publicar `"${PORT:-3000}:3000"` e `"${POSTGRES_PORT:-5432}:5432"`, sem
|
|
142
|
+
`container_name` (o projeto compose já namespaceia; nome explícito colide entre worktrees —
|
|
143
|
+
standard `infrastructure/docker/local-compose-isolation`). Config cravada = suíte batendo em
|
|
144
|
+
porta vazia e `ECONNREFUSED` com cara de app quebrada; compose cravado **reprova o nó e2e**
|
|
145
|
+
dentro de um worktree. Se estiver cravado, **isso é uma task**.
|
|
143
146
|
- **Setup de autenticação**, se a aplicação tem login: `e2e.auth` em `config.json`
|
|
144
147
|
(`mode: seed|storageState|bypass|none`, `seedCommand`, `storageStatePath`, `envFile`), com as
|
|
145
148
|
credenciais num `.env.e2e` **gitignored** — nunca no config commitado. **Se a app tem login e
|
|
@@ -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: "8.
|
|
7
|
+
cliVersion: "8.34.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: "8.
|
|
7
|
+
cliVersion: "8.34.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: "8.
|
|
7
|
+
cliVersion: "8.34.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-stack-scan
|
|
@@ -4,7 +4,7 @@ description: Localiza um standard específico via busca server-side (morph-spec
|
|
|
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: "8.
|
|
7
|
+
cliVersion: "8.34.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-standards
|
|
@@ -4,7 +4,7 @@ description: Conduz a fase opcional de UI/UX — design system, mockups, compone
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao tomar o ramo uiux (morph-spec advance --design), depois do Gate 1 e antes do morph-plan
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.34.2"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-uiux
|