@polymorphism-tech/morph-spec 4.7.1 → 4.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.morph/.morphversion +5 -0
- package/.morph/analytics/threads-log.jsonl +5 -0
- package/.morph/config/config.json +8 -0
- package/.morph/framework/agents.json +1815 -0
- package/.morph/framework/hooks/README.md +205 -0
- package/.morph/framework/hooks/claude-code/notification/approval-reminder.js +54 -0
- package/.morph/framework/hooks/claude-code/post-tool-use/dispatch.js +83 -0
- package/.morph/framework/hooks/claude-code/post-tool-use/handle-tool-failure.js +42 -0
- package/.morph/framework/hooks/claude-code/pre-compact/save-morph-context.js +61 -0
- package/.morph/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +71 -0
- package/.morph/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +58 -0
- package/.morph/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +64 -0
- package/.morph/framework/hooks/claude-code/session-start/inject-morph-context.js +94 -0
- package/.morph/framework/hooks/claude-code/statusline.py +538 -0
- package/.morph/framework/hooks/claude-code/statusline.sh +7 -0
- package/.morph/framework/hooks/claude-code/stop/validate-completion.js +88 -0
- package/.morph/framework/hooks/claude-code/user-prompt/enrich-prompt.js +91 -0
- package/.morph/framework/hooks/git/commit-msg/conventional-commits.sh +33 -0
- package/.morph/framework/hooks/git/pre-commit/agents.sh +25 -0
- package/.morph/framework/hooks/git/pre-commit/orchestrator.sh +64 -0
- package/.morph/framework/hooks/git/pre-commit/specs.sh +50 -0
- package/.morph/framework/hooks/git/pre-push/run-tests.sh +44 -0
- package/.morph/framework/hooks/shared/hook-response.js +45 -0
- package/.morph/framework/hooks/shared/phase-utils.js +129 -0
- package/.morph/framework/hooks/shared/state-reader.js +138 -0
- package/.morph/framework/hooks/shared/stdin-reader.js +26 -0
- package/.morph/framework/standards/STANDARDS.json +933 -0
- package/.morph/framework/standards/ai-agents/blazor-ui.md +364 -0
- package/.morph/framework/standards/ai-agents/production.md +415 -0
- package/.morph/framework/standards/ai-agents/setup.md +418 -0
- package/.morph/framework/standards/ai-agents/team-orchestration.md +479 -0
- package/.morph/framework/standards/ai-agents/workflows.md +354 -0
- package/.morph/framework/standards/architecture/ddd/aggregates.md +120 -0
- package/.morph/framework/standards/architecture/ddd/bounded-contexts.md +105 -0
- package/.morph/framework/standards/architecture/ddd/complexity-levels.md +108 -0
- package/.morph/framework/standards/architecture/ddd/entities.md +99 -0
- package/.morph/framework/standards/architecture/ddd/ubiquitous-language.md +58 -0
- package/.morph/framework/standards/architecture/ddd/value-objects.md +124 -0
- package/.morph/framework/standards/backend/api/minimal-api.md +494 -0
- package/.morph/framework/standards/backend/api/rest.md +492 -0
- package/.morph/framework/standards/backend/api/validation.md +88 -0
- package/.morph/framework/standards/backend/authentication/passkeys.md +428 -0
- package/.morph/framework/standards/backend/database/ef-core.md +199 -0
- package/.morph/framework/standards/backend/database/migrations.md +393 -0
- package/.morph/framework/standards/backend/database/postgresql/database.md +352 -0
- package/.morph/framework/standards/backend/database/repository-patterns.md +528 -0
- package/.morph/framework/standards/backend/database/vector-search-rag.md +541 -0
- package/.morph/framework/standards/backend/dotnet/async.md +366 -0
- package/.morph/framework/standards/backend/dotnet/core.md +117 -0
- package/.morph/framework/standards/backend/dotnet/di.md +439 -0
- package/.morph/framework/standards/backend/dotnet/program-cs-checklist.md +92 -0
- package/.morph/framework/standards/backend/integrations/asaas/asaas-api.md +216 -0
- package/.morph/framework/standards/backend/integrations/clerk/clerk-auth.md +290 -0
- package/.morph/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +350 -0
- package/.morph/framework/standards/backend/integrations/resend/resend-email.md +385 -0
- package/.morph/framework/standards/context/analytics.md +96 -0
- package/.morph/framework/standards/context/bundles.md +110 -0
- package/.morph/framework/standards/context/priming.md +78 -0
- package/.morph/framework/standards/core/architecture.md +185 -0
- package/.morph/framework/standards/core/coding.md +214 -0
- package/.morph/framework/standards/core/git-branching-strategy.md +403 -0
- package/.morph/framework/standards/core/git.md +185 -0
- package/.morph/framework/standards/core/testing.md +295 -0
- package/.morph/framework/standards/data/nosql/blob-storage.md +102 -0
- package/.morph/framework/standards/data/nosql/cache/redis.md +97 -0
- package/.morph/framework/standards/data/nosql/cosmos-db.md +118 -0
- package/.morph/framework/standards/data/vector-search/azure-ai-search.md +121 -0
- package/.morph/framework/standards/data/vector-search/rag-chunking.md +104 -0
- package/.morph/framework/standards/frontend/blazor/design-checklist.md +222 -0
- package/.morph/framework/standards/frontend/blazor/fluent-ui-setup.md +595 -0
- package/.morph/framework/standards/frontend/blazor/fluent-ui.md +137 -0
- package/.morph/framework/standards/frontend/blazor/html-conversion.md +184 -0
- package/.morph/framework/standards/frontend/blazor/lifecycle.md +195 -0
- package/.morph/framework/standards/frontend/blazor/pitfalls.md +198 -0
- package/.morph/framework/standards/frontend/blazor/state.md +191 -0
- package/.morph/framework/standards/frontend/design-system/animations.md +151 -0
- package/.morph/framework/standards/frontend/design-system/naming.md +64 -0
- package/.morph/framework/standards/frontend/nextjs/app-router.md +123 -0
- package/.morph/framework/standards/frontend/nextjs/components.md +132 -0
- package/.morph/framework/standards/frontend/nextjs/data-fetching.md +126 -0
- package/.morph/framework/standards/frontend/nextjs/forms.md +128 -0
- package/.morph/framework/standards/frontend/nextjs/naming-conventions.md +67 -0
- package/.morph/framework/standards/frontend/nextjs/nextjs-patterns.md +215 -0
- package/.morph/framework/standards/frontend/nextjs/project-structure.md +102 -0
- package/.morph/framework/standards/frontend/nextjs/state-management.md +72 -0
- package/.morph/framework/standards/frontend/nextjs/testing.md +111 -0
- package/.morph/framework/standards/infrastructure/azure/azure.md +624 -0
- package/.morph/framework/standards/infrastructure/azure/bicep/bicep-patterns.md +422 -0
- package/.morph/framework/standards/infrastructure/azure/devops/azure-devops-setup.md +516 -0
- package/.morph/framework/standards/infrastructure/azure/devops/local-development.md +520 -0
- package/.morph/framework/standards/infrastructure/azure/services/functions.md +486 -0
- package/.morph/framework/standards/infrastructure/azure/services/service-bus.md +459 -0
- package/.morph/framework/standards/infrastructure/azure/services/storage.md +407 -0
- package/.morph/framework/standards/infrastructure/docker/easypanel-deploy.md +196 -0
- package/.morph/framework/standards/infrastructure/supabase/mcp-setup.md +252 -0
- package/.morph/framework/standards/infrastructure/supabase/supabase-auth.md +176 -0
- package/.morph/framework/standards/infrastructure/supabase/supabase-pgvector.md +169 -0
- package/.morph/framework/standards/infrastructure/supabase/supabase-rls.md +184 -0
- package/.morph/framework/standards/infrastructure/supabase/supabase-storage.md +153 -0
- package/.morph/framework/standards/integration/api/graphql.md +91 -0
- package/.morph/framework/standards/integration/api/grpc.md +114 -0
- package/.morph/framework/standards/integration/api/rest-design.md +95 -0
- package/.morph/framework/standards/integration/event-driven/cqrs.md +101 -0
- package/.morph/framework/standards/integration/event-driven/event-sourcing.md +124 -0
- package/.morph/framework/standards/integration/event-driven/service-bus.md +95 -0
- package/.morph/framework/standards/integration/mcp/mcp-tools.md +384 -0
- package/.morph/framework/standards/observability/logging.md +131 -0
- package/.morph/framework/standards/observability/metrics.md +121 -0
- package/.morph/framework/standards/observability/monitoring.md +114 -0
- package/.morph/framework/standards/observability/tracing.md +132 -0
- package/.morph/framework/standards/workflows/parallel-execution.md +112 -0
- package/.morph/framework/standards/workflows/thread-management.md +113 -0
- package/.morph/framework/templates/.idea/morph-templates.xml +92 -0
- package/.morph/framework/templates/.vscode/morph-templates.code-snippets +186 -0
- package/.morph/framework/templates/IDE-SNIPPETS.md +266 -0
- package/.morph/framework/templates/README.md +814 -0
- package/.morph/framework/templates/REGISTRY.json +1888 -0
- package/.morph/framework/templates/code/dotnet/backend/repository.cs +141 -0
- package/.morph/framework/templates/code/dotnet/backend/service.cs +139 -0
- package/.morph/framework/templates/code/dotnet/contracts/Commands.cs +74 -0
- package/.morph/framework/templates/code/dotnet/contracts/Entities.cs +25 -0
- package/.morph/framework/templates/code/dotnet/contracts/Queries.cs +74 -0
- package/.morph/framework/templates/code/dotnet/contracts/README.md +74 -0
- package/.morph/framework/templates/code/dotnet/contracts/api-contracts.cs +173 -0
- package/.morph/framework/templates/code/dotnet/contracts/contracts-level1.cs +69 -0
- package/.morph/framework/templates/code/dotnet/contracts/contracts-level2.cs +86 -0
- package/.morph/framework/templates/code/dotnet/contracts/contracts-level3.cs +41 -0
- package/.morph/framework/templates/code/dotnet/database/migration.cs +83 -0
- package/.morph/framework/templates/code/dotnet/frontend/component.razor +239 -0
- package/.morph/framework/templates/code/dotnet/jobs/agent.cs +163 -0
- package/.morph/framework/templates/code/dotnet/jobs/job.cs +171 -0
- package/.morph/framework/templates/code/dotnet/test.cs +239 -0
- package/.morph/framework/templates/code/sql/rls-policy.sql +57 -0
- package/.morph/framework/templates/code/sql/supabase-migration.sql +100 -0
- package/.morph/framework/templates/code/sql/supabase-migration.template.sql +113 -0
- package/.morph/framework/templates/code/typescript/contracts.ts +168 -0
- package/.morph/framework/templates/context/CONTEXT-FEATURE.md +276 -0
- package/.morph/framework/templates/context/CONTEXT.md +181 -0
- package/.morph/framework/templates/docs/clarifications.md +253 -0
- package/.morph/framework/templates/docs/onboarding.md +123 -0
- package/.morph/framework/templates/docs/proposal.md +182 -0
- package/.morph/framework/templates/docs/schema-analysis.md +119 -0
- package/.morph/framework/templates/docs/spec.md +198 -0
- package/.morph/framework/templates/docs/ui-components.md +124 -0
- package/.morph/framework/templates/docs/ui-design-system.md +76 -0
- package/.morph/framework/templates/docs/ui-flows.md +167 -0
- package/.morph/framework/templates/docs/ui-mockups.md +98 -0
- package/.morph/framework/templates/docs/user-stories.md +34 -0
- package/.morph/framework/templates/examples/design-system-examples.md +357 -0
- package/.morph/framework/templates/examples/spec-examples.md +90 -0
- package/.morph/framework/templates/feature/decisions.md +187 -0
- package/.morph/framework/templates/feature/recap.md +146 -0
- package/.morph/framework/templates/feature/tasks.md +199 -0
- package/.morph/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -0
- package/.morph/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -0
- package/.morph/framework/templates/frontend/nextjs/env.mjs.hbs +32 -0
- package/.morph/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -0
- package/.morph/framework/templates/frontend/nextjs/page.tsx.hbs +22 -0
- package/.morph/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -0
- package/.morph/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -0
- package/.morph/framework/templates/infrastructure/azure/Dockerfile.example +82 -0
- package/.morph/framework/templates/infrastructure/azure/README.md +286 -0
- package/.morph/framework/templates/infrastructure/azure/app-insights.bicep +63 -0
- package/.morph/framework/templates/infrastructure/azure/app-service.bicep +164 -0
- package/.morph/framework/templates/infrastructure/azure/container-app-env.bicep +49 -0
- package/.morph/framework/templates/infrastructure/azure/container-app.bicep +156 -0
- package/.morph/framework/templates/infrastructure/azure/deploy-checklist.md +426 -0
- package/.morph/framework/templates/infrastructure/azure/deploy.ps1 +229 -0
- package/.morph/framework/templates/infrastructure/azure/deploy.sh +208 -0
- package/.morph/framework/templates/infrastructure/azure/key-vault.bicep +91 -0
- package/.morph/framework/templates/infrastructure/azure/main.bicep +189 -0
- package/.morph/framework/templates/infrastructure/azure/parameters.dev.json +29 -0
- package/.morph/framework/templates/infrastructure/azure/parameters.prod.json +29 -0
- package/.morph/framework/templates/infrastructure/azure/parameters.staging.json +29 -0
- package/.morph/framework/templates/infrastructure/azure/sql-database.bicep +103 -0
- package/.morph/framework/templates/infrastructure/azure/storage.bicep +106 -0
- package/.morph/framework/templates/infrastructure/docker/Dockerfile.template +58 -0
- package/.morph/framework/templates/infrastructure/docker/docker-compose.template.yml +67 -0
- package/.morph/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -0
- package/.morph/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -0
- package/.morph/framework/templates/infrastructure/docker/easypanel.template.json +54 -0
- package/.morph/framework/templates/infrastructure/github/README.md +593 -0
- package/.morph/framework/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +22 -0
- package/.morph/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -0
- package/.morph/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -0
- package/.morph/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +61 -0
- package/.morph/framework/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +31 -0
- package/.morph/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -0
- package/.morph/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -0
- package/.morph/framework/templates/integrations/asaas-client.cs +387 -0
- package/.morph/framework/templates/integrations/asaas-webhook.cs +351 -0
- package/.morph/framework/templates/integrations/azure-identity-config.cs +288 -0
- package/.morph/framework/templates/integrations/clerk-config.cs +258 -0
- package/.morph/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -0
- package/.morph/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -0
- package/.morph/framework/templates/meta-prompts/hops/hop-retry.md +78 -0
- package/.morph/framework/templates/meta-prompts/hops/hop-validation.md +97 -0
- package/.morph/framework/templates/meta-prompts/hops/hop-wrapper.md +36 -0
- package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-coordinator.md +113 -0
- package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +80 -0
- package/.morph/framework/templates/meta-prompts/squad-leaders/backend-squad.md +90 -0
- package/.morph/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +126 -0
- package/.morph/framework/templates/meta-prompts/squad-leaders/squad-leader.md +43 -0
- package/.morph/framework/templates/meta-prompts/validators/checkpoint-validator.md +107 -0
- package/.morph/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -0
- package/.morph/framework/templates/project-structure/dotnet-ddd.md +70 -0
- package/.morph/framework/templates/saas/subscription.cs +347 -0
- package/.morph/framework/templates/saas/tenant.cs +338 -0
- package/.morph/framework/templates/state.template.json +17 -0
- package/.morph/framework/templates/ui/FluentDesignTheme.cs +149 -0
- package/.morph/framework/templates/ui/MudTheme.cs +281 -0
- package/.morph/framework/templates/ui/design-system.css +226 -0
- package/.morph/logs/tool-failures.log +17 -0
- package/.morph/memory/pre-compact-2026-02-24T17-43-30-049Z.json +16 -0
- package/.morph/plans/eager-watching-bunny.md +105 -0
- package/.morph/plans/temporal-seeking-nebula.md +45 -0
- package/.morph/state.json +48 -0
- package/CLAUDE.md +1 -1
- package/README.md +2 -2
- package/bin/morph-spec.js +0 -9
- package/framework/CLAUDE.md +1 -1
- package/framework/hooks/README.md +10 -6
- package/framework/hooks/claude-code/notification/approval-reminder.js +2 -0
- package/framework/hooks/claude-code/post-tool-use/dispatch.js +1 -1
- package/framework/hooks/claude-code/stop/validate-completion.js +1 -1
- package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +1 -1
- package/package.json +1 -1
- package/src/commands/project/init.js +15 -42
- package/src/commands/project/update.js +22 -37
- package/src/lib/installers/mcp-installer.js +18 -3
- package/src/utils/hooks-installer.js +5 -15
- package/src/commands/project/detect.js +0 -114
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Plan: Fix Statusline Not Being Installed
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
|
|
5
|
+
`morph-spec init` is supposed to install the global statusline to `~/.claude/` so
|
|
6
|
+
it appears in every Claude Code session. Two bugs exist:
|
|
7
|
+
|
|
8
|
+
1. **`update.js` never calls `installGlobalStatusline`** — running `morph-spec update`
|
|
9
|
+
leaves the statusline missing or stale, and there is no path for existing users to
|
|
10
|
+
get it without running `init` from scratch.
|
|
11
|
+
2. **No success confirmation in `init.js` output** — after a successful installation the
|
|
12
|
+
"Files installed:" list never mentions `~/.claude/statusline.sh`, so users assume
|
|
13
|
+
it was skipped (especially since failures are silently swallowed by a bare `catch {}`).
|
|
14
|
+
|
|
15
|
+
Root cause confirmed by: reading `update.js` (no `installGlobalStatusline` import or call)
|
|
16
|
+
and `init.js` lines 462–505 (success block omits statusline entry). Tests for
|
|
17
|
+
`installGlobalStatusline` in isolation pass; there is no integration test covering the
|
|
18
|
+
init/update flow.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Critical Files
|
|
23
|
+
|
|
24
|
+
| File | Change |
|
|
25
|
+
|------|--------|
|
|
26
|
+
| `src/commands/project/update.js` | Add `installGlobalStatusline` import + call |
|
|
27
|
+
| `src/commands/project/init.js` | Add `✓ ~/.claude/statusline.sh` to success output |
|
|
28
|
+
| `test/hooks/hooks-installer.test.js` | Already has good coverage — no change needed |
|
|
29
|
+
| `test/commands/init.test.js` | Add `statusline-installation` describe suite |
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Implementation Steps
|
|
34
|
+
|
|
35
|
+
### 1. `update.js` — Add statusline installation
|
|
36
|
+
|
|
37
|
+
**File:** `src/commands/project/update.js`
|
|
38
|
+
|
|
39
|
+
**Import change** (line 27 — extend existing destructure):
|
|
40
|
+
```js
|
|
41
|
+
import { installClaudeHooks, installGlobalStatusline } from '../../utils/claude-settings-manager.js';
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Call** — insert after the CLAUDE.md sync block (after line 280, before "Update Claude
|
|
45
|
+
Code hooks" at line 282):
|
|
46
|
+
```js
|
|
47
|
+
// Sync statusline globally to ~/.claude/
|
|
48
|
+
updateSpinner.text = 'Syncing statusline to ~/.claude/...';
|
|
49
|
+
const HOOKS_SRC = join(__dirname, '..', '..', '..', 'framework', 'hooks', 'claude-code');
|
|
50
|
+
try {
|
|
51
|
+
await installGlobalStatusline(HOOKS_SRC);
|
|
52
|
+
} catch {
|
|
53
|
+
// Non-critical: global dir may not be writable in all environments
|
|
54
|
+
logger.dim(' ⚠ Could not install statusline globally (non-critical)');
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Success output** — add line after `.claude/CLAUDE.md` entry (around line 324):
|
|
59
|
+
```js
|
|
60
|
+
logger.dim(' ✓ ~/.claude/statusline.sh (global statusline synced)');
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Note: `update.js` already uses `__dirname` (defined at line 6 via `fileURLToPath`),
|
|
64
|
+
so use `__dirname` instead of `import.meta.dirname` to stay consistent with the file.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### 2. `init.js` — Add statusline to success output
|
|
69
|
+
|
|
70
|
+
**File:** `src/commands/project/init.js`
|
|
71
|
+
|
|
72
|
+
After line 505 (`logger.dim(' ✓ .claude/agents/...')`), add:
|
|
73
|
+
```js
|
|
74
|
+
logger.dim(' ✓ ~/.claude/statusline.sh (global statusline installed)');
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
This line is unconditional — the installation is always attempted and the message
|
|
78
|
+
reflects the intent (mirrors how skills/agents are always listed even without a flag).
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
### 3. `test/commands/init.test.js` — Add statusline integration test suite
|
|
83
|
+
|
|
84
|
+
Add a new `describe('statusline-installation')` block that:
|
|
85
|
+
- Calls `installGlobalStatusline` directly with a `globalClaudeDirOverride` temp dir
|
|
86
|
+
and the real `framework/hooks/claude-code` source path
|
|
87
|
+
- Asserts `statusline.sh` and `statusline.py` were copied
|
|
88
|
+
- Asserts `settings.json` has a `statusLine` key pointing to `statusline.sh`
|
|
89
|
+
|
|
90
|
+
This mirrors the pattern used by the `rules-installation` suite.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Verification
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Run full test suite — must stay green (678+ pass, 0 fail)
|
|
98
|
+
node --test --test-concurrency=1
|
|
99
|
+
|
|
100
|
+
# Smoke test update path
|
|
101
|
+
node bin/morph-spec.js update --skip-detection --skip-mcp 2>&1 | grep -i statusline
|
|
102
|
+
|
|
103
|
+
# Manually verify ~/.claude/statusline.sh exists and settings.json has statusLine key
|
|
104
|
+
node -e "const s = require('fs').readFileSync(require('os').homedir()+'/.claude/settings.json','utf8'); console.log(JSON.parse(s).statusLine)"
|
|
105
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Plan: Remove `detect` command and fix `init` for PowerShell execution
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
|
|
5
|
+
`morph-spec init` is run from PowerShell (not inside Claude Code), so `detectClaudeCode()` always returns false, making step 13 a dead code branch that shows a confusing warning. `morph-spec detect` is registered but provides no additional value beyond what `init` already does with `detectProject()`. `--wizard` is referenced in messages but was never registered as a CLI option. This plan removes the dead code and makes `init` self-sufficient.
|
|
6
|
+
|
|
7
|
+
## What changes
|
|
8
|
+
|
|
9
|
+
### 1. Delete `src/commands/project/detect.js`
|
|
10
|
+
The command is obsolete — its functionality (stack/arch detection + saving to `.morph/project/context/`) is superseded by the `detectProject()` call already inside `init` at step 11c.
|
|
11
|
+
|
|
12
|
+
### 2. `bin/morph-spec.js`
|
|
13
|
+
- Remove `import { detectCommand }` (line 14)
|
|
14
|
+
- Remove the `.command('detect')` block (lines 131–136)
|
|
15
|
+
|
|
16
|
+
### 3. `src/commands/project/init.js`
|
|
17
|
+
- Remove imports: `AutoContextOrchestrator` (line 21), `detectClaudeCode` (line 22)
|
|
18
|
+
- **Remove step 13 entirely** (lines 509–540) — the entire `if (!options.skipDetection && detectClaudeCode())` / `else if` / `else` block
|
|
19
|
+
- Fix context README.md template (line 110): remove `Run \`morph-spec detect\`` sentence, replace with `Edit this file to describe your project context.`
|
|
20
|
+
- Fix Next Steps (line 470): remove `logger.step(1, 'Run detection: morph-spec detect')`, renumber remaining steps (step 1 → "Review .morph/config/config.json", step 2 → "Open project in VS Code with Claude Code", step 3 → "Start your first feature:")
|
|
21
|
+
|
|
22
|
+
### 4. `src/commands/project/update.js`
|
|
23
|
+
- Remove imports: `AutoContextOrchestrator`, `detectClaudeCode` (lines ~3–4 in that file)
|
|
24
|
+
- Remove the `if (!options.skipDetection && detectClaudeCode())` / `else if` / `else` block (lines 331–363)
|
|
25
|
+
|
|
26
|
+
## Files to modify
|
|
27
|
+
- `bin/morph-spec.js`
|
|
28
|
+
- `src/commands/project/init.js`
|
|
29
|
+
- `src/commands/project/update.js`
|
|
30
|
+
|
|
31
|
+
## Files to delete
|
|
32
|
+
- `src/commands/project/detect.js`
|
|
33
|
+
|
|
34
|
+
## Files NOT changed
|
|
35
|
+
- `test/integration/wizard-fallback.test.js` — tests `mapAnswersToConfig()` from `wizard-questions.js`, unrelated to detect command; still passes
|
|
36
|
+
- `test/commands/init.test.js` — no references to detect/wizard/detectClaudeCode; unaffected
|
|
37
|
+
- `src/core/orchestrator.js`, `src/ui/wizard-questions.js`, `src/llm/environment-detector.js` — left in place (may be used elsewhere); just remove imports/usage from init+update
|
|
38
|
+
- `src/lib/detectors/index.js` + `detectProject()` — **kept** in init (step 11c); this is the static file-based stack detection that works without Claude Code
|
|
39
|
+
|
|
40
|
+
## Verification
|
|
41
|
+
1. `node bin/morph-spec.js --help` — `detect` command should no longer appear
|
|
42
|
+
2. `node bin/morph-spec.js init --help` — no `--skip-detection` or `--wizard` references
|
|
43
|
+
3. `node bin/morph-spec.js update --help` — same
|
|
44
|
+
4. Run test suite: `npm test` — should still pass 678 tests (no tests reference detect/wizard in init.test.js)
|
|
45
|
+
5. Manual: run `morph-spec init` from PowerShell in a test project — should complete without the "Claude Code not detected" warning
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "4.0.0",
|
|
3
|
+
"features": {
|
|
4
|
+
"override-feature": {
|
|
5
|
+
"status": "in_progress",
|
|
6
|
+
"phase": "implement",
|
|
7
|
+
"tasks": {
|
|
8
|
+
"total": 20,
|
|
9
|
+
"completed": 30
|
|
10
|
+
},
|
|
11
|
+
"checkpoints": [
|
|
12
|
+
{
|
|
13
|
+
"passed": true
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"passed": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"passed": false
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"passed": false
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"passed": false
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"passed": false
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"passed": false
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"passed": false
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"passed": false
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"passed": false
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"trustConfig": {}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"threads": {},
|
|
47
|
+
"metadata": {}
|
|
48
|
+
}
|
package/CLAUDE.md
CHANGED
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
proposal → setup → [uiux] → design → clarify → tasks → implement → [sync]
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
Use `morph-spec
|
|
59
|
+
Use `morph-spec status {feature}` to see current phase and pending approval gates.
|
|
60
60
|
|
|
61
61
|
---
|
|
62
62
|
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> Spec-driven development framework for multi-stack projects. Turns feature requests into implementation-ready code through structured, AI-orchestrated phases.
|
|
4
4
|
|
|
5
5
|
**Package:** `@polymorphism-tech/morph-spec`
|
|
6
|
-
**Version:** 4.7.
|
|
6
|
+
**Version:** 4.7.2
|
|
7
7
|
**Requires:** Node.js 18+, Claude Code
|
|
8
8
|
|
|
9
9
|
---
|
|
@@ -282,7 +282,7 @@ Path-scoped rules are installed to `.claude/rules/` and activate automatically b
|
|
|
282
282
|
| `morph-workflow.md` | Always active — spec-first mandate, phase commands |
|
|
283
283
|
| `csharp-standards.md` | `**/*.cs`, `**/*.csproj` |
|
|
284
284
|
| `frontend-standards.md` | `**/*.razor`, `**/*.tsx`, `**/*.ts`, `**/*.css` |
|
|
285
|
-
| `testing-standards.md` | `tests
|
|
285
|
+
| `testing-standards.md` | `tests/`**, `**/*.test.*`, `**/*.spec.*`, `**/*Tests.cs` |
|
|
286
286
|
| `infrastructure-standards.md` | `**/*.bicep`, `**/Dockerfile`, `**/pipelines/**` |
|
|
287
287
|
|
|
288
288
|
|
package/bin/morph-spec.js
CHANGED
|
@@ -11,7 +11,6 @@ import { initCommand } from '../src/commands/project/init.js';
|
|
|
11
11
|
import { updateCommand } from '../src/commands/project/update.js';
|
|
12
12
|
import { updateAgentsCommand } from '../src/commands/project/update-agents.js';
|
|
13
13
|
import { doctorCommand } from '../src/commands/project/doctor.js';
|
|
14
|
-
import { detectCommand } from '../src/commands/project/detect.js';
|
|
15
14
|
|
|
16
15
|
import { syncCommand } from '../src/commands/project/sync.js';
|
|
17
16
|
import { statusCommand } from '../src/commands/project/status.js';
|
|
@@ -127,14 +126,6 @@ program
|
|
|
127
126
|
.option('--reset', 'Remove morph-managed entries from .claude/settings.local.json')
|
|
128
127
|
.action(doctorCommand);
|
|
129
128
|
|
|
130
|
-
program
|
|
131
|
-
.command('detect')
|
|
132
|
-
.description('Detect project stack, architecture, and patterns')
|
|
133
|
-
.option('-p, --path <path>', 'Project path (default: current directory)')
|
|
134
|
-
.option('-v, --verbose', 'Show detailed detection results')
|
|
135
|
-
.option('--no-save', 'Do not save results to .morph/project/')
|
|
136
|
-
.action(detectCommand);
|
|
137
|
-
|
|
138
129
|
program
|
|
139
130
|
.command('sync')
|
|
140
131
|
.description('Sync standards from feature decisions')
|
package/framework/CLAUDE.md
CHANGED
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
proposal → setup → [uiux] → design → clarify → tasks → implement → [sync]
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
Use `morph-spec
|
|
59
|
+
Use `morph-spec status {feature}` to see current phase and pending approval gates.
|
|
60
60
|
|
|
61
61
|
---
|
|
62
62
|
|
|
@@ -47,13 +47,13 @@ framework/hooks/
|
|
|
47
47
|
|-------|------|------|---------|
|
|
48
48
|
| **SessionStart** | inject-morph-context.js | Inject context | Shows active feature, phase, pending approvals |
|
|
49
49
|
| **UserPromptSubmit** | enrich-prompt.js | Inject context | Warns about wrong-phase work, injects commands |
|
|
50
|
-
| **PreToolUse** (Write\|Edit) |
|
|
50
|
+
| **PreToolUse** (Write\|Edit) | _(native permissions.deny)_ | Block | Blocks edits to state.json and .morph/framework/ |
|
|
51
51
|
| **PreToolUse** (Write\|Edit) | protect-spec-files.js | Block | Blocks edits to spec files after approval |
|
|
52
52
|
| **PreToolUse** (Write\|Edit) | enforce-phase-writes.js | Block | Ensures writes go to current phase directory |
|
|
53
53
|
| **PreToolUse** (Bash) | _(prompt-type inline guard)_ | Block | Blocks `rm -rf .morph/` and direct state edits via Claude's reasoning |
|
|
54
|
-
| **PostToolUse** (Write) | track-output-creation.js | Auto-state | Marks outputs as created when files are written |
|
|
55
54
|
| **PostToolUse** (Bash) | dispatch.js | Dispatch | Triggers checkpoints on task completion |
|
|
56
|
-
| **
|
|
55
|
+
| **PostToolUseFailure** | handle-tool-failure.js | Logging | Appends structured JSON to .morph/logs/tool-failures.log |
|
|
56
|
+
| **Stop** | validate-completion.js | Advisory | Warns about incomplete tasks/missing outputs/pending gates |
|
|
57
57
|
| **PreCompact** | save-morph-context.js | Snapshot | Saves state to .morph/memory/ before compaction |
|
|
58
58
|
| **Notification** | approval-reminder.js | Advisory | Reminds about pending approval gates |
|
|
59
59
|
|
|
@@ -69,6 +69,10 @@ framework/hooks/
|
|
|
69
69
|
|
|
70
70
|
Hooks are automatically installed by `morph-spec init` and updated by `morph-spec update`.
|
|
71
71
|
|
|
72
|
+
During init/update, the entire `framework/hooks/` directory is copied to `.morph/framework/hooks/`.
|
|
73
|
+
Hook commands in `.claude/settings.local.json` reference `$CLAUDE_PROJECT_DIR/.morph/framework/hooks/`
|
|
74
|
+
so they work correctly in any project regardless of how morph-spec was installed.
|
|
75
|
+
|
|
72
76
|
The installer writes to `.claude/settings.local.json`:
|
|
73
77
|
|
|
74
78
|
```json
|
|
@@ -122,10 +126,10 @@ Claude calls Write/Edit tool
|
|
|
122
126
|
↓
|
|
123
127
|
Claude Code sends JSON to stdin: { tool_input: { file_path: "..." } }
|
|
124
128
|
↓
|
|
125
|
-
|
|
129
|
+
[native permissions.deny]
|
|
126
130
|
├── Is .morph/state.json? → BLOCK (use CLI)
|
|
127
131
|
├── Is .morph/framework/**? → BLOCK (read-only)
|
|
128
|
-
└── Other →
|
|
132
|
+
└── Other → continue
|
|
129
133
|
↓
|
|
130
134
|
protect-spec-files.js
|
|
131
135
|
├── Is in .morph/features/{feature}/?
|
|
@@ -198,4 +202,4 @@ morph-spec doctor --reset
|
|
|
198
202
|
|
|
199
203
|
---
|
|
200
204
|
|
|
201
|
-
*MORPH-SPEC v4.
|
|
205
|
+
*MORPH-SPEC v4.5.0 — Hooks Architecture v2.5*
|
|
@@ -46,7 +46,7 @@ function dispatch(command) {
|
|
|
46
46
|
const completed = (feature.tasks.completed || 0) + 1; // +1 because task-done hasn't executed yet
|
|
47
47
|
if (completed > 0 && completed % 3 === 0) {
|
|
48
48
|
const checkpointNum = Math.floor(completed / 3);
|
|
49
|
-
run(`
|
|
49
|
+
run(`morph-spec checkpoint-save ${featureName} --note "Auto-checkpoint #${checkpointNum} at task ${completed}"`);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
} catch {
|
|
@@ -58,7 +58,7 @@ try {
|
|
|
58
58
|
// Check pending approval gates
|
|
59
59
|
if (feature.approvalGates) {
|
|
60
60
|
const pendingGates = Object.entries(feature.approvalGates)
|
|
61
|
-
.filter(([, gate]) => !gate.approved && gate.timestamp
|
|
61
|
+
.filter(([, gate]) => !gate.approved && !gate.timestamp)
|
|
62
62
|
.map(([name]) => name);
|
|
63
63
|
|
|
64
64
|
// Only warn about gates relevant to current/past phases
|
|
@@ -24,7 +24,7 @@ try {
|
|
|
24
24
|
const payload = await readStdin();
|
|
25
25
|
if (!payload) pass();
|
|
26
26
|
|
|
27
|
-
const userPrompt = payload?.user_prompt || payload?.content || '';
|
|
27
|
+
const userPrompt = payload?.prompt || payload?.user_prompt || payload?.content || '';
|
|
28
28
|
if (!userPrompt || userPrompt.length < 3) pass();
|
|
29
29
|
|
|
30
30
|
const promptLower = userPrompt.toLowerCase();
|
package/package.json
CHANGED
|
@@ -18,8 +18,6 @@ import { saveProjectMorphVersion, getInstalledCLIVersion } from '../../utils/ver
|
|
|
18
18
|
import { installClaudeHooks, installGlobalStatusline } from '../../utils/claude-settings-manager.js';
|
|
19
19
|
import { installSkills } from '../../utils/skills-installer.js';
|
|
20
20
|
import { installAgents, installDomainAgents } from '../../utils/agents-installer.js';
|
|
21
|
-
import { AutoContextOrchestrator } from '../../core/orchestrator.js';
|
|
22
|
-
import { detectClaudeCode } from '../../llm/environment-detector.js';
|
|
23
21
|
import inquirer from 'inquirer';
|
|
24
22
|
import { detectProject } from '../../lib/detectors/index.js';
|
|
25
23
|
import { detectClaudeConfig, mapMcpsToPhases, formatConfigSummary } from '../../lib/detectors/claude-config-detector.js';
|
|
@@ -102,11 +100,11 @@ export async function initCommand(options) {
|
|
|
102
100
|
|
|
103
101
|
## Overview
|
|
104
102
|
|
|
105
|
-
This file
|
|
103
|
+
This file describes your project context for MORPH-SPEC agents.
|
|
106
104
|
|
|
107
105
|
## Stack
|
|
108
106
|
|
|
109
|
-
|
|
107
|
+
Edit this file to describe your project context.
|
|
110
108
|
|
|
111
109
|
## Technologies
|
|
112
110
|
|
|
@@ -139,6 +137,14 @@ Run \`morph-spec detect\` to analyze your project.
|
|
|
139
137
|
logger.dim(' ✓ Copied framework standards: core/, backend/, frontend/, infrastructure/');
|
|
140
138
|
}
|
|
141
139
|
|
|
140
|
+
// 6c. Copy hooks to .morph/framework/hooks/ (required for hook commands at runtime)
|
|
141
|
+
spinner.text = 'Copying hooks...';
|
|
142
|
+
const hooksSrc = join(import.meta.dirname, '..', '..', '..', 'framework', 'hooks');
|
|
143
|
+
const hooksDest = join(frameworkDestDir, 'hooks');
|
|
144
|
+
if (await pathExists(hooksSrc)) {
|
|
145
|
+
await copyDirectory(hooksSrc, hooksDest);
|
|
146
|
+
}
|
|
147
|
+
|
|
142
148
|
// 7. Copy agents.json (sourced from framework/ — canonical single source of truth)
|
|
143
149
|
spinner.text = 'Copying agents configuration...';
|
|
144
150
|
const agentsSrc = join(import.meta.dirname, '..', '..', '..', 'framework', 'agents.json');
|
|
@@ -467,10 +473,9 @@ Run \`morph-spec detect\` to analyze your project.
|
|
|
467
473
|
logger.blank();
|
|
468
474
|
logger.header('Next Steps');
|
|
469
475
|
|
|
470
|
-
logger.step(1, '
|
|
471
|
-
logger.step(2, '
|
|
472
|
-
logger.step(3, '
|
|
473
|
-
logger.step(4, 'Start your first feature:');
|
|
476
|
+
logger.step(1, 'Review .morph/config/config.json');
|
|
477
|
+
logger.step(2, 'Open project in VS Code with Claude Code');
|
|
478
|
+
logger.step(3, 'Start your first feature:');
|
|
474
479
|
logger.blank();
|
|
475
480
|
logger.box([
|
|
476
481
|
'Ask Claude Code to implement a feature'
|
|
@@ -480,7 +485,7 @@ Run \`morph-spec detect\` to analyze your project.
|
|
|
480
485
|
logger.info('Files installed:');
|
|
481
486
|
logger.dim(` ✓ CLAUDE.md`);
|
|
482
487
|
logger.dim(` ✓ .morph/config/ (config.json)`);
|
|
483
|
-
logger.dim(` ✓ .morph/framework/ (agents.json, standards/, templates/)`);
|
|
488
|
+
logger.dim(` ✓ .morph/framework/ (agents.json, standards/, templates/, hooks/)`);
|
|
484
489
|
logger.dim(` ✓ .morph/context/ (project context)`);
|
|
485
490
|
logger.dim(` ✓ .morph/features/ (feature outputs)`);
|
|
486
491
|
if (commandsCopied) {
|
|
@@ -503,42 +508,10 @@ Run \`morph-spec detect\` to analyze your project.
|
|
|
503
508
|
|
|
504
509
|
logger.dim(' ✓ .claude/skills/ (installed as skill directories)');
|
|
505
510
|
logger.dim(' ✓ .claude/agents/ (native subagents installed)');
|
|
511
|
+
logger.dim(' ✓ ~/.claude/statusline.sh (global statusline installed)');
|
|
506
512
|
|
|
507
513
|
logger.blank();
|
|
508
514
|
|
|
509
|
-
// 13. LLM-based auto-detect project context (if Claude Code is available and not --skip-detection)
|
|
510
|
-
if (!options.skipDetection && detectClaudeCode()) {
|
|
511
|
-
logger.blank();
|
|
512
|
-
logger.header('Auto-Detecting Project Context');
|
|
513
|
-
logger.dim('Using Claude Code LLM to analyze your project...');
|
|
514
|
-
logger.blank();
|
|
515
|
-
|
|
516
|
-
try {
|
|
517
|
-
const orchestrator = new AutoContextOrchestrator();
|
|
518
|
-
const result = await orchestrator.execute(targetPath, {
|
|
519
|
-
skipReview: false,
|
|
520
|
-
fallbackOnError: true,
|
|
521
|
-
wizardMode: options.wizard || false
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
if (result.success) {
|
|
525
|
-
logger.success('Project context detected and saved to .morph/project.md');
|
|
526
|
-
} else {
|
|
527
|
-
logger.warn('Auto-detection incomplete. Run "morph-spec update" to retry.');
|
|
528
|
-
}
|
|
529
|
-
} catch (error) {
|
|
530
|
-
logger.warn(`Auto-detection failed: ${error.message}`);
|
|
531
|
-
logger.dim('You can run "morph-spec update" later to re-analyze your project.');
|
|
532
|
-
}
|
|
533
|
-
} else if (options.skipDetection) {
|
|
534
|
-
logger.dim('\nSkipped auto-detection (--skip-detection flag)');
|
|
535
|
-
logger.dim('Run "morph-spec update" later to analyze your project.');
|
|
536
|
-
} else {
|
|
537
|
-
logger.warn('\n⚠️ Claude Code not detected');
|
|
538
|
-
logger.dim('Auto-detection requires Claude Code CLI.');
|
|
539
|
-
logger.dim('Run "morph-spec update --wizard" to configure manually.');
|
|
540
|
-
}
|
|
541
|
-
|
|
542
515
|
// Suggest tutorial for first-time users
|
|
543
516
|
if (integrationsCreated) {
|
|
544
517
|
logger.blank();
|
|
@@ -24,11 +24,9 @@ import {
|
|
|
24
24
|
getUpdateInstructions,
|
|
25
25
|
detectInstallMethod
|
|
26
26
|
} from '../../utils/version-checker.js';
|
|
27
|
-
import { installClaudeHooks } from '../../utils/claude-settings-manager.js';
|
|
27
|
+
import { installClaudeHooks, installGlobalStatusline } from '../../utils/claude-settings-manager.js';
|
|
28
28
|
import { installSkills } from '../../utils/skills-installer.js';
|
|
29
29
|
import { installAgents, installDomainAgents } from '../../utils/agents-installer.js';
|
|
30
|
-
import { AutoContextOrchestrator } from '../../core/orchestrator.js';
|
|
31
|
-
import { detectClaudeCode } from '../../llm/environment-detector.js';
|
|
32
30
|
|
|
33
31
|
/**
|
|
34
32
|
* Backup user's config.json before cleaning
|
|
@@ -57,6 +55,7 @@ async function cleanFrameworkDirs(morphPath, targetPath) {
|
|
|
57
55
|
const dirsToClean = [
|
|
58
56
|
join(morphPath, 'framework', 'templates'),
|
|
59
57
|
join(morphPath, 'framework', 'standards'),
|
|
58
|
+
join(morphPath, 'framework', 'hooks'),
|
|
60
59
|
join(morphPath, 'config'),
|
|
61
60
|
join(targetPath, '.claude')
|
|
62
61
|
];
|
|
@@ -208,6 +207,14 @@ export async function updateCommand(options) {
|
|
|
208
207
|
await copyDirectory(standardsSrc, standardsDest);
|
|
209
208
|
}
|
|
210
209
|
|
|
210
|
+
// Update hooks (runtime hook scripts under .morph/framework/hooks/)
|
|
211
|
+
updateSpinner.text = 'Updating hooks...';
|
|
212
|
+
const hooksSrc = join(__dirname, '..', '..', '..', 'framework', 'hooks');
|
|
213
|
+
const hooksDest = join(morphPath, 'framework', 'hooks');
|
|
214
|
+
if (await pathExists(hooksSrc)) {
|
|
215
|
+
await copyDirectory(hooksSrc, hooksDest);
|
|
216
|
+
}
|
|
217
|
+
|
|
211
218
|
// Update agents.json (sourced from framework/ — canonical single source of truth)
|
|
212
219
|
updateSpinner.text = 'Updating agents configuration...';
|
|
213
220
|
const agentsSrc = join(__dirname, '..', '..', '..', 'framework', 'agents.json');
|
|
@@ -279,6 +286,16 @@ export async function updateCommand(options) {
|
|
|
279
286
|
await copyFile(runtimeSrc, runtimeDest);
|
|
280
287
|
}
|
|
281
288
|
|
|
289
|
+
// Sync statusline globally to ~/.claude/
|
|
290
|
+
updateSpinner.text = 'Syncing statusline to ~/.claude/...';
|
|
291
|
+
const HOOKS_SRC = join(__dirname, '..', '..', '..', 'framework', 'hooks', 'claude-code');
|
|
292
|
+
try {
|
|
293
|
+
await installGlobalStatusline(HOOKS_SRC);
|
|
294
|
+
} catch {
|
|
295
|
+
// Non-critical: global dir may not be writable in all environments
|
|
296
|
+
logger.dim(' ⚠ Could not install statusline globally (non-critical)');
|
|
297
|
+
}
|
|
298
|
+
|
|
282
299
|
// Update Claude Code hooks in .claude/settings.local.json
|
|
283
300
|
updateSpinner.text = 'Updating Claude Code hooks...';
|
|
284
301
|
const hooksResult = await installClaudeHooks(targetPath);
|
|
@@ -314,6 +331,7 @@ export async function updateCommand(options) {
|
|
|
314
331
|
logger.info('Updated files:');
|
|
315
332
|
if (updateTemplates) logger.dim(' ✓ .morph/framework/templates/');
|
|
316
333
|
if (updateStandards) logger.dim(' ✓ .morph/framework/standards/');
|
|
334
|
+
logger.dim(' ✓ .morph/framework/hooks/');
|
|
317
335
|
logger.dim(' ✓ .morph/framework/agents.json');
|
|
318
336
|
if (commandsCopied) logger.dim(' ✓ .claude/commands/');
|
|
319
337
|
|
|
@@ -322,46 +340,13 @@ export async function updateCommand(options) {
|
|
|
322
340
|
logger.dim(' ✓ .claude/agents/ (native subagents refreshed)');
|
|
323
341
|
logger.dim(' ✓ .claude/rules/ (path-scoped rules synced)');
|
|
324
342
|
logger.dim(' ✓ .claude/CLAUDE.md (runtime quick reference)');
|
|
343
|
+
logger.dim(' ✓ ~/.claude/statusline.sh (global statusline synced)');
|
|
325
344
|
logger.dim(' ✓ CLAUDE.md');
|
|
326
345
|
logger.blank();
|
|
327
346
|
logger.info('Your config.json was preserved.');
|
|
328
347
|
logger.dim('Review the updated files for any new features.');
|
|
329
348
|
logger.blank();
|
|
330
349
|
|
|
331
|
-
// Re-analyze project context (unless --skip-detection)
|
|
332
|
-
if (!options.skipDetection && detectClaudeCode()) {
|
|
333
|
-
logger.header('Re-Analyzing Project Context');
|
|
334
|
-
logger.dim('Using Claude Code LLM to update project detection...');
|
|
335
|
-
logger.blank();
|
|
336
|
-
|
|
337
|
-
try {
|
|
338
|
-
const orchestrator = new AutoContextOrchestrator();
|
|
339
|
-
const result = await orchestrator.execute(targetPath, {
|
|
340
|
-
skipReview: false,
|
|
341
|
-
fallbackOnError: true,
|
|
342
|
-
wizardMode: options.wizard || false
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
if (result.success) {
|
|
346
|
-
logger.success('Project context re-analyzed and updated');
|
|
347
|
-
logger.dim(' ✓ .morph/project.md updated with latest detection');
|
|
348
|
-
logger.dim(' ✓ .morph/config/config.json updated with stack info');
|
|
349
|
-
} else {
|
|
350
|
-
logger.warn('Context re-analysis incomplete');
|
|
351
|
-
}
|
|
352
|
-
} catch (error) {
|
|
353
|
-
logger.warn(`Auto-detection failed: ${error.message}`);
|
|
354
|
-
logger.dim('Your existing config.json was preserved.');
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
logger.blank();
|
|
358
|
-
} else if (options.skipDetection) {
|
|
359
|
-
logger.dim('Skipped auto-detection (--skip-detection flag)');
|
|
360
|
-
} else {
|
|
361
|
-
logger.warn('⚠️ Claude Code not detected - skipping auto-detection');
|
|
362
|
-
logger.dim('Run with --wizard to configure manually.');
|
|
363
|
-
}
|
|
364
|
-
|
|
365
350
|
} catch (error) {
|
|
366
351
|
updateSpinner.fail('Update failed');
|
|
367
352
|
logger.error(error.message);
|
|
@@ -96,6 +96,21 @@ export function checkPrerequisites(mcpEntry) {
|
|
|
96
96
|
return results;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Patch MCP config for the current platform.
|
|
101
|
+
* On Windows, npx must be invoked via `cmd /C` to avoid ENOENT errors.
|
|
102
|
+
* @param {Object} config - MCP server config { command, args, env? }
|
|
103
|
+
* @returns {Object} Patched config (new object, original unmodified)
|
|
104
|
+
*/
|
|
105
|
+
export function patchConfigForPlatform(config) {
|
|
106
|
+
if (process.platform !== 'win32' || config.command !== 'npx') return config;
|
|
107
|
+
return {
|
|
108
|
+
...config,
|
|
109
|
+
command: 'cmd',
|
|
110
|
+
args: ['/C', 'npx', ...(config.args || [])]
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
99
114
|
/**
|
|
100
115
|
* Install auto-installable MCPs (no credentials, no prerequisites)
|
|
101
116
|
* @param {string} targetPath - Project root directory
|
|
@@ -106,12 +121,12 @@ export async function installAutoMcps(targetPath, mcpsToInstall) {
|
|
|
106
121
|
const servers = {};
|
|
107
122
|
|
|
108
123
|
for (const [name, entry] of Object.entries(mcpsToInstall)) {
|
|
109
|
-
|
|
124
|
+
let config = { ...entry.install.config };
|
|
110
125
|
// Only include env if it has actual values
|
|
111
126
|
if (config.env && Object.values(config.env).every(v => !v)) {
|
|
112
127
|
delete config.env;
|
|
113
128
|
}
|
|
114
|
-
servers[name] = config;
|
|
129
|
+
servers[name] = patchConfigForPlatform(config);
|
|
115
130
|
}
|
|
116
131
|
|
|
117
132
|
return installMcpServers(targetPath, servers);
|
|
@@ -126,7 +141,7 @@ export async function installAutoMcps(targetPath, mcpsToInstall) {
|
|
|
126
141
|
* @returns {Promise<Object>} Result from installMcpServers
|
|
127
142
|
*/
|
|
128
143
|
export async function installMcpWithCredentials(targetPath, name, mcpEntry, credentialValues) {
|
|
129
|
-
const config = { ...mcpEntry.install.config };
|
|
144
|
+
const config = patchConfigForPlatform({ ...mcpEntry.install.config });
|
|
130
145
|
config.env = { ...config.env, ...credentialValues };
|
|
131
146
|
return installMcpServers(targetPath, { [name]: config });
|
|
132
147
|
}
|
|
@@ -14,7 +14,7 @@ import { existsSync, chmodSync } from 'fs';
|
|
|
14
14
|
import { homedir } from 'os';
|
|
15
15
|
|
|
16
16
|
/** Current hooks schema version — bump when hook definitions change */
|
|
17
|
-
const HOOKS_VERSION = '2.
|
|
17
|
+
const HOOKS_VERSION = '2.5.0';
|
|
18
18
|
|
|
19
19
|
/** Marker for old dispatch.js (v1) */
|
|
20
20
|
const OLD_DISPATCH_COMMAND = 'node framework/hooks/agent-teams/dispatch.js';
|
|
@@ -104,19 +104,8 @@ Otherwise respond: {"ok": true}`
|
|
|
104
104
|
event: 'Stop',
|
|
105
105
|
matcher: null,
|
|
106
106
|
hooks: [{
|
|
107
|
-
type: '
|
|
108
|
-
|
|
109
|
-
1. Read the file .morph/state.json to find features with status "in_progress".
|
|
110
|
-
2. For each in_progress feature, check if required output files for the current phase exist and are non-empty.
|
|
111
|
-
- proposal phase: .morph/features/{feature}/0-proposal/proposal.md
|
|
112
|
-
- design phase: .morph/features/{feature}/1-design/spec.md
|
|
113
|
-
- tasks phase: .morph/features/{feature}/3-tasks/tasks.md
|
|
114
|
-
- implement phase: check tasks.completed vs tasks.total from state.json
|
|
115
|
-
3. If all required outputs exist and tasks are complete, return {"ok": true}.
|
|
116
|
-
4. If any required output is missing or empty, return {"ok": false, "reason": "Missing output: <path>"}.
|
|
117
|
-
5. If state.json does not exist or no feature is in_progress, return {"ok": true}.
|
|
118
|
-
Do NOT modify any files. Read only.`,
|
|
119
|
-
timeout: 60
|
|
107
|
+
type: 'command',
|
|
108
|
+
command: 'node framework/hooks/claude-code/stop/validate-completion.js'
|
|
120
109
|
}]
|
|
121
110
|
},
|
|
122
111
|
|
|
@@ -209,9 +198,10 @@ export async function installClaudeHooks(targetPath) {
|
|
|
209
198
|
return agentHook;
|
|
210
199
|
}
|
|
211
200
|
// Command hooks: transform path to use $CLAUDE_PROJECT_DIR
|
|
201
|
+
// Hooks are copied to .morph/framework/hooks/ during `morph-spec init/update`
|
|
212
202
|
return {
|
|
213
203
|
type: h.type,
|
|
214
|
-
command: `node "$CLAUDE_PROJECT_DIR/framework/hooks/claude-code/${getHookSubpath(h.command)}"`,
|
|
204
|
+
command: `node "$CLAUDE_PROJECT_DIR/.morph/framework/hooks/claude-code/${getHookSubpath(h.command)}"`,
|
|
215
205
|
...(h.timeout !== undefined ? { timeout: h.timeout } : {})
|
|
216
206
|
};
|
|
217
207
|
});
|