moflo 4.8.10 → 4.8.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/browser/browser-agent.yaml +182 -0
- package/.claude/agents/core/coder.md +265 -265
- package/.claude/agents/core/planner.md +167 -167
- package/.claude/agents/core/researcher.md +189 -189
- package/.claude/agents/core/reviewer.md +325 -325
- package/.claude/agents/core/tester.md +318 -318
- package/.claude/agents/dual-mode/codex-coordinator.md +224 -224
- package/.claude/agents/dual-mode/codex-worker.md +211 -211
- package/.claude/agents/dual-mode/dual-orchestrator.md +291 -291
- package/.claude/agents/github/code-review-swarm.md +537 -537
- package/.claude/agents/github/github-modes.md +172 -172
- package/.claude/agents/github/issue-tracker.md +318 -318
- package/.claude/agents/github/multi-repo-swarm.md +552 -552
- package/.claude/agents/github/pr-manager.md +190 -190
- package/.claude/agents/github/project-board-sync.md +508 -508
- package/.claude/agents/github/release-manager.md +366 -366
- package/.claude/agents/github/release-swarm.md +582 -582
- package/.claude/agents/github/repo-architect.md +397 -397
- package/.claude/agents/github/swarm-issue.md +572 -572
- package/.claude/agents/github/swarm-pr.md +427 -427
- package/.claude/agents/github/sync-coordinator.md +451 -451
- package/.claude/agents/github/workflow-automation.md +634 -634
- package/.claude/agents/goal/code-goal-planner.md +445 -445
- package/.claude/agents/hive-mind/collective-intelligence-coordinator.md +129 -129
- package/.claude/agents/hive-mind/queen-coordinator.md +202 -202
- package/.claude/agents/hive-mind/scout-explorer.md +241 -241
- package/.claude/agents/hive-mind/swarm-memory-manager.md +192 -192
- package/.claude/agents/hive-mind/worker-specialist.md +216 -216
- package/.claude/agents/neural/safla-neural.md +73 -73
- package/.claude/agents/reasoning/goal-planner.md +72 -72
- package/.claude/agents/swarm/adaptive-coordinator.md +395 -395
- package/.claude/agents/swarm/hierarchical-coordinator.md +326 -326
- package/.claude/agents/swarm/mesh-coordinator.md +391 -391
- package/.claude/agents/templates/migration-plan.md +745 -745
- package/.claude/commands/agents/agent-spawning.md +28 -28
- package/.claude/commands/analysis/COMMAND_COMPLIANCE_REPORT.md +53 -53
- package/.claude/commands/analysis/bottleneck-detect.md +162 -162
- package/.claude/commands/analysis/performance-bottlenecks.md +58 -58
- package/.claude/commands/analysis/token-efficiency.md +44 -44
- package/.claude/commands/automation/auto-agent.md +122 -122
- package/.claude/commands/automation/self-healing.md +105 -105
- package/.claude/commands/automation/session-memory.md +89 -89
- package/.claude/commands/automation/smart-agents.md +72 -72
- package/.claude/commands/coordination/init.md +44 -44
- package/.claude/commands/coordination/orchestrate.md +43 -43
- package/.claude/commands/coordination/spawn.md +45 -45
- package/.claude/commands/coordination/swarm-init.md +85 -85
- package/.claude/commands/github/github-modes.md +146 -146
- package/.claude/commands/github/github-swarm.md +121 -121
- package/.claude/commands/github/issue-tracker.md +291 -291
- package/.claude/commands/github/pr-manager.md +169 -169
- package/.claude/commands/github/release-manager.md +337 -337
- package/.claude/commands/github/repo-architect.md +366 -366
- package/.claude/commands/github/sync-coordinator.md +300 -300
- package/.claude/commands/memory/neural.md +47 -47
- package/.claude/commands/monitoring/agents.md +44 -44
- package/.claude/commands/monitoring/status.md +46 -46
- package/.claude/commands/optimization/auto-topology.md +61 -61
- package/.claude/commands/optimization/parallel-execution.md +49 -49
- package/.claude/commands/sparc/analyzer.md +51 -51
- package/.claude/commands/sparc/architect.md +53 -53
- package/.claude/commands/sparc/ask.md +97 -97
- package/.claude/commands/sparc/batch-executor.md +54 -54
- package/.claude/commands/sparc/code.md +89 -89
- package/.claude/commands/sparc/coder.md +54 -54
- package/.claude/commands/sparc/debug.md +83 -83
- package/.claude/commands/sparc/debugger.md +54 -54
- package/.claude/commands/sparc/designer.md +53 -53
- package/.claude/commands/sparc/devops.md +109 -109
- package/.claude/commands/sparc/docs-writer.md +80 -80
- package/.claude/commands/sparc/documenter.md +54 -54
- package/.claude/commands/sparc/innovator.md +54 -54
- package/.claude/commands/sparc/integration.md +83 -83
- package/.claude/commands/sparc/mcp.md +117 -117
- package/.claude/commands/sparc/memory-manager.md +54 -54
- package/.claude/commands/sparc/optimizer.md +54 -54
- package/.claude/commands/sparc/orchestrator.md +131 -131
- package/.claude/commands/sparc/post-deployment-monitoring-mode.md +83 -83
- package/.claude/commands/sparc/refinement-optimization-mode.md +83 -83
- package/.claude/commands/sparc/researcher.md +54 -54
- package/.claude/commands/sparc/reviewer.md +54 -54
- package/.claude/commands/sparc/security-review.md +80 -80
- package/.claude/commands/sparc/sparc-modes.md +174 -174
- package/.claude/commands/sparc/sparc.md +111 -111
- package/.claude/commands/sparc/spec-pseudocode.md +80 -80
- package/.claude/commands/sparc/supabase-admin.md +348 -348
- package/.claude/commands/sparc/swarm-coordinator.md +54 -54
- package/.claude/commands/sparc/tdd.md +54 -54
- package/.claude/commands/sparc/tester.md +54 -54
- package/.claude/commands/sparc/tutorial.md +79 -79
- package/.claude/commands/sparc/workflow-manager.md +54 -54
- package/.claude/commands/sparc.md +166 -166
- package/.claude/commands/swarm/analysis.md +95 -95
- package/.claude/commands/swarm/development.md +96 -96
- package/.claude/commands/swarm/examples.md +168 -168
- package/.claude/commands/swarm/maintenance.md +102 -102
- package/.claude/commands/swarm/optimization.md +117 -117
- package/.claude/commands/swarm/research.md +136 -136
- package/.claude/commands/swarm/testing.md +131 -131
- package/.claude/commands/training/neural-patterns.md +73 -73
- package/.claude/commands/training/specialization.md +62 -62
- package/.claude/commands/workflows/development.md +77 -77
- package/.claude/commands/workflows/research.md +62 -62
- package/.claude/guidance/moflo-bootstrap.md +129 -0
- package/.claude/guidance/{agent-bootstrap.md → shipped/agent-bootstrap.md} +126 -126
- package/.claude/guidance/{guidance-memory-strategy.md → shipped/guidance-memory-strategy.md} +262 -262
- package/.claude/guidance/{memory-strategy.md → shipped/memory-strategy.md} +204 -204
- package/.claude/guidance/{moflo.md → shipped/moflo.md} +45 -31
- package/.claude/guidance/{task-swarm-integration.md → shipped/task-swarm-integration.md} +441 -348
- package/.claude/helpers/gate-hook.mjs +50 -0
- package/.claude/helpers/gate.cjs +138 -236
- package/.claude/helpers/hook-handler.cjs +64 -326
- package/.claude/helpers/post-commit +16 -0
- package/.claude/helpers/pre-commit +26 -0
- package/.claude/helpers/prompt-hook.mjs +72 -0
- package/.claude/scripts/build-embeddings.mjs +549 -0
- package/.claude/scripts/generate-code-map.mjs +697 -0
- package/.claude/scripts/hooks.mjs +656 -0
- package/.claude/scripts/index-guidance.mjs +893 -0
- package/.claude/scripts/index-tests.mjs +710 -0
- package/.claude/scripts/semantic-search.mjs +473 -0
- package/.claude/scripts/session-start-launcher.mjs +226 -0
- package/.claude/settings.json +351 -290
- package/.claude/settings.local.json +4 -3
- package/.claude/skills/browser/SKILL.md +204 -0
- package/.claude/skills/fl/SKILL.md +29 -23
- package/.claude/skills/flo/SKILL.md +29 -23
- package/.claude/skills/github-code-review/SKILL.md +4 -4
- package/.claude/skills/github-multi-repo/SKILL.md +8 -8
- package/.claude/skills/github-project-management/SKILL.md +6 -6
- package/.claude/skills/github-release-management/SKILL.md +12 -12
- package/.claude/skills/github-workflow-automation/SKILL.md +6 -6
- package/.claude/skills/hooks-automation/SKILL.md +1201 -1201
- package/.claude/skills/performance-analysis/SKILL.md +563 -563
- package/.claude/skills/sparc-methodology/SKILL.md +64 -64
- package/.claude/skills/swarm-advanced/SKILL.md +77 -77
- package/.claude/workflow-state.json +9 -0
- package/.claude-plugin/README.md +3 -3
- package/.claude-plugin/docs/PLUGIN_SUMMARY.md +3 -3
- package/.claude-plugin/docs/QUICKSTART.md +4 -4
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +3 -3
- package/.claude-plugin/scripts/install.sh +9 -9
- package/.claude-plugin/scripts/verify.sh +7 -7
- package/README.md +311 -116
- package/bin/gate-hook.mjs +50 -0
- package/bin/gate.cjs +138 -0
- package/bin/hook-handler.cjs +83 -0
- package/bin/hooks.mjs +72 -12
- package/bin/index-guidance.mjs +29 -35
- package/bin/index-tests.mjs +710 -0
- package/bin/lib/process-manager.mjs +243 -0
- package/bin/lib/registry-cleanup.cjs +41 -0
- package/bin/prompt-hook.mjs +72 -0
- package/bin/semantic-search.mjs +472 -440
- package/bin/session-start-launcher.mjs +81 -31
- package/bin/setup-project.mjs +65 -65
- package/package.json +4 -2
- package/src/@claude-flow/cli/README.md +1 -1
- package/src/@claude-flow/cli/bin/cli.js +175 -175
- package/src/@claude-flow/cli/dist/src/commands/doctor.js +1091 -736
- package/src/@claude-flow/cli/dist/src/commands/github.d.ts +12 -0
- package/src/@claude-flow/cli/dist/src/commands/github.js +505 -0
- package/src/@claude-flow/cli/dist/src/commands/hive-mind.js +90 -90
- package/src/@claude-flow/cli/dist/src/commands/index.d.ts +1 -0
- package/src/@claude-flow/cli/dist/src/commands/index.js +7 -0
- package/src/@claude-flow/cli/dist/src/config-adapter.js +1 -1
- package/src/@claude-flow/cli/dist/src/init/claudemd-generator.d.ts +29 -24
- package/src/@claude-flow/cli/dist/src/init/claudemd-generator.js +73 -494
- package/src/@claude-flow/cli/dist/src/init/executor.js +109 -5
- package/src/@claude-flow/cli/dist/src/init/helpers-generator.d.ts +14 -0
- package/src/@claude-flow/cli/dist/src/init/helpers-generator.js +156 -24
- package/src/@claude-flow/cli/dist/src/init/mcp-generator.js +20 -20
- package/src/@claude-flow/cli/dist/src/init/moflo-init.d.ts +30 -23
- package/src/@claude-flow/cli/dist/src/init/moflo-init.js +727 -670
- package/src/@claude-flow/cli/dist/src/init/settings-generator.js +23 -14
- package/src/@claude-flow/cli/dist/src/mcp-server.js +3 -3
- package/src/@claude-flow/cli/dist/src/plugins/manager.js +9 -8
- package/src/@claude-flow/cli/dist/src/services/worker-daemon.d.ts +1 -0
- package/src/@claude-flow/cli/dist/src/services/worker-daemon.js +3 -1
- package/src/@claude-flow/cli/dist/src/services/workflow-gate.js +10 -10
- package/src/@claude-flow/cli/package.json +106 -106
|
@@ -14,7 +14,7 @@ import { detectPlatform, DEFAULT_INIT_OPTIONS } from './types.js';
|
|
|
14
14
|
import { generateSettingsJson, generateSettings } from './settings-generator.js';
|
|
15
15
|
import { generateMCPJson } from './mcp-generator.js';
|
|
16
16
|
import { generateStatuslineScript } from './statusline-generator.js';
|
|
17
|
-
import { generatePreCommitHook, generatePostCommitHook, generateAutoMemoryHook, generateGateScript, generateHookHandlerScript, } from './helpers-generator.js';
|
|
17
|
+
import { generatePreCommitHook, generatePostCommitHook, generateAutoMemoryHook, generateGateScript, generateGateHookScript, generatePromptHookScript, generateHookHandlerScript, } from './helpers-generator.js';
|
|
18
18
|
import { generateClaudeMd } from './claudemd-generator.js';
|
|
19
19
|
/**
|
|
20
20
|
* Skills to copy based on configuration
|
|
@@ -377,6 +377,8 @@ export async function executeUpgrade(targetDir, upgradeSettings = false) {
|
|
|
377
377
|
const generatedCritical = {
|
|
378
378
|
'auto-memory-hook.mjs': generateAutoMemoryHook(),
|
|
379
379
|
'gate.cjs': generateGateScript(),
|
|
380
|
+
'gate-hook.mjs': generateGateHookScript(),
|
|
381
|
+
'prompt-hook.mjs': generatePromptHookScript(),
|
|
380
382
|
'hook-handler.cjs': generateHookHandlerScript(),
|
|
381
383
|
};
|
|
382
384
|
for (const [helperName, content] of Object.entries(generatedCritical)) {
|
|
@@ -463,6 +465,22 @@ export async function executeUpgrade(targetDir, upgradeSettings = false) {
|
|
|
463
465
|
}
|
|
464
466
|
}
|
|
465
467
|
}
|
|
468
|
+
// 1c. Build manifest of files we're installing, clean up stale ones
|
|
469
|
+
const manifestPath = path.join(targetDir, '.claude-flow', 'installed-files.json');
|
|
470
|
+
let previousManifest = [];
|
|
471
|
+
try {
|
|
472
|
+
previousManifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
473
|
+
}
|
|
474
|
+
catch { /* ok */ }
|
|
475
|
+
const currentManifest = [];
|
|
476
|
+
// Collect everything we just synced into the manifest
|
|
477
|
+
for (const entry of [...result.created, ...result.updated]) {
|
|
478
|
+
// Strip annotations like " (removed, obsolete)" — keep only clean paths
|
|
479
|
+
const clean = entry.replace(/\s*\(.*\)$/, '');
|
|
480
|
+
if (clean.startsWith('.claude/') || clean.startsWith('.claude-flow/')) {
|
|
481
|
+
currentManifest.push(clean);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
466
484
|
// 2. Create MISSING metrics files only (preserve existing data)
|
|
467
485
|
const metricsDir = path.join(targetDir, '.claude-flow', 'metrics');
|
|
468
486
|
const securityDir = path.join(targetDir, '.claude-flow', 'security');
|
|
@@ -579,6 +597,39 @@ export async function executeUpgrade(targetDir, upgradeSettings = false) {
|
|
|
579
597
|
result.settingsUpdated = ['Created new settings.json with Agent Teams'];
|
|
580
598
|
}
|
|
581
599
|
}
|
|
600
|
+
// ── Final: collect any additional generated files into manifest, then clean up stale ──
|
|
601
|
+
// Re-scan result arrays since metrics/security files were added after initial collection
|
|
602
|
+
for (const entry of [...result.created, ...result.updated]) {
|
|
603
|
+
const clean = entry.replace(/\s*\(.*\)$/, '');
|
|
604
|
+
if ((clean.startsWith('.claude/') || clean.startsWith('.claude-flow/')) && !currentManifest.includes(clean)) {
|
|
605
|
+
currentManifest.push(clean);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
// Remove files that were in the OLD manifest but NOT in the new one.
|
|
609
|
+
// This only deletes files moflo previously installed — never user or runtime files.
|
|
610
|
+
if (previousManifest.length > 0) {
|
|
611
|
+
const currentSet = new Set(currentManifest);
|
|
612
|
+
for (const rel of previousManifest) {
|
|
613
|
+
if (!currentSet.has(rel)) {
|
|
614
|
+
const abs = path.join(targetDir, rel);
|
|
615
|
+
try {
|
|
616
|
+
if (fs.existsSync(abs)) {
|
|
617
|
+
fs.unlinkSync(abs);
|
|
618
|
+
result.updated.push(`${rel} (removed, no longer shipped)`);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
catch { /* non-fatal */ }
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
// Write manifest for next upgrade
|
|
626
|
+
try {
|
|
627
|
+
const cfDir = path.join(targetDir, '.claude-flow');
|
|
628
|
+
if (!fs.existsSync(cfDir))
|
|
629
|
+
fs.mkdirSync(cfDir, { recursive: true });
|
|
630
|
+
fs.writeFileSync(manifestPath, JSON.stringify(currentManifest, null, 2), 'utf-8');
|
|
631
|
+
}
|
|
632
|
+
catch { /* non-fatal */ }
|
|
582
633
|
}
|
|
583
634
|
catch (error) {
|
|
584
635
|
result.success = false;
|
|
@@ -713,12 +764,63 @@ async function writeSettings(targetDir, options, result) {
|
|
|
713
764
|
}
|
|
714
765
|
/**
|
|
715
766
|
* Write .mcp.json
|
|
767
|
+
*
|
|
768
|
+
* If an existing config contains the legacy 'claude-flow' server key, prompt
|
|
769
|
+
* the user to migrate it to 'moflo', keep both side-by-side, or leave as-is.
|
|
716
770
|
*/
|
|
717
771
|
async function writeMCPConfig(targetDir, options, result) {
|
|
718
772
|
const mcpPath = path.join(targetDir, '.mcp.json');
|
|
719
|
-
if (fs.existsSync(mcpPath)
|
|
720
|
-
|
|
721
|
-
|
|
773
|
+
if (fs.existsSync(mcpPath)) {
|
|
774
|
+
const existing = JSON.parse(fs.readFileSync(mcpPath, 'utf-8'));
|
|
775
|
+
const servers = existing?.mcpServers ?? {};
|
|
776
|
+
const hasLegacy = 'claude-flow' in servers;
|
|
777
|
+
const hasMoflo = 'moflo' in servers;
|
|
778
|
+
if (hasLegacy && !hasMoflo) {
|
|
779
|
+
// Interactive mode: prompt the user
|
|
780
|
+
if (process.stdin.isTTY && !options.force) {
|
|
781
|
+
const { select } = await import('../prompt.js');
|
|
782
|
+
const action = await select({
|
|
783
|
+
message: "Found existing 'claude-flow' MCP server. How should we handle it?",
|
|
784
|
+
options: [
|
|
785
|
+
{ value: 'migrate', label: 'Migrate to moflo', hint: 'Rename claude-flow → moflo (recommended)' },
|
|
786
|
+
{ value: 'side-by-side', label: 'Keep both', hint: 'Add moflo alongside existing claude-flow' },
|
|
787
|
+
{ value: 'skip', label: 'Skip', hint: 'Leave .mcp.json unchanged' },
|
|
788
|
+
],
|
|
789
|
+
default: 'migrate',
|
|
790
|
+
});
|
|
791
|
+
if (action === 'skip') {
|
|
792
|
+
result.skipped.push('.mcp.json');
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (action === 'migrate') {
|
|
796
|
+
servers['moflo'] = servers['claude-flow'];
|
|
797
|
+
delete servers['claude-flow'];
|
|
798
|
+
existing.mcpServers = servers;
|
|
799
|
+
fs.writeFileSync(mcpPath, JSON.stringify(existing, null, 2), 'utf-8');
|
|
800
|
+
result.created.files.push('.mcp.json (migrated claude-flow → moflo)');
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
// side-by-side: fall through to generate new config and merge
|
|
804
|
+
const newConfig = JSON.parse(generateMCPJson(options));
|
|
805
|
+
Object.assign(servers, newConfig.mcpServers ?? {});
|
|
806
|
+
existing.mcpServers = servers;
|
|
807
|
+
fs.writeFileSync(mcpPath, JSON.stringify(existing, null, 2), 'utf-8');
|
|
808
|
+
result.created.files.push('.mcp.json (added moflo alongside claude-flow)');
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
// Non-interactive (CI/pipe): auto-migrate silently
|
|
812
|
+
servers['moflo'] = servers['claude-flow'];
|
|
813
|
+
delete servers['claude-flow'];
|
|
814
|
+
existing.mcpServers = servers;
|
|
815
|
+
fs.writeFileSync(mcpPath, JSON.stringify(existing, null, 2), 'utf-8');
|
|
816
|
+
result.created.files.push('.mcp.json (auto-migrated claude-flow → moflo)');
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
// Already has moflo or no legacy key — skip unless forced
|
|
820
|
+
if (!options.force) {
|
|
821
|
+
result.skipped.push('.mcp.json');
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
722
824
|
}
|
|
723
825
|
const content = generateMCPJson(options);
|
|
724
826
|
fs.writeFileSync(mcpPath, content, 'utf-8');
|
|
@@ -1012,6 +1114,8 @@ async function writeHelpers(targetDir, options, result) {
|
|
|
1012
1114
|
'post-commit': generatePostCommitHook(),
|
|
1013
1115
|
'auto-memory-hook.mjs': generateAutoMemoryHook(),
|
|
1014
1116
|
'gate.cjs': generateGateScript(),
|
|
1117
|
+
'gate-hook.mjs': generateGateHookScript(),
|
|
1118
|
+
'prompt-hook.mjs': generatePromptHookScript(),
|
|
1015
1119
|
'hook-handler.cjs': generateHookHandlerScript(),
|
|
1016
1120
|
};
|
|
1017
1121
|
for (const [name, content] of Object.entries(helpers)) {
|
|
@@ -1653,7 +1757,7 @@ npx moflo hive-mind consensus --propose "task"
|
|
|
1653
1757
|
### MCP Server Setup
|
|
1654
1758
|
\`\`\`bash
|
|
1655
1759
|
# Add Claude Flow MCP
|
|
1656
|
-
claude mcp add
|
|
1760
|
+
claude mcp add moflo -- npx -y moflo
|
|
1657
1761
|
|
|
1658
1762
|
# Optional servers
|
|
1659
1763
|
claude mcp add ruv-swarm -- npx -y ruv-swarm mcp start
|
|
@@ -28,6 +28,20 @@ export declare function generateHelpers(options: InitOptions): Record<string, st
|
|
|
28
28
|
* on every tool call (~500ms npx overhead → ~20ms direct node).
|
|
29
29
|
*/
|
|
30
30
|
export declare function generateGateScript(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Generate gate-hook.mjs — ESM wrapper that reads Claude Code stdin JSON
|
|
33
|
+
* and passes tool_name + tool_input to gate.cjs via environment variables.
|
|
34
|
+
*
|
|
35
|
+
* Claude Code hooks receive context as JSON on stdin but don't set env vars
|
|
36
|
+
* for tool input. This script bridges that gap. It also translates exit code 1
|
|
37
|
+
* from gate.cjs into exit code 2 (which Claude Code requires to block tools).
|
|
38
|
+
*/
|
|
39
|
+
export declare function generateGateHookScript(): string;
|
|
40
|
+
/**
|
|
41
|
+
* Generate prompt-hook.mjs — reads user prompt from Claude Code stdin JSON,
|
|
42
|
+
* runs prompt classification via gate.cjs, and appends namespace hints.
|
|
43
|
+
*/
|
|
44
|
+
export declare function generatePromptHookScript(): string;
|
|
31
45
|
/**
|
|
32
46
|
* Generate lightweight hook-handler.cjs — hook dispatch without CLI bootstrap.
|
|
33
47
|
* Handles routing, edit/task tracking, session lifecycle, and notifications.
|
|
@@ -178,6 +178,8 @@ export function generateHelpers(options) {
|
|
|
178
178
|
helpers['pre-commit'] = generatePreCommitHook();
|
|
179
179
|
helpers['post-commit'] = generatePostCommitHook();
|
|
180
180
|
helpers['gate.cjs'] = generateGateScript();
|
|
181
|
+
helpers['gate-hook.mjs'] = generateGateHookScript();
|
|
182
|
+
helpers['prompt-hook.mjs'] = generatePromptHookScript();
|
|
181
183
|
helpers['hook-handler.cjs'] = generateHookHandlerScript();
|
|
182
184
|
}
|
|
183
185
|
if (options.components.statusline) {
|
|
@@ -197,7 +199,7 @@ export function generateGateScript() {
|
|
|
197
199
|
var fs = require('fs');
|
|
198
200
|
var path = require('path');
|
|
199
201
|
|
|
200
|
-
var PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
202
|
+
var PROJECT_DIR = (process.env.CLAUDE_PROJECT_DIR || process.cwd()).replace(/^\\/([a-z])\\//i, '$1:/');
|
|
201
203
|
var STATE_FILE = path.join(PROJECT_DIR, '.claude', 'workflow-state.json');
|
|
202
204
|
|
|
203
205
|
function readState() {
|
|
@@ -241,13 +243,15 @@ var TASK_RE = /\\b(fix|bug|error|implement|add|create|build|write|refactor|debug
|
|
|
241
243
|
switch (command) {
|
|
242
244
|
case 'check-before-agent': {
|
|
243
245
|
var s = readState();
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
process.
|
|
246
|
+
// Hard gate: memory must be searched
|
|
247
|
+
if (config.memory_first && s.memoryRequired && !s.memorySearched) {
|
|
248
|
+
process.stderr.write('BLOCKED: Search memory (mcp__moflo__memory_search) before spawning agents.\\n');
|
|
249
|
+
process.exit(2);
|
|
247
250
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
+
// Soft gate: TaskCreate recommended but not blocking
|
|
252
|
+
// (TaskCreate PostToolUse doesn't fire in Claude Code, so we can't track it reliably)
|
|
253
|
+
if (config.task_create_first && !s.tasksCreated) {
|
|
254
|
+
process.stdout.write('REMINDER: Use TaskCreate before spawning agents. Task tool is blocked until then.\\n');
|
|
251
255
|
}
|
|
252
256
|
break;
|
|
253
257
|
}
|
|
@@ -257,14 +261,8 @@ switch (command) {
|
|
|
257
261
|
if (s.memorySearched || !s.memoryRequired) break;
|
|
258
262
|
var target = (process.env.TOOL_INPUT_pattern || '') + ' ' + (process.env.TOOL_INPUT_path || '');
|
|
259
263
|
if (EXEMPT.some(function(p) { return target.indexOf(p) >= 0; })) break;
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (now - last > 2000) {
|
|
263
|
-
s.lastBlockedAt = new Date(now).toISOString();
|
|
264
|
-
writeState(s);
|
|
265
|
-
console.log('BLOCKED: Search memory before exploring files.');
|
|
266
|
-
}
|
|
267
|
-
process.exit(1);
|
|
264
|
+
process.stderr.write('BLOCKED: Search memory before exploring files. Use mcp__moflo__memory_search.\\n');
|
|
265
|
+
process.exit(2);
|
|
268
266
|
}
|
|
269
267
|
case 'check-before-read': {
|
|
270
268
|
if (!config.memory_first) break;
|
|
@@ -272,14 +270,8 @@ switch (command) {
|
|
|
272
270
|
if (s.memorySearched || !s.memoryRequired) break;
|
|
273
271
|
var fp = process.env.TOOL_INPUT_file_path || '';
|
|
274
272
|
if (fp.indexOf('.claude/guidance/') < 0 && fp.indexOf('.claude\\\\guidance\\\\') < 0) break;
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
if (now - last > 2000) {
|
|
278
|
-
s.lastBlockedAt = new Date(now).toISOString();
|
|
279
|
-
writeState(s);
|
|
280
|
-
console.log('BLOCKED: Search memory before reading guidance files.');
|
|
281
|
-
}
|
|
282
|
-
process.exit(1);
|
|
273
|
+
process.stderr.write('BLOCKED: Search memory before reading guidance files. Use mcp__moflo__memory_search.\\n');
|
|
274
|
+
process.exit(2);
|
|
283
275
|
}
|
|
284
276
|
case 'record-task-created': {
|
|
285
277
|
var s = readState();
|
|
@@ -325,7 +317,7 @@ switch (command) {
|
|
|
325
317
|
var ic = s.interactionCount;
|
|
326
318
|
if (ic > 30) console.log('Context: CRITICAL. Commit, store learnings, suggest new session.');
|
|
327
319
|
else if (ic > 20) console.log('Context: DEPLETED. Checkpoint progress. Recommend /compact or fresh session.');
|
|
328
|
-
else if (ic > 10) console.log('Context: MODERATE. Re-state goal before architectural decisions.');
|
|
320
|
+
else if (ic > 10) console.log('Context: MODERATE. Re-state goal before architectural decisions. Use agents for >300 LOC.');
|
|
329
321
|
}
|
|
330
322
|
break;
|
|
331
323
|
}
|
|
@@ -342,6 +334,146 @@ switch (command) {
|
|
|
342
334
|
}
|
|
343
335
|
`;
|
|
344
336
|
}
|
|
337
|
+
/**
|
|
338
|
+
* Generate gate-hook.mjs — ESM wrapper that reads Claude Code stdin JSON
|
|
339
|
+
* and passes tool_name + tool_input to gate.cjs via environment variables.
|
|
340
|
+
*
|
|
341
|
+
* Claude Code hooks receive context as JSON on stdin but don't set env vars
|
|
342
|
+
* for tool input. This script bridges that gap. It also translates exit code 1
|
|
343
|
+
* from gate.cjs into exit code 2 (which Claude Code requires to block tools).
|
|
344
|
+
*/
|
|
345
|
+
export function generateGateHookScript() {
|
|
346
|
+
return `#!/usr/bin/env node
|
|
347
|
+
import { execSync } from 'child_process';
|
|
348
|
+
import { resolve } from 'path';
|
|
349
|
+
|
|
350
|
+
var command = process.argv[2];
|
|
351
|
+
if (!command) process.exit(0);
|
|
352
|
+
|
|
353
|
+
// Read stdin JSON from Claude Code
|
|
354
|
+
var stdinData = '';
|
|
355
|
+
try {
|
|
356
|
+
stdinData = await new Promise(function(res) {
|
|
357
|
+
var data = '';
|
|
358
|
+
var timeout = setTimeout(function() { res(data); }, 500);
|
|
359
|
+
process.stdin.setEncoding('utf-8');
|
|
360
|
+
process.stdin.on('data', function(chunk) { data += chunk; });
|
|
361
|
+
process.stdin.on('end', function() { clearTimeout(timeout); res(data); });
|
|
362
|
+
process.stdin.on('error', function() { clearTimeout(timeout); res(''); });
|
|
363
|
+
if (process.stdin.isTTY) { clearTimeout(timeout); res(''); }
|
|
364
|
+
});
|
|
365
|
+
} catch (e) { /* no stdin */ }
|
|
366
|
+
|
|
367
|
+
var hookContext = {};
|
|
368
|
+
try { if (stdinData.trim()) hookContext = JSON.parse(stdinData); } catch (e) {}
|
|
369
|
+
|
|
370
|
+
// Pass tool info as env vars for gate.cjs
|
|
371
|
+
var env = Object.assign({}, process.env);
|
|
372
|
+
if (hookContext.tool_name) env.TOOL_NAME = hookContext.tool_name;
|
|
373
|
+
if (hookContext.tool_input && typeof hookContext.tool_input === 'object') {
|
|
374
|
+
Object.keys(hookContext.tool_input).forEach(function(key) {
|
|
375
|
+
if (typeof hookContext.tool_input[key] === 'string') {
|
|
376
|
+
env['TOOL_INPUT_' + key] = hookContext.tool_input[key];
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Run gate.cjs with the enriched environment
|
|
382
|
+
var projectDir = (env.CLAUDE_PROJECT_DIR || process.cwd()).replace(/^\\/([a-z])\\//i, '$1:/');
|
|
383
|
+
var gateScript = resolve(projectDir, '.claude/helpers/gate.cjs');
|
|
384
|
+
try {
|
|
385
|
+
var output = execSync('node "' + gateScript + '" ' + command, {
|
|
386
|
+
env: env, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe']
|
|
387
|
+
});
|
|
388
|
+
if (output.trim()) process.stdout.write(output);
|
|
389
|
+
process.exit(0);
|
|
390
|
+
} catch (err) {
|
|
391
|
+
// gate.cjs exit(2) = block, exit(1) = also block attempt — translate both to exit(2)
|
|
392
|
+
if (err.stderr) process.stderr.write(err.stderr);
|
|
393
|
+
if (err.stdout) process.stderr.write(err.stdout);
|
|
394
|
+
process.exit(err.status === 2 || err.status === 1 ? 2 : 0);
|
|
395
|
+
}
|
|
396
|
+
`;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Generate prompt-hook.mjs — reads user prompt from Claude Code stdin JSON,
|
|
400
|
+
* runs prompt classification via gate.cjs, and appends namespace hints.
|
|
401
|
+
*/
|
|
402
|
+
export function generatePromptHookScript() {
|
|
403
|
+
return `#!/usr/bin/env node
|
|
404
|
+
import { execSync } from 'child_process';
|
|
405
|
+
import { resolve } from 'path';
|
|
406
|
+
|
|
407
|
+
// Read stdin JSON from Claude Code
|
|
408
|
+
var stdinData = '';
|
|
409
|
+
try {
|
|
410
|
+
stdinData = await new Promise(function(res) {
|
|
411
|
+
var data = '';
|
|
412
|
+
var timeout = setTimeout(function() { res(data); }, 500);
|
|
413
|
+
process.stdin.setEncoding('utf-8');
|
|
414
|
+
process.stdin.on('data', function(chunk) { data += chunk; });
|
|
415
|
+
process.stdin.on('end', function() { clearTimeout(timeout); res(data); });
|
|
416
|
+
process.stdin.on('error', function() { clearTimeout(timeout); res(''); });
|
|
417
|
+
if (process.stdin.isTTY) { clearTimeout(timeout); res(''); }
|
|
418
|
+
});
|
|
419
|
+
} catch (e) { /* no stdin */ }
|
|
420
|
+
|
|
421
|
+
var hookContext = {};
|
|
422
|
+
try { if (stdinData.trim()) hookContext = JSON.parse(stdinData); } catch (e) {}
|
|
423
|
+
|
|
424
|
+
var userPrompt = hookContext.user_prompt || hookContext.prompt || '';
|
|
425
|
+
var env = Object.assign({}, process.env, { CLAUDE_USER_PROMPT: userPrompt });
|
|
426
|
+
|
|
427
|
+
// Run prompt-reminder via gate.cjs
|
|
428
|
+
var projectDir = (env.CLAUDE_PROJECT_DIR || process.cwd()).replace(/^\\/([a-z])\\//i, '$1:/');
|
|
429
|
+
var gateScript = resolve(projectDir, '.claude/helpers/gate.cjs');
|
|
430
|
+
var output = '';
|
|
431
|
+
try {
|
|
432
|
+
output = execSync('node "' + gateScript + '" prompt-reminder', {
|
|
433
|
+
env: env, encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe']
|
|
434
|
+
});
|
|
435
|
+
} catch (err) { output = (err && err.stdout) || ''; }
|
|
436
|
+
|
|
437
|
+
// Classify prompt for namespace hint
|
|
438
|
+
var lower = userPrompt.toLowerCase();
|
|
439
|
+
|
|
440
|
+
var KNOWLEDGE_ONLY = /\\b(knowledge|remember|recall)\\b|we (decid|agree|chose|said)/;
|
|
441
|
+
var EXPLICIT_NS = [
|
|
442
|
+
{ pattern: /\\b(pattern|convention|best practice|style|coding rule)\\b/, ns: 'patterns', label: 'code patterns and conventions' },
|
|
443
|
+
{ pattern: /\\b(code.?map|file structure|project structure|directory)\\b/, ns: 'code-map', label: 'codebase navigation' },
|
|
444
|
+
];
|
|
445
|
+
var PATTERN_HINTS = [/\\b(template|example|similar to|how do we|how should)\\b/];
|
|
446
|
+
var DOMAIN_HINTS = [
|
|
447
|
+
/\\b(guidance|guide|docs|documentation|rules|how-to)\\b/,
|
|
448
|
+
/\\b(architecture|design|domain|tenant|migrat|schema|deploy)/,
|
|
449
|
+
/\\b(rule|requirement|constraint|compliance)\\b/,
|
|
450
|
+
];
|
|
451
|
+
var NAV_PATTERNS = [
|
|
452
|
+
/\\b(find|where|which file|look up|locate|endpoint|route|url|path)\\b/,
|
|
453
|
+
/\\b(class|function|method|component|service|entity|module)\\b/,
|
|
454
|
+
];
|
|
455
|
+
|
|
456
|
+
var nsHint = '';
|
|
457
|
+
if (KNOWLEDGE_ONLY.test(lower)) {
|
|
458
|
+
nsHint = 'Memory namespace hint: use "knowledge" for user-directed project decisions.';
|
|
459
|
+
} else {
|
|
460
|
+
var found = EXPLICIT_NS.find(function(e) { return e.pattern.test(lower); });
|
|
461
|
+
if (found) {
|
|
462
|
+
nsHint = 'Memory namespace hint: use "' + found.ns + '" for ' + found.label + '.';
|
|
463
|
+
} else if (DOMAIN_HINTS.some(function(p) { return p.test(lower); })) {
|
|
464
|
+
nsHint = 'Memory namespace hint: search "guidance" and "knowledge" for domain rules and project decisions.';
|
|
465
|
+
} else if (PATTERN_HINTS.some(function(p) { return p.test(lower); })) {
|
|
466
|
+
nsHint = 'Memory namespace hint: use "patterns" for code patterns and conventions.';
|
|
467
|
+
} else if (NAV_PATTERNS.some(function(p) { return p.test(lower); })) {
|
|
468
|
+
nsHint = 'Memory namespace hint: use "code-map" for codebase navigation.';
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
var parts = [output.trim(), nsHint].filter(Boolean);
|
|
473
|
+
if (parts.length) process.stdout.write(parts.join('\\n') + '\\n');
|
|
474
|
+
process.exit(0);
|
|
475
|
+
`;
|
|
476
|
+
}
|
|
345
477
|
/**
|
|
346
478
|
* Generate lightweight hook-handler.cjs — hook dispatch without CLI bootstrap.
|
|
347
479
|
* Handles routing, edit/task tracking, session lifecycle, and notifications.
|
|
@@ -8,28 +8,25 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { existsSync } from 'fs';
|
|
10
10
|
import { join } from 'path';
|
|
11
|
+
const isWindows = process.platform === 'win32';
|
|
11
12
|
/**
|
|
12
|
-
* Generate MCP server entry using npx (for external packages)
|
|
13
|
+
* Generate MCP server entry using npx (for external packages).
|
|
14
|
+
* On Windows, wraps with `cmd /c` so Claude Code can spawn the process.
|
|
13
15
|
*/
|
|
14
16
|
function createNpxServerEntry(npxArgs, env, additionalProps = {}) {
|
|
15
|
-
return
|
|
16
|
-
command: 'npx',
|
|
17
|
-
args: ['-y', ...npxArgs],
|
|
18
|
-
env,
|
|
19
|
-
...additionalProps,
|
|
20
|
-
};
|
|
17
|
+
return isWindows
|
|
18
|
+
? { command: 'cmd', args: ['/c', 'npx', '-y', ...npxArgs], env, ...additionalProps }
|
|
19
|
+
: { command: 'npx', args: ['-y', ...npxArgs], env, ...additionalProps };
|
|
21
20
|
}
|
|
22
21
|
/**
|
|
23
22
|
* Generate MCP server entry using direct node invocation (for local moflo).
|
|
24
23
|
* Avoids npx overhead — faster startup, fewer intermediate processes.
|
|
24
|
+
* On Windows, wraps with `cmd /c` so Claude Code can spawn the process.
|
|
25
25
|
*/
|
|
26
26
|
function createDirectServerEntry(cliPath, cliArgs, env, additionalProps = {}) {
|
|
27
|
-
return
|
|
28
|
-
command: 'node',
|
|
29
|
-
args: [cliPath, ...cliArgs],
|
|
30
|
-
env,
|
|
31
|
-
...additionalProps,
|
|
32
|
-
};
|
|
27
|
+
return isWindows
|
|
28
|
+
? { command: 'cmd', args: ['/c', 'node', cliPath, ...cliArgs], env, ...additionalProps }
|
|
29
|
+
: { command: 'node', args: [cliPath, ...cliArgs], env, ...additionalProps };
|
|
33
30
|
}
|
|
34
31
|
/**
|
|
35
32
|
* Find the moflo CLI entry point relative to the project root.
|
|
@@ -73,10 +70,10 @@ export function generateMCPConfig(options) {
|
|
|
73
70
|
const projectRoot = options.targetDir ?? process.cwd();
|
|
74
71
|
const localCli = findMofloCli(projectRoot);
|
|
75
72
|
if (localCli) {
|
|
76
|
-
mcpServers['
|
|
73
|
+
mcpServers['moflo'] = createDirectServerEntry(localCli, ['mcp', 'start'], mcpEnv, { autoStart: config.autoStart, ...deferProps });
|
|
77
74
|
}
|
|
78
75
|
else {
|
|
79
|
-
mcpServers['
|
|
76
|
+
mcpServers['moflo'] = createNpxServerEntry(['moflo', 'mcp', 'start'], mcpEnv, { autoStart: config.autoStart, ...deferProps });
|
|
80
77
|
}
|
|
81
78
|
}
|
|
82
79
|
// Ruv-Swarm MCP server (enhanced coordination) — always npx (external package)
|
|
@@ -102,21 +99,22 @@ export function generateMCPJson(options) {
|
|
|
102
99
|
export function generateMCPCommands(options) {
|
|
103
100
|
const commands = [];
|
|
104
101
|
const config = options.mcp;
|
|
102
|
+
const cmdPrefix = isWindows ? 'cmd /c ' : '';
|
|
105
103
|
if (config.claudeFlow) {
|
|
106
104
|
const projectRoot = options.targetDir ?? process.cwd();
|
|
107
105
|
const localCli = findMofloCli(projectRoot);
|
|
108
106
|
if (localCli) {
|
|
109
|
-
commands.push(`claude mcp add
|
|
107
|
+
commands.push(`claude mcp add moflo -- ${cmdPrefix}node ${localCli} mcp start`);
|
|
110
108
|
}
|
|
111
109
|
else {
|
|
112
|
-
commands.push(
|
|
110
|
+
commands.push(`claude mcp add moflo -- ${cmdPrefix}npx -y moflo mcp start`);
|
|
113
111
|
}
|
|
114
112
|
}
|
|
115
113
|
if (config.ruvSwarm) {
|
|
116
|
-
commands.push(
|
|
114
|
+
commands.push(`claude mcp add ruv-swarm -- ${cmdPrefix}npx -y ruv-swarm mcp start`);
|
|
117
115
|
}
|
|
118
116
|
if (config.flowNexus) {
|
|
119
|
-
commands.push(
|
|
117
|
+
commands.push(`claude mcp add flow-nexus -- ${cmdPrefix}npx -y flow-nexus@latest mcp start`);
|
|
120
118
|
}
|
|
121
119
|
return commands;
|
|
122
120
|
}
|
|
@@ -129,7 +127,9 @@ export function getPlatformInstructions() {
|
|
|
129
127
|
: process.platform === 'darwin' ? 'macOS' : 'Linux';
|
|
130
128
|
return {
|
|
131
129
|
platform,
|
|
132
|
-
note:
|
|
130
|
+
note: isWindows
|
|
131
|
+
? 'MCP configuration uses cmd /c wrapper for Windows compatibility.'
|
|
132
|
+
: 'MCP configuration uses npx directly.',
|
|
133
133
|
};
|
|
134
134
|
}
|
|
135
135
|
//# sourceMappingURL=mcp-generator.js.map
|
|
@@ -1,24 +1,31 @@
|
|
|
1
|
-
export interface MofloInitOptions {
|
|
2
|
-
projectRoot: string;
|
|
3
|
-
force?: boolean;
|
|
4
|
-
skipIndex?: boolean;
|
|
5
|
-
interactive?: boolean;
|
|
6
|
-
minimal?: boolean;
|
|
7
|
-
}
|
|
8
|
-
export interface MofloInitAnswers {
|
|
9
|
-
guidance: boolean;
|
|
10
|
-
guidanceDirs: string[];
|
|
11
|
-
codeMap: boolean;
|
|
12
|
-
srcDirs: string[];
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
export interface MofloInitOptions {
|
|
2
|
+
projectRoot: string;
|
|
3
|
+
force?: boolean;
|
|
4
|
+
skipIndex?: boolean;
|
|
5
|
+
interactive?: boolean;
|
|
6
|
+
minimal?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface MofloInitAnswers {
|
|
9
|
+
guidance: boolean;
|
|
10
|
+
guidanceDirs: string[];
|
|
11
|
+
codeMap: boolean;
|
|
12
|
+
srcDirs: string[];
|
|
13
|
+
tests: boolean;
|
|
14
|
+
testDirs: string[];
|
|
15
|
+
gates: boolean;
|
|
16
|
+
stopHook: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface MofloInitResult {
|
|
19
|
+
steps: {
|
|
20
|
+
name: string;
|
|
21
|
+
status: 'created' | 'updated' | 'skipped' | 'error';
|
|
22
|
+
detail?: string;
|
|
23
|
+
}[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Discover test directories by checking common locations and walking for
|
|
27
|
+
* colocated __tests__ dirs. Returns relative paths.
|
|
28
|
+
*/
|
|
29
|
+
export declare function discoverTestDirs(root: string): string[];
|
|
30
|
+
export declare function initMoflo(options: MofloInitOptions): Promise<MofloInitResult>;
|
|
24
31
|
//# sourceMappingURL=moflo-init.d.ts.map
|