@polymorphism-tech/morph-spec 4.11.1 → 4.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -29
- package/bin/morph-spec.js +41 -24
- package/bin/task-manager.js +962 -1341
- package/bin/validate.js +1 -1
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +10 -11
- package/docs/QUICKSTART.md +15 -15
- package/framework/CLAUDE.md +5 -2
- package/framework/agents/README.md +3 -4
- package/framework/agents/ai-agents/ai-system-architect.md +6 -10
- package/framework/agents/architecture/seo-growth-hacker.md +166 -326
- package/framework/agents/architecture/standards-architect.md +21 -31
- package/framework/agents/backend/dotnet-senior.md +160 -86
- package/framework/agents/backend/ef-modeler.md +2 -6
- package/framework/agents/backend/hangfire-orchestrator.md +8 -9
- package/framework/agents/backend/ms-agent-expert.md +1 -1
- package/framework/agents/frontend/nextjs-expert.md +198 -133
- package/framework/agents/frontend/ui-ux-designer.md +226 -267
- package/framework/agents/infrastructure/infra-architect.md +191 -27
- package/framework/agents/integrations/clerk-auth.md +19 -26
- package/framework/agents/integrations/hangfire-integration.md +1 -4
- package/framework/agents.json +226 -1454
- package/framework/commands/morph-apply.md +4 -4
- package/framework/commands/morph-preflight.md +4 -26
- package/framework/commands/morph-proposal.md +19 -19
- package/framework/commands/morph-status.md +2 -2
- package/framework/commands/morph-troubleshoot.md +6 -13
- package/framework/hooks/README.md +1 -6
- package/framework/hooks/claude-code/post-tool-use/agent-complete.js +122 -0
- package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +4 -6
- package/framework/hooks/claude-code/pre-compact/save-morph-context.js +12 -7
- package/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +2 -2
- package/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +2 -2
- package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +5 -10
- package/framework/hooks/claude-code/session-start/inject-morph-context.js +63 -30
- package/framework/hooks/claude-code/session-start/resume-context.js +77 -0
- package/framework/hooks/claude-code/statusline.py +4 -5
- package/framework/hooks/claude-code/stop/validate-completion.js +4 -4
- package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +8 -8
- package/framework/hooks/shared/compact-restore.js +28 -5
- package/framework/hooks/shared/dispatch-helpers.js +17 -0
- package/framework/hooks/shared/phase-utils.js +4 -8
- package/framework/hooks/shared/state-reader.js +34 -3
- package/framework/phases.json +7 -45
- package/framework/rules/ai-agents-standards.md +15 -0
- package/framework/rules/asaas-standards.md +13 -0
- package/framework/rules/clerk-standards.md +13 -0
- package/framework/rules/csharp-standards.md +8 -4
- package/framework/rules/data-standards.md +18 -0
- package/framework/rules/dotnet-templates.md +87 -0
- package/framework/rules/frontend-standards.md +13 -13
- package/framework/rules/hangfire-standards.md +13 -0
- package/framework/rules/infrastructure-standards.md +27 -16
- package/framework/rules/morph-workflow.md +73 -13
- package/framework/rules/nextjs-standards.md +1 -0
- package/framework/rules/nextjs-templates.md +40 -0
- package/framework/rules/resend-standards.md +12 -0
- package/framework/rules/supabase-standards.md +29 -0
- package/framework/skills/README.md +6 -8
- package/framework/skills/level-0-meta/mcp-registry.json +21 -99
- package/framework/{standards/ai-agents/team-orchestration.md → skills/level-0-meta/morph-agent-teams/SKILL.md} +472 -479
- package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +28 -1
- package/framework/skills/level-0-meta/morph-checklist/SKILL.md +2 -2
- package/framework/skills/level-0-meta/morph-code-review/SKILL.md +1 -5
- package/framework/skills/level-0-meta/morph-code-review/scripts/scan-csharp.mjs +1 -1
- package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +23 -41
- package/framework/skills/level-0-meta/morph-init/SKILL.md +18 -14
- package/framework/skills/level-0-meta/morph-parallel-dispatch/SKILL.md +225 -0
- package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +20 -0
- package/framework/skills/level-0-meta/morph-tool-usage-guide/SKILL.md +4 -8
- package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +15 -59
- package/framework/skills/level-0-meta/morph-verification-before-completion/SKILL.md +7 -19
- package/framework/skills/level-0-meta/morph-verification-before-completion/scripts/check-phase-outputs.mjs +8 -8
- package/framework/skills/level-1-workflows/README.md +1 -1
- package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +49 -50
- package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +58 -124
- package/framework/skills/level-1-workflows/morph-phase-design/references/architecture-analysis-guide.md +5 -50
- package/framework/skills/level-1-workflows/morph-phase-design/references/spec-example.md +1 -1
- package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +127 -159
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +4 -3
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/spec-reviewer-prompt.md +2 -2
- package/framework/skills/level-1-workflows/morph-phase-implement/references/recap-example.md +1 -1
- package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +17 -13
- package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +22 -40
- package/framework/skills/level-1-workflows/morph-phase-tasks/references/task-planning-patterns.md +0 -2
- package/framework/skills/level-1-workflows/morph-phase-tasks/references/tasks-example.md +5 -5
- package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +275 -61
- package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +1 -1
- package/framework/squad-templates/backend-only.json +6 -6
- package/framework/squad-templates/frontend-only.json +17 -8
- package/framework/squad-templates/full-stack.json +29 -24
- package/framework/standards/STANDARDS.json +1021 -2338
- package/framework/standards/backend/dotnet/fluent-validation-vsa.md +200 -0
- package/framework/standards/backend/dotnet/result-pattern.md +213 -0
- package/framework/standards/backend/dotnet/scalar-ui.md +172 -0
- package/framework/standards/backend/dotnet/scrutor.md +158 -0
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +274 -0
- package/framework/standards/frontend/nextjs/motion-patterns.md +1 -1
- package/framework/standards/infrastructure/supabase/mcp-setup.md +83 -193
- package/framework/standards/integration/mcp/mcp-tools.md +91 -77
- package/framework/templates/IDE-SNIPPETS.md +2 -6
- package/framework/templates/README.md +709 -814
- package/framework/templates/REGISTRY.json +223 -762
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -0
- package/framework/templates/code/dotnet/abstractions/error.cs +60 -0
- package/framework/templates/code/dotnet/abstractions/handler.cs +12 -0
- package/framework/templates/code/dotnet/abstractions/result.cs +74 -0
- package/framework/templates/code/dotnet/backend/repository.cs +148 -141
- package/framework/templates/code/dotnet/constants/api-tags.cs +6 -0
- package/framework/templates/code/dotnet/exceptions/exception-handler.cs +32 -0
- package/framework/templates/code/dotnet/extensions/database-extensions.cs +20 -0
- package/framework/templates/code/dotnet/extensions/handler-registration.cs +38 -0
- package/framework/templates/code/dotnet/extensions/health-checks.cs +24 -0
- package/framework/templates/code/dotnet/extensions/map-endpoints.cs +35 -0
- package/framework/templates/code/dotnet/extensions/result-extensions.cs +29 -0
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -0
- package/framework/templates/code/dotnet/feature/entity.cs.hbs +8 -0
- package/framework/templates/code/dotnet/feature/errors.cs.hbs +8 -0
- package/framework/templates/code/dotnet/feature/handler.cs.hbs +24 -0
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -0
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -0
- package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -0
- package/framework/templates/code/dotnet/jobs/job.cs +21 -17
- package/framework/templates/code/dotnet/pipelines/logging-decorator.cs +31 -0
- package/framework/templates/code/dotnet/pipelines/validation-decorator.cs +97 -0
- package/framework/templates/code/dotnet/test.cs +192 -106
- package/framework/templates/context/ARCHITECTURE.md +89 -0
- package/framework/templates/context/CONTEXT-FEATURE.md +2 -2
- package/framework/templates/context/CONTEXT.md +180 -181
- package/framework/templates/context/design-system.md +342 -211
- package/framework/templates/docs/onboarding.md +2 -3
- package/framework/templates/docs/proposal.md +171 -182
- package/framework/templates/docs/spec.md +1 -3
- package/framework/templates/docs/ui-components.md +0 -72
- package/framework/templates/examples/design-system-examples.md +4 -4
- package/framework/templates/feature/decisions.md +0 -66
- package/framework/templates/feature/recap.md +1 -2
- package/framework/templates/infrastructure/github/README.md +56 -593
- package/framework/templates/integrations/clerk-config.cs +0 -41
- package/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +2 -2
- package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +1 -2
- package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +83 -126
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +2 -2
- package/framework/templates/project/validate.js +2 -4
- package/framework/templates/ui/design-system.css +1 -1
- package/framework/workflows/README.md +8 -8
- package/framework/workflows/configs/fast-track.json +51 -0
- package/framework/workflows/configs/full.json +68 -0
- package/framework/workflows/configs/standard.json +7 -3
- package/framework/workflows/docs/STORY-DRIVEN-DEVELOPMENT.md +1 -1
- package/framework/workflows/docs/enforcement-pipeline.md +18 -19
- package/framework/workflows/docs/full-morph.md +69 -76
- package/framework/workflows/docs/standard.md +49 -44
- package/framework/workflows/docs/ui-refresh.md +1 -1
- package/package.json +3 -3
- package/src/commands/agents/dispatch-agents.js +55 -116
- package/src/commands/context/context-refresh.js +79 -0
- package/src/commands/mcp/mcp-setup.js +28 -6
- package/src/commands/phase/phase-reset.js +1 -1
- package/src/commands/project/doctor.js +10 -32
- package/src/commands/project/init.js +32 -1
- package/src/commands/project/status.js +6 -12
- package/src/commands/scaffold/scaffold.js +131 -0
- package/src/commands/scope/escalate.js +1 -1
- package/src/commands/state/advance-phase.js +15 -29
- package/src/commands/state/state.js +20 -5
- package/src/commands/tasks/task.js +0 -30
- package/src/commands/validation/validate-feature.js +3 -10
- package/src/core/paths/output-schema.js +12 -13
- package/src/core/state/phase-state-machine.js +211 -217
- package/src/core/state/state-manager.js +9 -9
- package/src/lib/agents/agents-manager.js +2 -2
- package/src/lib/agents/output-collector.js +1 -2
- package/src/lib/detectors/design-system-detector.js +4 -4
- package/src/lib/detectors/index.js +1 -11
- package/src/lib/generators/architecture-scanner.js +640 -0
- package/src/lib/generators/context-generator.js +3 -3
- package/src/lib/generators/design-system-generator.js +508 -298
- package/src/lib/generators/index.js +12 -10
- package/src/lib/generators/metadata-extractor.js +386 -387
- package/src/lib/generators/recap-generator.js +4 -4
- package/src/lib/generators/scaffold-generator.js +317 -0
- package/src/lib/generators/settings-generator.js +0 -1
- package/src/lib/phase-chain/phase-validator.js +64 -42
- package/src/lib/stack/stack-profile.js +2 -2
- package/src/lib/standards/digest-builder.js +72 -285
- package/src/lib/tasks/task-parser.js +11 -5
- package/src/lib/validators/architecture/architecture-validator.js +259 -387
- package/src/lib/validators/content/content-validator.js +287 -287
- package/src/lib/validators/css/css-validator.js +340 -352
- package/src/lib/validators/design-system/design-system-validator.js +11 -5
- package/src/lib/validators/packages/package-validator.js +347 -360
- package/src/lib/validators/shared/issue-counter.js +14 -18
- package/src/lib/validators/validation-runner.js +3 -19
- package/src/scripts/setup-infra.js +1 -1
- package/src/utils/agents-installer.js +24 -3
- package/src/utils/file-copier.js +1 -0
- package/src/utils/hooks-installer.js +21 -19
- package/src/utils/skills-installer.js +178 -178
- package/framework/agents/architecture/prompt-engineer.md +0 -195
- package/framework/agents/backend/api-designer.md +0 -106
- package/framework/agents/frontend/blazor-builder.md +0 -229
- package/framework/agents/frontend/nextjs-ui-specialist.md +0 -218
- package/framework/agents/infrastructure/azure-architect.md +0 -150
- package/framework/agents/infrastructure/azure-deploy-specialist.md +0 -707
- package/framework/agents/infrastructure/bicep-architect.md +0 -132
- package/framework/agents/infrastructure/container-specialist.md +0 -137
- package/framework/agents/infrastructure/devops-engineer.md +0 -126
- package/framework/agents/integrations/azure-identity.md +0 -148
- package/framework/agents/quality/code-analyzer.md +0 -239
- package/framework/agents/quality/testing-specialist.md +0 -130
- package/framework/hooks/claude-code/notification/approval-reminder.js +0 -57
- package/framework/hooks/claude-code/post-tool-use/context-refresh.js +0 -109
- package/framework/hooks/claude-code/post-tool-use/skill-reminder.js +0 -78
- package/framework/index/troubleshooting-index.json +0 -184
- package/framework/rules/testing-standards.md +0 -14
- package/framework/skills/level-0-meta/morph-replicate/SKILL.md +0 -230
- package/framework/skills/level-0-meta/morph-replicate/references/blazor-html-mapping.md +0 -70
- package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +0 -256
- package/framework/skills/level-1-workflows/morph-phase-clarify/references/clarifications-example.md +0 -117
- package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +0 -269
- package/framework/standards/ai-agents/blazor-ui.md +0 -364
- package/framework/standards/architecture/ddd/aggregates.md +0 -120
- package/framework/standards/architecture/ddd/bounded-contexts.md +0 -105
- package/framework/standards/architecture/ddd/complexity-levels.md +0 -108
- package/framework/standards/architecture/ddd/entities.md +0 -99
- package/framework/standards/architecture/ddd/ubiquitous-language.md +0 -58
- package/framework/standards/architecture/ddd/value-objects.md +0 -124
- package/framework/standards/backend/api/minimal-api.md +0 -494
- package/framework/standards/backend/api/rest.md +0 -492
- package/framework/standards/backend/authentication/passkeys.md +0 -428
- package/framework/standards/backend/database/ef-core.md +0 -199
- package/framework/standards/backend/database/migrations.md +0 -393
- package/framework/standards/backend/database/repository-patterns.md +0 -528
- package/framework/standards/backend/dotnet/async.md +0 -366
- package/framework/standards/backend/dotnet/core.md +0 -117
- package/framework/standards/backend/dotnet/di.md +0 -439
- package/framework/standards/backend/dotnet/program-cs-checklist.md +0 -92
- package/framework/standards/context/analytics.md +0 -96
- package/framework/standards/context/bundles.md +0 -110
- package/framework/standards/context/priming.md +0 -78
- package/framework/standards/core/architecture.md +0 -185
- package/framework/standards/core/coding.md +0 -214
- package/framework/standards/core/git-branching-strategy.md +0 -403
- package/framework/standards/core/git.md +0 -185
- package/framework/standards/core/testing.md +0 -295
- package/framework/standards/data/nosql/blob-storage.md +0 -102
- package/framework/standards/data/vector-search/azure-ai-search.md +0 -121
- package/framework/standards/frontend/blazor/design-checklist.md +0 -222
- package/framework/standards/frontend/blazor/fluent-ui-setup.md +0 -595
- package/framework/standards/frontend/blazor/fluent-ui.md +0 -137
- package/framework/standards/frontend/blazor/html-conversion.md +0 -184
- package/framework/standards/frontend/blazor/lifecycle.md +0 -195
- package/framework/standards/frontend/blazor/pitfalls.md +0 -198
- package/framework/standards/frontend/blazor/state.md +0 -191
- package/framework/standards/frontend/design-system/aesthetic-direction.md +0 -213
- package/framework/standards/infrastructure/azure/azure.md +0 -624
- package/framework/standards/infrastructure/azure/bicep/bicep-patterns.md +0 -422
- package/framework/standards/infrastructure/azure/devops/azure-devops-setup.md +0 -516
- package/framework/standards/infrastructure/azure/devops/local-development.md +0 -520
- package/framework/standards/infrastructure/azure/services/functions.md +0 -486
- package/framework/standards/infrastructure/azure/services/service-bus.md +0 -459
- package/framework/standards/infrastructure/azure/services/storage.md +0 -407
- package/framework/standards/infrastructure/vercel/vercel-database.md +0 -106
- package/framework/standards/integration/api/graphql.md +0 -91
- package/framework/standards/integration/api/grpc.md +0 -114
- package/framework/standards/integration/api/rest-design.md +0 -95
- package/framework/standards/integration/event-driven/cqrs.md +0 -101
- package/framework/standards/integration/event-driven/event-sourcing.md +0 -124
- package/framework/standards/integration/event-driven/service-bus.md +0 -95
- package/framework/standards/observability/logging.md +0 -131
- package/framework/standards/observability/metrics.md +0 -121
- package/framework/standards/observability/monitoring.md +0 -114
- package/framework/standards/observability/tracing.md +0 -132
- package/framework/standards/workflows/parallel-execution.md +0 -112
- package/framework/standards/workflows/thread-management.md +0 -113
- package/framework/templates/code/dotnet/backend/service.cs +0 -139
- package/framework/templates/code/dotnet/contracts/Commands.cs +0 -74
- package/framework/templates/code/dotnet/contracts/Entities.cs +0 -25
- package/framework/templates/code/dotnet/contracts/Queries.cs +0 -74
- package/framework/templates/code/dotnet/contracts/api-contracts.cs +0 -173
- package/framework/templates/code/dotnet/contracts/contracts-level1.cs +0 -69
- package/framework/templates/code/dotnet/contracts/contracts-level2.cs +0 -86
- package/framework/templates/code/dotnet/contracts/contracts-level3.cs +0 -41
- package/framework/templates/code/dotnet/frontend/component.razor +0 -239
- package/framework/templates/infrastructure/azure/Dockerfile.example +0 -82
- package/framework/templates/infrastructure/azure/README.md +0 -286
- package/framework/templates/infrastructure/azure/app-insights.bicep +0 -63
- package/framework/templates/infrastructure/azure/app-service.bicep +0 -164
- package/framework/templates/infrastructure/azure/container-app-env.bicep +0 -49
- package/framework/templates/infrastructure/azure/container-app.bicep +0 -156
- package/framework/templates/infrastructure/azure/deploy-checklist.md +0 -426
- package/framework/templates/infrastructure/azure/deploy.ps1 +0 -229
- package/framework/templates/infrastructure/azure/deploy.sh +0 -208
- package/framework/templates/infrastructure/azure/key-vault.bicep +0 -91
- package/framework/templates/infrastructure/azure/main.bicep +0 -189
- package/framework/templates/infrastructure/azure/parameters.dev.json +0 -29
- package/framework/templates/infrastructure/azure/parameters.prod.json +0 -29
- package/framework/templates/infrastructure/azure/parameters.staging.json +0 -29
- package/framework/templates/infrastructure/azure/sql-database.bicep +0 -103
- package/framework/templates/infrastructure/azure/storage.bicep +0 -106
- package/framework/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +0 -22
- package/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +0 -61
- package/framework/templates/integrations/azure-identity-config.cs +0 -288
- package/framework/templates/project-structure/dotnet-ddd.md +0 -70
- package/framework/templates/saas/subscription.cs +0 -347
- package/framework/templates/saas/tenant.cs +0 -338
- package/framework/templates/ui/FluentDesignTheme.cs +0 -149
- package/framework/templates/ui/MudTheme.cs +0 -281
- package/framework/workflows/configs/nodejs-cli.json +0 -40
- package/src/commands/standards/context-budget.js +0 -89
- package/src/lib/standards/index.js +0 -7
- package/src/lib/standards/standards-context-injector.js +0 -302
- package/src/lib/validators/blazor/blazor-concurrency-analyzer.js +0 -316
- package/src/lib/validators/blazor/blazor-state-validator.js +0 -279
- package/src/lib/validators/blazor/blazor-validator.js +0 -369
- package/src/lib/validators/blazor/index.js +0 -9
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
* Fail-open: exits 0 on any error.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { loadState, getActiveFeature, getPendingGates, getMissingOutputs, derivePhaseForFeature } from '../../shared/state-reader.js';
|
|
14
|
+
import { loadState, getActiveFeature, getPendingGates, getMissingOutputs, derivePhaseForFeature, getTaskStats } 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 { resetActivity, logHookActivity } from '../../shared/activity-logger.js';
|
|
18
|
-
import { readFileSync, existsSync, writeFileSync, renameSync, unlinkSync } from 'fs';
|
|
18
|
+
import { readFileSync, existsSync, writeFileSync, renameSync, unlinkSync, statSync } from 'fs';
|
|
19
19
|
import { join } from 'path';
|
|
20
20
|
import { resetStaleTasks } from '../../shared/stale-task-reset.js';
|
|
21
21
|
import { execSync as _execSync } from 'child_process';
|
|
22
22
|
import { parseWorktreeResult, buildWorktreeContextLine, buildWorktreeResumeContext } from '../../shared/worktree-helpers.js';
|
|
23
23
|
|
|
24
|
-
const DEFAULT_SPEC_MAX_CHARS =
|
|
24
|
+
const DEFAULT_SPEC_MAX_CHARS = 6000;
|
|
25
25
|
|
|
26
26
|
function getSpecMaxChars() {
|
|
27
27
|
try {
|
|
@@ -90,6 +90,29 @@ try {
|
|
|
90
90
|
// ────────────────────────────────────────────────────────────────────────────
|
|
91
91
|
|
|
92
92
|
const lines = ['MORPH-SPEC Status:'];
|
|
93
|
+
|
|
94
|
+
// ── Context freshness check ─────────────────────────────────────────────
|
|
95
|
+
// If .morph/context/README.md is missing or older than 24h, suggest refresh.
|
|
96
|
+
try {
|
|
97
|
+
const contextReadmePath = join(process.cwd(), '.morph/context/README.md');
|
|
98
|
+
let contextStale = false;
|
|
99
|
+
if (!existsSync(contextReadmePath)) {
|
|
100
|
+
contextStale = true;
|
|
101
|
+
} else {
|
|
102
|
+
const stat = statSync(contextReadmePath);
|
|
103
|
+
const ageMs = Date.now() - stat.mtimeMs;
|
|
104
|
+
const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000;
|
|
105
|
+
contextStale = ageMs > TWENTY_FOUR_HOURS;
|
|
106
|
+
}
|
|
107
|
+
if (contextStale) {
|
|
108
|
+
lines.push('');
|
|
109
|
+
lines.push('⚠ Architecture context is stale or missing. Run: morph-spec context refresh');
|
|
110
|
+
}
|
|
111
|
+
} catch {
|
|
112
|
+
// Fail-open — context freshness check must never block the session
|
|
113
|
+
}
|
|
114
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
115
|
+
|
|
93
116
|
if (staleResetLog.length > 0) {
|
|
94
117
|
lines.push(`⚠️ ${staleResetLog.length} task(s) auto-reset in_progress → pending (orphaned from previous session): ${staleResetLog.join(', ')}`);
|
|
95
118
|
}
|
|
@@ -100,9 +123,10 @@ try {
|
|
|
100
123
|
lines.push(`- Active feature: ${name} (phase: ${phase}, workflow: ${feature.workflow || 'auto'})`);
|
|
101
124
|
lines.push(`- Status: ${feature.status}`);
|
|
102
125
|
|
|
103
|
-
// Task progress
|
|
104
|
-
|
|
105
|
-
|
|
126
|
+
// Task progress (read directly from taskList)
|
|
127
|
+
const stats = getTaskStats(feature);
|
|
128
|
+
if (stats.total > 0) {
|
|
129
|
+
lines.push(`- Tasks: ${stats.completed}/${stats.total} completed`);
|
|
106
130
|
}
|
|
107
131
|
|
|
108
132
|
// Pending approvals
|
|
@@ -124,16 +148,8 @@ try {
|
|
|
124
148
|
lines.push(`- Last checkpoint: #${lastCp.checkpointNum} (${lastCp.passed ? 'passed' : 'failed'})`);
|
|
125
149
|
}
|
|
126
150
|
|
|
127
|
-
// Task tracking guidance for work phases
|
|
128
|
-
if (['proposal', 'setup', 'uiux', 'design', 'clarify', 'plan', 'tasks', 'implement'].includes(phase)) {
|
|
129
|
-
lines.push('');
|
|
130
|
-
lines.push('⚠️ MANDATORY: Create session tasks (TaskCreate) BEFORE starting phase work.');
|
|
131
|
-
lines.push(' Analyze the phase workflow and create tasks reflecting your planned actions.');
|
|
132
|
-
lines.push(' Mark each in_progress → completed as you go. See phase skill for guidance.');
|
|
133
|
-
}
|
|
134
|
-
|
|
135
151
|
// Trust level visibility — warn when low trust may block approval gates
|
|
136
|
-
const APPROVAL_GATE_PHASES = new Set(['proposal', '
|
|
152
|
+
const APPROVAL_GATE_PHASES = new Set(['proposal', 'design', 'tasks']);
|
|
137
153
|
if (APPROVAL_GATE_PHASES.has(phase)) {
|
|
138
154
|
const config = getProjectConfig();
|
|
139
155
|
const trustLevel = config?.trust?.level || config?.trustLevel || 'low';
|
|
@@ -150,15 +166,15 @@ try {
|
|
|
150
166
|
}
|
|
151
167
|
|
|
152
168
|
// Active feature spec (truncated for context budget)
|
|
153
|
-
const specPath = join(process.cwd(), `.morph/features/${name}/
|
|
169
|
+
const specPath = join(process.cwd(), `.morph/features/${name}/2-design/spec.md`);
|
|
154
170
|
if (existsSync(specPath)) {
|
|
155
171
|
try {
|
|
156
172
|
const specContent = readFileSync(specPath, 'utf-8');
|
|
157
173
|
const truncated = specContent.length > SPEC_MAX_CHARS
|
|
158
|
-
? specContent.slice(0, SPEC_MAX_CHARS) + `\n\n[... spec truncated — full file at .morph/features/${name}/
|
|
174
|
+
? specContent.slice(0, SPEC_MAX_CHARS) + `\n\n[... spec truncated — full file at .morph/features/${name}/2-design/spec.md]`
|
|
159
175
|
: specContent;
|
|
160
176
|
lines.push('');
|
|
161
|
-
lines.push(`--- Active feature spec (${name}/
|
|
177
|
+
lines.push(`--- Active feature spec (${name}/2-design/spec.md) ---`);
|
|
162
178
|
lines.push(truncated);
|
|
163
179
|
lines.push('--- End spec ---');
|
|
164
180
|
} catch {
|
|
@@ -249,20 +265,37 @@ try {
|
|
|
249
265
|
}
|
|
250
266
|
// ────────────────────────────────────────────────────────────────────────────
|
|
251
267
|
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
|
|
268
|
+
// ── CLI availability detection ─────────────────────────────────────────────
|
|
269
|
+
// Check which development CLIs are available for the current phase.
|
|
270
|
+
// Uses execSync with short timeout — fail-open on any error.
|
|
271
|
+
try {
|
|
272
|
+
const currentPhaseForCli = active ? derivePhaseForFeature(active.name) : '';
|
|
273
|
+
if (currentPhaseForCli) {
|
|
274
|
+
const cliChecks = [
|
|
275
|
+
{ name: 'docker', cmd: 'docker --version', phases: ['design', 'implement'] },
|
|
276
|
+
{ name: 'supabase', cmd: 'npx supabase --version', phases: ['design', 'implement'] },
|
|
277
|
+
{ name: 'psql', cmd: 'psql --version', phases: ['design', 'implement'] },
|
|
278
|
+
{ name: 'az', cmd: 'az version --output none', phases: ['implement'] },
|
|
279
|
+
{ name: 'gh', cmd: 'gh --version', phases: ['design', 'tasks', 'implement'] },
|
|
280
|
+
];
|
|
255
281
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
282
|
+
const relevant = cliChecks.filter(c => c.phases.includes(currentPhaseForCli));
|
|
283
|
+
if (relevant.length > 0) {
|
|
284
|
+
const cliStatus = relevant.map(c => {
|
|
285
|
+
try {
|
|
286
|
+
_execSync(c.cmd, { stdio: 'pipe', timeout: 5000 });
|
|
287
|
+
return `${c.name} ✓`;
|
|
288
|
+
} catch {
|
|
289
|
+
return `${c.name} ✗`;
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
lines.push(`CLIs: ${cliStatus.join(', ')}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
// Fail-open — CLI detection must never block the session
|
|
265
297
|
}
|
|
298
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
266
299
|
|
|
267
300
|
injectContext(lines.join('\n'));
|
|
268
301
|
} catch {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SessionStart Hook: Resume Context Orientation
|
|
5
|
+
*
|
|
6
|
+
* Event: SessionStart | Matcher: resume
|
|
7
|
+
*
|
|
8
|
+
* Fires ONLY when a session resumes via /resume.
|
|
9
|
+
* Injects a brief orientation message so Claude immediately knows
|
|
10
|
+
* the active feature, phase, in-progress tasks, and last checkpoint.
|
|
11
|
+
*
|
|
12
|
+
* Fail-open: exits 0 on any error.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { existsSync, readFileSync } from 'fs';
|
|
16
|
+
import { join } from 'path';
|
|
17
|
+
import {
|
|
18
|
+
stateExists, getActiveFeature, derivePhaseForFeature,
|
|
19
|
+
} from '../../shared/state-reader.js';
|
|
20
|
+
import { injectContext, pass } from '../../shared/hook-response.js';
|
|
21
|
+
import { logHookActivity } from '../../shared/activity-logger.js';
|
|
22
|
+
import { SPEC_SUMMARY_MAX_CHARS } from '../../shared/compact-restore.js';
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
if (!stateExists()) pass();
|
|
26
|
+
|
|
27
|
+
const active = getActiveFeature();
|
|
28
|
+
if (!active) pass();
|
|
29
|
+
|
|
30
|
+
const { name, feature } = active;
|
|
31
|
+
const phase = derivePhaseForFeature(name);
|
|
32
|
+
const cwd = process.cwd();
|
|
33
|
+
|
|
34
|
+
const lines = [
|
|
35
|
+
`🔄 RESUME — Você está continuando a feature "${name}" na fase ${phase}.`,
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
// In-progress tasks
|
|
39
|
+
const taskList = Array.isArray(feature.taskList) ? feature.taskList : [];
|
|
40
|
+
const inProg = taskList.filter(t => t.status === 'in_progress');
|
|
41
|
+
if (inProg.length > 0) {
|
|
42
|
+
const ids = inProg.map(t => t.id).join(', ');
|
|
43
|
+
lines.push(`Tasks em progresso: ${ids}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Task progress summary
|
|
47
|
+
const tasks = feature.tasks || {};
|
|
48
|
+
if (tasks.total > 0) {
|
|
49
|
+
lines.push(`Progresso: ${tasks.completed || 0}/${tasks.total} tasks concluídas`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Last checkpoint
|
|
53
|
+
const checkpoints = Array.isArray(feature.checkpoints) ? feature.checkpoints : [];
|
|
54
|
+
if (checkpoints.length > 0) {
|
|
55
|
+
const last = checkpoints[checkpoints.length - 1];
|
|
56
|
+
lines.push(`Último checkpoint: #${last.checkpointNum} (${last.passed ? 'passed' : 'failed'})`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Spec summary (truncated)
|
|
60
|
+
const specPath = join(cwd, `.morph/features/${name}/2-design/spec.md`);
|
|
61
|
+
if (existsSync(specPath)) {
|
|
62
|
+
try {
|
|
63
|
+
const raw = readFileSync(specPath, 'utf-8');
|
|
64
|
+
const summary = raw.length > SPEC_SUMMARY_MAX_CHARS
|
|
65
|
+
? raw.slice(0, SPEC_SUMMARY_MAX_CHARS) + '\n[... truncated]'
|
|
66
|
+
: raw;
|
|
67
|
+
lines.push('');
|
|
68
|
+
lines.push('Spec summary:');
|
|
69
|
+
lines.push(summary);
|
|
70
|
+
} catch { /* non-blocking */ }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
logHookActivity('resume-context', 'SessionStart', 'resume_injected');
|
|
74
|
+
injectContext(lines.join('\n'));
|
|
75
|
+
} catch {
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
@@ -37,19 +37,18 @@ _CREATE_NO_WINDOW = 0x08000000 if os.name == 'nt' else 0
|
|
|
37
37
|
# ── MORPH framework constants (derived from phases.json / trust-manager.js) ──
|
|
38
38
|
|
|
39
39
|
PHASE_POSITIONS = {
|
|
40
|
-
'proposal': 1,
|
|
40
|
+
'proposal': 1,
|
|
41
41
|
'uiux': 2, 'design': 2,
|
|
42
|
-
'
|
|
42
|
+
'plan': 3,
|
|
43
43
|
'tasks': 4,
|
|
44
44
|
'implement': 5, 'sync': 5,
|
|
45
45
|
}
|
|
46
46
|
PHASE_LABELS = {
|
|
47
47
|
'proposal': 'proposal',
|
|
48
|
-
'setup': 'setup',
|
|
49
48
|
'uiux': 'UI/UX',
|
|
50
49
|
'design': 'design',
|
|
51
|
-
'
|
|
52
|
-
'tasks': '
|
|
50
|
+
'plan': 'planning',
|
|
51
|
+
'tasks': 'tasks',
|
|
53
52
|
'implement': 'implement',
|
|
54
53
|
'sync': 'sync',
|
|
55
54
|
}
|
|
@@ -30,7 +30,7 @@ import { logHookActivity } from '../../shared/activity-logger.js';
|
|
|
30
30
|
const COMPACT_TRIGGER_PHASES = new Set(['implement']);
|
|
31
31
|
|
|
32
32
|
// Phases where compaction is suggested when arriving from a heavy spec phase
|
|
33
|
-
const HEAVY_SOURCE_PHASES = new Set(['tasks', 'design', '
|
|
33
|
+
const HEAVY_SOURCE_PHASES = new Set(['tasks', 'design', 'uiux']);
|
|
34
34
|
|
|
35
35
|
try {
|
|
36
36
|
// Prevent infinite loop
|
|
@@ -78,7 +78,7 @@ try {
|
|
|
78
78
|
` loaded during planning take significant space. A compact now gives`,
|
|
79
79
|
` Claude a clean slate focused on writing code.`,
|
|
80
80
|
``,
|
|
81
|
-
` After /compact, resume with: morph-spec task
|
|
81
|
+
` After /compact, resume with: morph-spec task start ${name} <next-task-id>`,
|
|
82
82
|
);
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -96,7 +96,7 @@ try {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
// Missing outputs in spec phases
|
|
99
|
-
if (['proposal', 'design', '
|
|
99
|
+
if (['proposal', 'design', 'tasks', 'uiux'].includes(currentPhase)) {
|
|
100
100
|
const missing = getMissingOutputs(name);
|
|
101
101
|
if (missing.length > 0) {
|
|
102
102
|
warnings.push(`Missing outputs for '${name}' (${currentPhase} phase):`);
|
|
@@ -124,7 +124,7 @@ try {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// ── MEMORY.md reminder ────────────────────────────────────────────────────
|
|
127
|
-
const WORK_PHASES = new Set(['design', '
|
|
127
|
+
const WORK_PHASES = new Set(['design', 'tasks', 'implement']);
|
|
128
128
|
const memoryLines = [];
|
|
129
129
|
if (WORK_PHASES.has(currentPhase)) {
|
|
130
130
|
memoryLines.push('📝 Sessão encerrando. Considere salvar no MEMORY.md:');
|
|
@@ -39,8 +39,11 @@ try {
|
|
|
39
39
|
if (promptLower.includes(featureName.toLowerCase())) {
|
|
40
40
|
const featurePhase = feature.phase || derivePhaseForFeature(featureName);
|
|
41
41
|
context.push(`[morph-spec] Feature '${featureName}': phase=${featurePhase}, status=${feature.status}`);
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
const taskList = feature.taskList || [];
|
|
43
|
+
const activeTasks = taskList.filter(t => t.status !== 'expanded');
|
|
44
|
+
if (activeTasks.length > 0) {
|
|
45
|
+
const completed = activeTasks.filter(t => t.status === 'completed').length;
|
|
46
|
+
context.push(` Tasks: ${completed}/${activeTasks.length} completed`);
|
|
44
47
|
}
|
|
45
48
|
break; // Only inject for the first matched feature
|
|
46
49
|
}
|
|
@@ -64,15 +67,12 @@ try {
|
|
|
64
67
|
|
|
65
68
|
// Coding intent during implement phase but no task in_progress
|
|
66
69
|
if (wantsToCode && activePhase === 'implement') {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
hasActiveTask = feature.taskList.some(t => t.status === 'in_progress');
|
|
70
|
-
}
|
|
70
|
+
const hasActiveTask = feature.taskList?.some(t => t.status === 'in_progress') ||
|
|
71
|
+
feature.tasks?.inProgress > 0; // fallback for legacy state
|
|
71
72
|
if (!hasActiveTask) {
|
|
72
73
|
context.push(
|
|
73
74
|
`[morph-spec] REMINDER: No task is currently in_progress for '${name}'.` +
|
|
74
75
|
` Start a task before coding:\n` +
|
|
75
|
-
` morph-spec task next ${name} # see what's next\n` +
|
|
76
76
|
` morph-spec task start ${name} <id> # mark it in progress`
|
|
77
77
|
);
|
|
78
78
|
}
|
|
@@ -95,7 +95,7 @@ try {
|
|
|
95
95
|
if (promptLower.includes('next task') || promptLower.includes('what\'s next')) {
|
|
96
96
|
if (activePhase === 'implement') {
|
|
97
97
|
context.push(
|
|
98
|
-
`[morph-spec]
|
|
98
|
+
`[morph-spec] Check tasks.md for the next task, then: morph-spec task start ${name} <id>`
|
|
99
99
|
);
|
|
100
100
|
}
|
|
101
101
|
}
|
|
@@ -8,17 +8,19 @@
|
|
|
8
8
|
* Pure functions — no I/O.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
export const DECISIONS_MAX_CHARS
|
|
12
|
-
export const MAX_PENDING_TASKS
|
|
11
|
+
export const DECISIONS_MAX_CHARS = 3000;
|
|
12
|
+
export const MAX_PENDING_TASKS = 8;
|
|
13
|
+
export const SPEC_SUMMARY_MAX_CHARS = 3000;
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Build the richContext object to embed in pre-compact memory file.
|
|
16
|
-
* @param {Object} feature - Feature state object (tasks, taskList)
|
|
17
|
+
* @param {Object} feature - Feature state object (tasks, taskList, checkpoints)
|
|
17
18
|
* @param {string} phase - Current derived phase string
|
|
18
19
|
* @param {string} decisionsContent - Raw text of decisions.md (may be empty string)
|
|
20
|
+
* @param {string} [specContent=''] - Raw text of spec.md (may be empty string)
|
|
19
21
|
* @returns {Object} richContext
|
|
20
22
|
*/
|
|
21
|
-
export function buildRichContext(feature, phase, decisionsContent) {
|
|
23
|
+
export function buildRichContext(feature, phase, decisionsContent, specContent = '') {
|
|
22
24
|
const taskList = Array.isArray(feature.taskList) ? feature.taskList : [];
|
|
23
25
|
|
|
24
26
|
const inProgress = taskList
|
|
@@ -34,12 +36,23 @@ export function buildRichContext(feature, phase, decisionsContent) {
|
|
|
34
36
|
? decisionsContent.slice(0, DECISIONS_MAX_CHARS)
|
|
35
37
|
: decisionsContent;
|
|
36
38
|
|
|
39
|
+
const specSummary = specContent.length > SPEC_SUMMARY_MAX_CHARS
|
|
40
|
+
? specContent.slice(0, SPEC_SUMMARY_MAX_CHARS)
|
|
41
|
+
: specContent;
|
|
42
|
+
|
|
43
|
+
const checkpoints = Array.isArray(feature.checkpoints) ? feature.checkpoints : [];
|
|
44
|
+
const lastCheckpoint = checkpoints.length > 0
|
|
45
|
+
? { passed: checkpoints[checkpoints.length - 1].passed, checkpointNum: checkpoints[checkpoints.length - 1].checkpointNum }
|
|
46
|
+
: null;
|
|
47
|
+
|
|
37
48
|
return {
|
|
38
49
|
phase,
|
|
39
50
|
tasks: feature.tasks || {},
|
|
40
51
|
decisionsSnippet,
|
|
41
52
|
inProgress,
|
|
42
53
|
nextPending,
|
|
54
|
+
specSummary,
|
|
55
|
+
lastCheckpoint,
|
|
43
56
|
};
|
|
44
57
|
}
|
|
45
58
|
|
|
@@ -53,7 +66,7 @@ export function buildRestoreBlock(memorySnapshot) {
|
|
|
53
66
|
if (!rc) return null;
|
|
54
67
|
|
|
55
68
|
const { timestamp, activeFeature } = memorySnapshot;
|
|
56
|
-
const { phase, tasks, decisionsSnippet, inProgress, nextPending } = rc;
|
|
69
|
+
const { phase, tasks, decisionsSnippet, inProgress, nextPending, specSummary, lastCheckpoint } = rc;
|
|
57
70
|
|
|
58
71
|
const done = tasks?.completed ?? '?';
|
|
59
72
|
const total = tasks?.total ?? '?';
|
|
@@ -63,6 +76,16 @@ export function buildRestoreBlock(memorySnapshot) {
|
|
|
63
76
|
`Active feature: ${activeFeature} | Phase: ${phase} | Tasks: ${done}/${total}`,
|
|
64
77
|
];
|
|
65
78
|
|
|
79
|
+
if (lastCheckpoint) {
|
|
80
|
+
lines.push(`Last checkpoint: #${lastCheckpoint.checkpointNum} (${lastCheckpoint.passed ? 'passed' : 'failed'})`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (specSummary) {
|
|
84
|
+
lines.push('');
|
|
85
|
+
lines.push('Spec summary (at time of compact):');
|
|
86
|
+
lines.push(specSummary);
|
|
87
|
+
}
|
|
88
|
+
|
|
66
89
|
if (decisionsSnippet) {
|
|
67
90
|
lines.push('');
|
|
68
91
|
lines.push('Key decisions (at time of compact):');
|
|
@@ -112,6 +112,23 @@ export function parseDispatchAgentsCommand(command) {
|
|
|
112
112
|
return { featureName: match[1], phase: match[2] };
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Convert a subagent_type string back to a morph agent ID.
|
|
117
|
+
* Reverses the mapping used when dispatching agents as subagents.
|
|
118
|
+
*
|
|
119
|
+
* Example: 'morph-nextjs-expert' → 'nextjs-expert'
|
|
120
|
+
*
|
|
121
|
+
* @param {string} subagentType - The subagent_type value (e.g. 'morph-nextjs-expert')
|
|
122
|
+
* @returns {string|null} - Agent ID without 'morph-' prefix, or null if invalid
|
|
123
|
+
*/
|
|
124
|
+
export function subagentTypeToAgentId(subagentType) {
|
|
125
|
+
if (!subagentType || typeof subagentType !== 'string') return null;
|
|
126
|
+
if (!subagentType.startsWith('morph-')) return null;
|
|
127
|
+
const agentId = subagentType.slice('morph-'.length);
|
|
128
|
+
if (!agentId) return null;
|
|
129
|
+
return agentId;
|
|
130
|
+
}
|
|
131
|
+
|
|
115
132
|
/**
|
|
116
133
|
* Extract the tool result string from a PostToolUse hook payload.
|
|
117
134
|
* Handles multiple possible formats.
|
|
@@ -8,15 +8,13 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/** Phase order */
|
|
11
|
-
export const PHASE_ORDER = ["proposal","
|
|
11
|
+
export const PHASE_ORDER = ["proposal","uiux","design","plan","tasks","implement","sync"];
|
|
12
12
|
|
|
13
13
|
/** Map phase → allowed output subdirectory */
|
|
14
14
|
export const PHASE_DIRS = {
|
|
15
15
|
proposal: '0-proposal',
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
design: '1-design',
|
|
19
|
-
clarify: '1-design',
|
|
16
|
+
uiux: '1-ui',
|
|
17
|
+
design: '2-design',
|
|
20
18
|
plan: '3-plan',
|
|
21
19
|
tasks: '4-tasks',
|
|
22
20
|
implement: '5-implement',
|
|
@@ -28,7 +26,6 @@ export const OUTPUT_PHASE_MAP = {
|
|
|
28
26
|
proposal: 'proposal',
|
|
29
27
|
schemaAnalysis: 'design',
|
|
30
28
|
spec: 'design',
|
|
31
|
-
clarifications: 'clarify',
|
|
32
29
|
contracts: 'design',
|
|
33
30
|
contractsTs: 'design',
|
|
34
31
|
contractsVsa: 'design',
|
|
@@ -47,7 +44,6 @@ export const FILENAME_TO_OUTPUT = {
|
|
|
47
44
|
'proposal.md': 'proposal',
|
|
48
45
|
'schema-analysis.md': 'schemaAnalysis',
|
|
49
46
|
'spec.md': 'spec',
|
|
50
|
-
'clarifications.md': 'clarifications',
|
|
51
47
|
'contracts.cs': 'contracts',
|
|
52
48
|
'contracts.ts': 'contractsTs',
|
|
53
49
|
'contracts-vsa.cs': 'contractsVsa',
|
|
@@ -90,7 +86,7 @@ export function extractFeatureName(filePath) {
|
|
|
90
86
|
/**
|
|
91
87
|
* Extract phase subdirectory from a .morph/features/{feature}/{phaseDir}/... path
|
|
92
88
|
* @param {string} filePath - File path to analyze
|
|
93
|
-
* @returns {string|null} Phase directory (e.g., '0-proposal', '
|
|
89
|
+
* @returns {string|null} Phase directory (e.g., '0-proposal', '2-design') or null
|
|
94
90
|
*/
|
|
95
91
|
export function extractPhaseDir(filePath) {
|
|
96
92
|
const normalized = filePath.replace(/\\/g, '/');
|
|
@@ -110,14 +110,14 @@ export function derivePhaseForFeature(featureName, projectPath) {
|
|
|
110
110
|
['5-implement', 'implement'],
|
|
111
111
|
['4-tasks', 'tasks'],
|
|
112
112
|
['3-plan', 'plan'],
|
|
113
|
-
['2-
|
|
114
|
-
['1-
|
|
113
|
+
['2-design', 'design'],
|
|
114
|
+
['1-ui', 'uiux'],
|
|
115
115
|
['0-proposal', 'proposal'],
|
|
116
116
|
];
|
|
117
117
|
for (const [folder, phase] of phaseMap) {
|
|
118
118
|
if (existsSync(join(basePath, folder))) return phase;
|
|
119
119
|
}
|
|
120
|
-
return '
|
|
120
|
+
return 'proposal';
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
/**
|
|
@@ -181,6 +181,37 @@ export function getOutputs(featureName, projectPath) {
|
|
|
181
181
|
* @param {string} [projectPath]
|
|
182
182
|
* @returns {Array<{type: string, path: string}>}
|
|
183
183
|
*/
|
|
184
|
+
/**
|
|
185
|
+
* Get task statistics directly from taskList (preferred over feature.tasks counters).
|
|
186
|
+
* Excludes expanded tasks from counts, matching calculateProgress() behavior.
|
|
187
|
+
*
|
|
188
|
+
* @param {Object} feature - Feature state object
|
|
189
|
+
* @returns {{ total: number, completed: number, inProgress: number, pending: number }}
|
|
190
|
+
*/
|
|
191
|
+
export function getTaskStats(feature) {
|
|
192
|
+
const list = feature?.taskList || [];
|
|
193
|
+
if (list.length > 0) {
|
|
194
|
+
const active = list.filter(t => t.status !== 'expanded');
|
|
195
|
+
return {
|
|
196
|
+
total: active.length,
|
|
197
|
+
completed: active.filter(t => t.status === 'completed').length,
|
|
198
|
+
inProgress: active.filter(t => t.status === 'in_progress').length,
|
|
199
|
+
pending: active.filter(t => t.status === 'pending').length,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// Fallback: read from legacy counter object
|
|
203
|
+
const tasks = feature?.tasks;
|
|
204
|
+
if (tasks && typeof tasks === 'object' && !Array.isArray(tasks)) {
|
|
205
|
+
return {
|
|
206
|
+
total: tasks.total || 0,
|
|
207
|
+
completed: tasks.completed || 0,
|
|
208
|
+
inProgress: tasks.inProgress || 0,
|
|
209
|
+
pending: tasks.pending || 0,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
return { total: 0, completed: 0, inProgress: 0, pending: 0 };
|
|
213
|
+
}
|
|
214
|
+
|
|
184
215
|
export function getMissingOutputs(featureName, projectPath) {
|
|
185
216
|
const feature = getFeature(featureName, projectPath);
|
|
186
217
|
if (!feature?.outputs) return [];
|
package/framework/phases.json
CHANGED
|
@@ -22,27 +22,10 @@
|
|
|
22
22
|
{ "trigger": "beforePhaseStart", "skill": "morph-brainstorming" }
|
|
23
23
|
]
|
|
24
24
|
},
|
|
25
|
-
"setup": {
|
|
26
|
-
"id": "setup",
|
|
27
|
-
"index": 1,
|
|
28
|
-
"folder": null,
|
|
29
|
-
"displayName": "Setup",
|
|
30
|
-
"goals": [
|
|
31
|
-
"Load project context from .morph/context/",
|
|
32
|
-
"Activate relevant agents by tier and keyword",
|
|
33
|
-
"Confirm workflow type (fast-track / standard / full-morph)"
|
|
34
|
-
],
|
|
35
|
-
"requiredOutputs": [],
|
|
36
|
-
"optionalOutputs": [],
|
|
37
|
-
"recommendedMCPs": ["github"],
|
|
38
|
-
"pausePoints": [],
|
|
39
|
-
"agentTiers": [1, 2],
|
|
40
|
-
"requiredSkills": []
|
|
41
|
-
},
|
|
42
25
|
"uiux": {
|
|
43
26
|
"id": "uiux",
|
|
44
|
-
"index":
|
|
45
|
-
"folder": "
|
|
27
|
+
"index": 2,
|
|
28
|
+
"folder": "1-ui",
|
|
46
29
|
"displayName": "UI/UX Design",
|
|
47
30
|
"optional": true,
|
|
48
31
|
"goals": [
|
|
@@ -59,14 +42,13 @@
|
|
|
59
42
|
"agentTiers": [1, 2, 3],
|
|
60
43
|
"requiredSkills": [
|
|
61
44
|
{ "trigger": "beforeArchitecturalDecision", "skill": "morph-brainstorming" },
|
|
62
|
-
{ "trigger": "onHTMLPrototypeAvailable", "skill": "morph-replicate" },
|
|
63
45
|
{ "trigger": "beforePhaseComplete", "skill": "morph-frontend-review" }
|
|
64
46
|
]
|
|
65
47
|
},
|
|
66
48
|
"design": {
|
|
67
49
|
"id": "design",
|
|
68
|
-
"index":
|
|
69
|
-
"folder": "
|
|
50
|
+
"index": 3,
|
|
51
|
+
"folder": "2-design",
|
|
70
52
|
"displayName": "Technical Design",
|
|
71
53
|
"goals": [
|
|
72
54
|
"Write technical specification",
|
|
@@ -75,8 +57,8 @@
|
|
|
75
57
|
"Document architectural decisions"
|
|
76
58
|
],
|
|
77
59
|
"requiredOutputs": ["spec", "contracts"],
|
|
78
|
-
"optionalOutputs": ["schemaAnalysis", "
|
|
79
|
-
"recommendedMCPs": ["
|
|
60
|
+
"optionalOutputs": ["schemaAnalysis", "decisions"],
|
|
61
|
+
"recommendedMCPs": ["context7", "github"],
|
|
80
62
|
"pausePoints": [
|
|
81
63
|
{ "id": "design", "label": "Approve Design Spec" }
|
|
82
64
|
],
|
|
@@ -89,26 +71,6 @@
|
|
|
89
71
|
{ "trigger": "beforePhaseComplete", "skill": "morph-verification-before-completion" }
|
|
90
72
|
]
|
|
91
73
|
},
|
|
92
|
-
"clarify": {
|
|
93
|
-
"id": "clarify",
|
|
94
|
-
"index": 3,
|
|
95
|
-
"folder": "1-design",
|
|
96
|
-
"displayName": "Clarification",
|
|
97
|
-
"goals": [
|
|
98
|
-
"Resolve open questions and ambiguities",
|
|
99
|
-
"Update spec with clarification decisions",
|
|
100
|
-
"Confirm edge cases are handled"
|
|
101
|
-
],
|
|
102
|
-
"requiredOutputs": ["clarifications"],
|
|
103
|
-
"optionalOutputs": [],
|
|
104
|
-
"recommendedMCPs": ["context7", "github"],
|
|
105
|
-
"pausePoints": [],
|
|
106
|
-
"agentTiers": [1, 2],
|
|
107
|
-
"requiredSkills": [
|
|
108
|
-
{ "trigger": "beforePhaseStart", "skill": "morph-phase-clarify" },
|
|
109
|
-
{ "trigger": "beforePhaseComplete", "skill": "morph-verification-before-completion" }
|
|
110
|
-
]
|
|
111
|
-
},
|
|
112
74
|
"plan": {
|
|
113
75
|
"id": "plan",
|
|
114
76
|
"index": 5,
|
|
@@ -166,7 +128,7 @@
|
|
|
166
128
|
],
|
|
167
129
|
"requiredOutputs": ["recap"],
|
|
168
130
|
"optionalOutputs": [],
|
|
169
|
-
"recommendedMCPs": ["
|
|
131
|
+
"recommendedMCPs": ["context7", "playwright", "github", "vercel"],
|
|
170
132
|
"pausePoints": [],
|
|
171
133
|
"agentTiers": [1, 2, 3, 4],
|
|
172
134
|
"requiredSkills": [
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/Agents/**"
|
|
4
|
+
- "**/agents/**"
|
|
5
|
+
- "**/*Agent*.cs"
|
|
6
|
+
stacks:
|
|
7
|
+
- dotnet
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Microsoft Agent Framework Standards
|
|
11
|
+
|
|
12
|
+
@.morph/framework/standards/ai-agents/setup.md
|
|
13
|
+
@.morph/framework/standards/ai-agents/workflows.md
|
|
14
|
+
@.morph/framework/standards/ai-agents/production.md
|
|
15
|
+
@.morph/framework/standards/integration/mcp/mcp-tools.md
|