triflux 10.0.0 → 10.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +171 -0
- package/README.md +32 -15
- package/bin/triflux.mjs +62 -5
- package/hooks/agent-route-guard.mjs +109 -0
- package/hooks/cross-review-tracker.mjs +122 -0
- package/hooks/error-context.mjs +148 -0
- package/hooks/hook-adaptive-collector.mjs +86 -0
- package/hooks/hook-manager.mjs +365 -0
- package/hooks/hook-orchestrator.mjs +312 -0
- package/hooks/hook-registry.json +246 -0
- package/hooks/hooks.json +89 -0
- package/hooks/keyword-rules.json +574 -0
- package/hooks/lib/resolve-root.mjs +59 -0
- package/hooks/mcp-config-watcher.mjs +80 -0
- package/hooks/pipeline-stop.mjs +76 -0
- package/hooks/safety-guard.mjs +169 -0
- package/hooks/subagent-verifier.mjs +80 -0
- package/hub/account-broker.mjs +251 -0
- package/hub/adaptive-diagnostic.mjs +323 -0
- package/hub/adaptive-inject.mjs +186 -0
- package/hub/adaptive-memory.mjs +163 -0
- package/hub/adaptive.mjs +143 -0
- package/hub/assign-callbacks.mjs +133 -0
- package/hub/bridge.mjs +799 -0
- package/hub/cli-adapter-base.mjs +280 -0
- package/hub/codex-adapter.mjs +199 -0
- package/hub/codex-compat.mjs +11 -0
- package/hub/codex-preflight.mjs +166 -0
- package/hub/delegator/contracts.mjs +37 -0
- package/hub/delegator/index.mjs +14 -0
- package/hub/delegator/schema/delegator-tools.schema.json +250 -0
- package/hub/delegator/service.mjs +307 -0
- package/hub/delegator/tool-definitions.mjs +35 -0
- package/hub/fullcycle.mjs +96 -0
- package/hub/gemini-adapter.mjs +180 -0
- package/hub/hitl.mjs +143 -0
- package/hub/intent.mjs +193 -0
- package/hub/lib/cache-guard.mjs +114 -0
- package/hub/lib/known-errors.json +72 -0
- package/hub/lib/memory-store.mjs +748 -0
- package/hub/lib/process-utils.mjs +361 -0
- package/hub/lib/ssh-command.mjs +211 -0
- package/hub/lib/ssh-retry.mjs +59 -0
- package/hub/lib/uuidv7.mjs +44 -0
- package/hub/memory-doctor.mjs +480 -0
- package/hub/middleware/request-logger.mjs +161 -0
- package/hub/paths.mjs +30 -0
- package/hub/pipe.mjs +664 -0
- package/hub/pipeline/gates/confidence.mjs +56 -0
- package/hub/pipeline/gates/consensus.mjs +94 -0
- package/hub/pipeline/gates/index.mjs +5 -0
- package/hub/pipeline/gates/selfcheck.mjs +82 -0
- package/hub/pipeline/index.mjs +318 -0
- package/hub/pipeline/state.mjs +191 -0
- package/hub/pipeline/transitions.mjs +124 -0
- package/hub/platform.mjs +225 -0
- package/hub/public/dashboard.html +355 -0
- package/hub/public/tray-icon.ico +0 -0
- package/hub/public/tray-icon.png +0 -0
- package/hub/quality/deslop.mjs +253 -0
- package/hub/reflexion.mjs +372 -0
- package/hub/research.mjs +146 -0
- package/hub/router.mjs +791 -0
- package/hub/routing/complexity.mjs +166 -0
- package/hub/routing/index.mjs +117 -0
- package/hub/routing/q-learning.mjs +336 -0
- package/hub/schema.sql +148 -0
- package/hub/server.mjs +1264 -0
- package/hub/session-fingerprint.mjs +352 -0
- package/hub/state.mjs +258 -0
- package/hub/store-adapter.mjs +118 -0
- package/hub/store.mjs +857 -0
- package/hub/team/agent-map.json +11 -0
- package/hub/team/ansi.mjs +379 -0
- package/hub/team/backend.mjs +90 -0
- package/hub/team/cli/commands/attach.mjs +37 -0
- package/hub/team/cli/commands/control.mjs +43 -0
- package/hub/team/cli/commands/debug.mjs +74 -0
- package/hub/team/cli/commands/focus.mjs +53 -0
- package/hub/team/cli/commands/interrupt.mjs +36 -0
- package/hub/team/cli/commands/kill.mjs +37 -0
- package/hub/team/cli/commands/list.mjs +24 -0
- package/hub/team/cli/commands/send.mjs +37 -0
- package/hub/team/cli/commands/start/index.mjs +106 -0
- package/hub/team/cli/commands/start/parse-args.mjs +130 -0
- package/hub/team/cli/commands/start/start-headless.mjs +109 -0
- package/hub/team/cli/commands/start/start-in-process.mjs +40 -0
- package/hub/team/cli/commands/start/start-mux.mjs +73 -0
- package/hub/team/cli/commands/start/start-wt.mjs +69 -0
- package/hub/team/cli/commands/status.mjs +87 -0
- package/hub/team/cli/commands/stop.mjs +31 -0
- package/hub/team/cli/commands/task.mjs +30 -0
- package/hub/team/cli/commands/tasks.mjs +13 -0
- package/hub/team/cli/help.mjs +42 -0
- package/hub/team/cli/index.mjs +41 -0
- package/hub/team/cli/manifest.mjs +29 -0
- package/hub/team/cli/render.mjs +30 -0
- package/hub/team/cli/services/attach-fallback.mjs +54 -0
- package/hub/team/cli/services/hub-client.mjs +227 -0
- package/hub/team/cli/services/member-selector.mjs +30 -0
- package/hub/team/cli/services/native-control.mjs +117 -0
- package/hub/team/cli/services/runtime-mode.mjs +62 -0
- package/hub/team/cli/services/state-store.mjs +48 -0
- package/hub/team/cli/services/task-model.mjs +30 -0
- package/hub/team/conductor-mesh-bridge.mjs +121 -0
- package/hub/team/conductor.mjs +671 -0
- package/hub/team/dashboard-anchor.mjs +14 -0
- package/hub/team/dashboard-layout.mjs +33 -0
- package/hub/team/dashboard-open.mjs +153 -0
- package/hub/team/dashboard.mjs +274 -0
- package/hub/team/event-log.mjs +76 -0
- package/hub/team/handoff.mjs +303 -0
- package/hub/team/headless.mjs +1156 -0
- package/hub/team/health-probe.mjs +272 -0
- package/hub/team/launcher-template.mjs +95 -0
- package/hub/team/lead-control.mjs +104 -0
- package/hub/team/native-supervisor.mjs +392 -0
- package/hub/team/native.mjs +649 -0
- package/hub/team/nativeProxy.mjs +688 -0
- package/hub/team/notify.mjs +293 -0
- package/hub/team/orchestrator.mjs +161 -0
- package/hub/team/pane.mjs +153 -0
- package/hub/team/process-cleanup.mjs +342 -0
- package/hub/team/psmux.mjs +1354 -0
- package/hub/team/remote-probe.mjs +276 -0
- package/hub/team/remote-session.mjs +299 -0
- package/hub/team/remote-watcher.mjs +478 -0
- package/hub/team/routing.mjs +223 -0
- package/hub/team/session-sync.mjs +169 -0
- package/hub/team/session.mjs +611 -0
- package/hub/team/shared.mjs +13 -0
- package/hub/team/staleState.mjs +361 -0
- package/hub/team/swarm-hypervisor.mjs +589 -0
- package/hub/team/swarm-locks.mjs +204 -0
- package/hub/team/swarm-planner.mjs +260 -0
- package/hub/team/swarm-reconciler.mjs +137 -0
- package/hub/team/tui-lite.mjs +380 -0
- package/hub/team/tui-remote-adapter.mjs +393 -0
- package/hub/team/tui-viewer.mjs +463 -0
- package/hub/team/tui.mjs +1449 -0
- package/hub/team/worktree-lifecycle.mjs +193 -0
- package/hub/team/wt-manager.mjs +407 -0
- package/hub/team/wt-templates.json +43 -0
- package/hub/team-bridge.mjs +27 -0
- package/hub/token-mode.mjs +224 -0
- package/hub/tools.mjs +636 -0
- package/hub/tray.mjs +376 -0
- package/hub/workers/claude-worker.mjs +475 -0
- package/hub/workers/codex-mcp.mjs +507 -0
- package/hub/workers/delegator-mcp.mjs +1076 -0
- package/hub/workers/factory.mjs +21 -0
- package/hub/workers/gemini-worker.mjs +374 -0
- package/hub/workers/interface.mjs +52 -0
- package/hub/workers/worker-utils.mjs +104 -0
- package/hud/colors.mjs +88 -0
- package/hud/constants.mjs +88 -0
- package/hud/context-monitor.mjs +403 -0
- package/hud/hud-qos-status.mjs +210 -0
- package/hud/providers/claude.mjs +314 -0
- package/hud/providers/codex.mjs +151 -0
- package/hud/providers/gemini.mjs +320 -0
- package/hud/renderers.mjs +442 -0
- package/hud/terminal.mjs +140 -0
- package/hud/utils.mjs +313 -0
- package/mesh/index.mjs +63 -0
- package/mesh/mesh-budget.mjs +128 -0
- package/mesh/mesh-heartbeat.mjs +100 -0
- package/mesh/mesh-protocol.mjs +96 -0
- package/mesh/mesh-queue.mjs +165 -0
- package/mesh/mesh-registry.mjs +78 -0
- package/mesh/mesh-router.mjs +76 -0
- package/package.json +8 -1
- package/references/hosts.json +33 -0
- package/scripts/__tests__/gen-skill-docs.test.mjs +87 -0
- package/scripts/__tests__/keyword-detector.test.mjs +234 -0
- package/scripts/__tests__/mcp-guard-engine.test.mjs +118 -0
- package/scripts/__tests__/remote-spawn-transfer.test.mjs +117 -0
- package/scripts/__tests__/remote-spawn.test.mjs +92 -0
- package/scripts/__tests__/skill-template.test.mjs +193 -0
- package/scripts/__tests__/smoke.test.mjs +34 -0
- package/scripts/cache-buildup.mjs +30 -0
- package/scripts/cache-doctor.mjs +149 -0
- package/scripts/cache-warmup.mjs +557 -0
- package/scripts/claudemd-sync.mjs +148 -0
- package/scripts/cli-route.sh +3 -0
- package/scripts/completions/tfx.bash +47 -0
- package/scripts/completions/tfx.fish +44 -0
- package/scripts/completions/tfx.zsh +83 -0
- package/scripts/cross-review-gate.mjs +126 -0
- package/scripts/cross-review-tracker.mjs +238 -0
- package/scripts/gen-skill-docs.mjs +111 -0
- package/scripts/headless-guard-fast.sh +21 -0
- package/scripts/headless-guard.mjs +360 -0
- package/scripts/hub-ensure.mjs +120 -0
- package/scripts/keyword-detector.mjs +272 -0
- package/scripts/keyword-rules-expander.mjs +521 -0
- package/scripts/lib/claudemd-scanner.mjs +218 -0
- package/scripts/lib/context.mjs +67 -0
- package/scripts/lib/cross-review-utils.mjs +51 -0
- package/scripts/lib/env-probe.mjs +241 -0
- package/scripts/lib/gemini-profiles.mjs +85 -0
- package/scripts/lib/handoff.mjs +171 -0
- package/scripts/lib/hook-utils.mjs +14 -0
- package/scripts/lib/keyword-rules.mjs +166 -0
- package/scripts/lib/logger.mjs +105 -0
- package/scripts/lib/mcp-filter.mjs +739 -0
- package/scripts/lib/mcp-guard-engine.mjs +954 -0
- package/scripts/lib/mcp-manifest.mjs +79 -0
- package/scripts/lib/mcp-server-catalog.mjs +118 -0
- package/scripts/lib/psmux-info.mjs +119 -0
- package/scripts/lib/remote-spawn-transfer.mjs +196 -0
- package/scripts/lib/skill-template.mjs +326 -0
- package/scripts/mcp-check.mjs +237 -0
- package/scripts/mcp-cleanup.ps1 +17 -0
- package/scripts/mcp-gateway-config.mjs +207 -0
- package/scripts/mcp-gateway-ensure.mjs +85 -0
- package/scripts/mcp-gateway-integration-test.mjs +228 -0
- package/scripts/mcp-gateway-start.mjs +226 -0
- package/scripts/mcp-gateway-start.ps1 +141 -0
- package/scripts/mcp-gateway-verify.mjs +77 -0
- package/scripts/mcp-safety-guard.mjs +44 -0
- package/scripts/notion-read.mjs +556 -0
- package/scripts/pack.mjs +295 -0
- package/scripts/preflight-cache.mjs +69 -0
- package/scripts/preinstall.mjs +96 -0
- package/scripts/remote-spawn.mjs +1376 -0
- package/scripts/run.cjs +79 -0
- package/scripts/session-spawn-helper.mjs +185 -0
- package/scripts/setup.mjs +1178 -0
- package/scripts/test-lock.mjs +71 -0
- package/scripts/test-tfx-route-no-claude-native.mjs +57 -0
- package/scripts/tfx-batch-stats.mjs +96 -0
- package/scripts/tfx-gate-activate.mjs +89 -0
- package/scripts/tfx-route-post.mjs +505 -0
- package/scripts/tfx-route-worker.mjs +223 -0
- package/scripts/tfx-route.sh +2014 -0
- package/scripts/tmp-cleanup.mjs +103 -0
- package/scripts/token-snapshot.mjs +575 -0
- package/skills/tfx-auto/SKILL.md.tmpl +2 -3
- package/skills/tfx-autoresearch/SKILL.md +6 -5
- package/skills/tfx-codex/SKILL.md.tmpl +2 -3
- package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +33 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/eval_metadata.json +42 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +11 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/analysis.md +87 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/classification.md +35 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/commands.sh +275 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/routing.md +56 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/timing.json +5 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +11 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/analysis.md +92 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/classification.md +71 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/commands.sh +264 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/routing.md +113 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/timing.json +5 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/eval_metadata.json +32 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +9 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/analysis.md +96 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/classification.md +38 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/commands.sh +151 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/routing.md +51 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/timing.json +5 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +9 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/analysis.md +127 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/classification.md +57 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/commands.sh +129 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/routing.md +84 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/timing.json +5 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/eval_metadata.json +27 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +8 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/analysis.md +98 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/classification.md +65 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/commands.sh +123 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/routing.md +66 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/timing.json +5 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +8 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/analysis.md +88 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/classification.md +40 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/commands.sh +130 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/routing.md +61 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/timing.json +5 -0
- package/skills/tfx-deep-interview/SKILL.md +1 -2
- package/skills/tfx-plan/SKILL.md.tmpl +2 -3
- package/skills/tfx-psmux-rules/SKILL.md +11 -2
- package/skills/tfx-qa/SKILL.md.tmpl +2 -3
- package/skills/tfx-remote-spawn/SKILL.md +8 -11
- package/skills/tfx-research/SKILL.md.tmpl +2 -3
- package/skills/tfx-review/SKILL.md.tmpl +2 -3
- package/skills/tfx-workspace/async-tests/run-tests.sh +203 -0
- package/skills/tfx-workspace/evals/evals.json +79 -0
- package/skills/tfx-workspace/iteration-1/benchmark.json +162 -0
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/eval_metadata.json +11 -0
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/grading.json +9 -0
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/outputs/analysis.md +154 -0
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/grading.json +9 -0
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/outputs/analysis.md +126 -0
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/eval_metadata.json +11 -0
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/grading.json +9 -0
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/outputs/analysis.md +119 -0
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/grading.json +9 -0
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/outputs/analysis.md +115 -0
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/eval_metadata.json +10 -0
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/grading.json +8 -0
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/outputs/analysis.md +86 -0
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/grading.json +8 -0
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/outputs/analysis.md +81 -0
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-1/multi-team-creation/eval_metadata.json +12 -0
- package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/grading.json +10 -0
- package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/outputs/analysis.md +316 -0
- package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/grading.json +10 -0
- package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/outputs/analysis.md +352 -0
- package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-1/review.html +1325 -0
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/eval_metadata.json +12 -0
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/grading.json +10 -0
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/outputs/analysis.md +97 -0
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/grading.json +10 -0
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/outputs/analysis.md +94 -0
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/eval_metadata.json +12 -0
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/grading.json +10 -0
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/outputs/analysis.md +209 -0
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/grading.json +10 -0
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/outputs/analysis.md +193 -0
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-2/benchmark.json +62 -0
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/eval_metadata.json +13 -0
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/grading.json +11 -0
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/outputs/analysis.md +382 -0
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/grading.json +11 -0
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/outputs/analysis.md +333 -0
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/timing.json +5 -0
- package/skills/tfx-workspace/iteration-2/review.html +1325 -0
- package/skills/tfx-workspace/skill-snapshot/tfx-auto/SKILL.md +217 -0
- package/skills/{tfx-auto-codex/SKILL.md.tmpl → tfx-workspace/skill-snapshot/tfx-auto-codex/SKILL.md} +3 -31
- package/skills/tfx-workspace/skill-snapshot/tfx-codex/SKILL.md +65 -0
- package/skills/tfx-workspace/skill-snapshot/tfx-doctor/SKILL.md +94 -0
- package/skills/{tfx-gemini/SKILL.md.tmpl → tfx-workspace/skill-snapshot/tfx-gemini/SKILL.md} +6 -14
- package/skills/tfx-workspace/skill-snapshot/tfx-hub/SKILL.md +133 -0
- package/skills/tfx-workspace/skill-snapshot/tfx-multi/SKILL.md +426 -0
- package/skills/tfx-workspace/skill-snapshot/tfx-setup/SKILL.md +101 -0
- package/skills/merge-worktree/SKILL.md.tmpl +0 -144
- package/skills/shared/arguments-processing.md +0 -2
- package/skills/shared/mandatory-rules.md +0 -6
- package/skills/shared/telemetry-segment.md +0 -6
- package/skills/star-prompt/SKILL.md.tmpl +0 -122
- package/skills/tfx-analysis/SKILL.md.tmpl +0 -106
- package/skills/tfx-analysis/skill.json +0 -11
- package/skills/tfx-auto/skill.json +0 -26
- package/skills/tfx-auto-codex/skill.json +0 -8
- package/skills/tfx-autopilot/SKILL.md.tmpl +0 -115
- package/skills/tfx-autopilot/skill.json +0 -10
- package/skills/tfx-autoresearch/SKILL.md.tmpl +0 -135
- package/skills/tfx-autoresearch/skill.json +0 -14
- package/skills/tfx-autoroute/SKILL.md.tmpl +0 -188
- package/skills/tfx-autoroute/skill.json +0 -12
- package/skills/tfx-codex/skill.json +0 -8
- package/skills/tfx-codex-swarm/SKILL.md.tmpl +0 -16
- package/skills/tfx-codex-swarm/skill.json +0 -5
- package/skills/tfx-consensus/SKILL.md.tmpl +0 -145
- package/skills/tfx-consensus/skill.json +0 -8
- package/skills/tfx-debate/SKILL.md.tmpl +0 -191
- package/skills/tfx-debate/skill.json +0 -12
- package/skills/tfx-deep-analysis/SKILL.md.tmpl +0 -227
- package/skills/tfx-deep-analysis/skill.json +0 -10
- package/skills/tfx-deep-interview/SKILL.md.tmpl +0 -203
- package/skills/tfx-deep-interview/skill.json +0 -12
- package/skills/tfx-deep-plan/SKILL.md.tmpl +0 -281
- package/skills/tfx-deep-plan/skill.json +0 -13
- package/skills/tfx-deep-qa/SKILL.md.tmpl +0 -164
- package/skills/tfx-deep-qa/skill.json +0 -11
- package/skills/tfx-deep-research/SKILL.md.tmpl +0 -216
- package/skills/tfx-deep-research/skill.json +0 -14
- package/skills/tfx-deep-review/SKILL.md.tmpl +0 -178
- package/skills/tfx-deep-review/skill.json +0 -12
- package/skills/tfx-doctor/SKILL.md.tmpl +0 -172
- package/skills/tfx-doctor/skill.json +0 -8
- package/skills/tfx-find/skill.json +0 -12
- package/skills/tfx-forge/SKILL.md.tmpl +0 -187
- package/skills/tfx-forge/skill.json +0 -12
- package/skills/tfx-fullcycle/SKILL.md.tmpl +0 -285
- package/skills/tfx-fullcycle/skill.json +0 -11
- package/skills/tfx-gemini/skill.json +0 -8
- package/skills/tfx-hooks/SKILL.md.tmpl +0 -216
- package/skills/tfx-hooks/skill.json +0 -8
- package/skills/tfx-hub/SKILL.md.tmpl +0 -212
- package/skills/tfx-hub/skill.json +0 -8
- package/skills/tfx-index/skill.json +0 -11
- package/skills/tfx-interview/SKILL.md.tmpl +0 -284
- package/skills/tfx-interview/skill.json +0 -12
- package/skills/tfx-multi/SKILL.md.tmpl +0 -183
- package/skills/tfx-multi/skill.json +0 -8
- package/skills/tfx-panel/SKILL.md.tmpl +0 -188
- package/skills/tfx-panel/skill.json +0 -12
- package/skills/tfx-persist/SKILL.md.tmpl +0 -269
- package/skills/tfx-persist/skill.json +0 -12
- package/skills/tfx-plan/skill.json +0 -11
- package/skills/tfx-profile/SKILL.md.tmpl +0 -239
- package/skills/tfx-profile/skill.json +0 -8
- package/skills/tfx-prune/SKILL.md.tmpl +0 -199
- package/skills/tfx-prune/skill.json +0 -12
- package/skills/tfx-psmux-rules/SKILL.md.tmpl +0 -317
- package/skills/tfx-psmux-rules/skill.json +0 -8
- package/skills/tfx-qa/skill.json +0 -11
- package/skills/tfx-ralph/SKILL.md.tmpl +0 -27
- package/skills/tfx-ralph/skill.json +0 -8
- package/skills/tfx-remote-setup/SKILL.md.tmpl +0 -576
- package/skills/tfx-remote-setup/skill.json +0 -8
- package/skills/tfx-remote-spawn/SKILL.md.tmpl +0 -263
- package/skills/tfx-remote-spawn/skill.json +0 -9
- package/skills/tfx-research/skill.json +0 -13
- package/skills/tfx-review/skill.json +0 -11
- package/skills/tfx-setup/SKILL.md.tmpl +0 -380
- package/skills/tfx-setup/skill.json +0 -8
- package/skills/tfx-swarm/SKILL.md.tmpl +0 -154
- package/skills/tfx-swarm/skill.json +0 -5
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// mcp-gateway-config.mjs — Claude Code MCP stdio↔SSE 전환
|
|
3
|
+
// Usage: node mcp-gateway-config.mjs --enable # stdio → SSE
|
|
4
|
+
// node mcp-gateway-config.mjs --disable # SSE → stdio (복원)
|
|
5
|
+
|
|
6
|
+
import { execSync } from 'node:child_process';
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
import { isServerEnabled } from './lib/mcp-manifest.mjs';
|
|
11
|
+
|
|
12
|
+
const BACKUP_FILE = join(homedir(), '.claude', 'cache', 'mcp-pre-gateway.json');
|
|
13
|
+
|
|
14
|
+
export const GATEWAY_SERVERS = [
|
|
15
|
+
{ name: 'context7', port: 8100, stdioCmd: 'cmd /c npx -y @upstash/context7-mcp@latest' },
|
|
16
|
+
{ name: 'brave-search', port: 8101, stdioCmd: 'cmd /c npx -y @brave/brave-search-mcp-server' },
|
|
17
|
+
{ name: 'exa', port: 8102, stdioCmd: 'cmd /c npx -y exa-mcp-server' },
|
|
18
|
+
{ name: 'tavily', port: 8103, stdioCmd: 'cmd /c npx -y tavily-mcp@latest' },
|
|
19
|
+
{ name: 'jira', port: 8104, stdioCmd: 'cmd /c npx -y mcp-jira-cloud@latest' },
|
|
20
|
+
{ name: 'serena', port: 8105, stdioCmd: 'uvx --from git+https://github.com/oraios/serena serena start-mcp-server' },
|
|
21
|
+
{ name: 'notion', port: 8106, stdioCmd: 'cmd /c npx -y @notionhq/notion-mcp-server' },
|
|
22
|
+
{ name: 'notion-guest', port: 8107, stdioCmd: 'cmd /c npx -y @notionhq/notion-mcp-server' },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const SKIP_SERVERS = new Set([
|
|
26
|
+
'playwright',
|
|
27
|
+
'claude.ai Notion',
|
|
28
|
+
'plugin:oh-my-claudecode:t',
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
// Git Bash에서 /c → C:/ 경로 변환 방지
|
|
32
|
+
const EXEC_ENV = { ...process.env, MSYS_NO_PATHCONV: '1' };
|
|
33
|
+
|
|
34
|
+
function run(cmd) {
|
|
35
|
+
try {
|
|
36
|
+
execSync(cmd, { stdio: 'pipe', encoding: 'utf8', timeout: 15000, env: EXEC_ENV });
|
|
37
|
+
return true;
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function removeMcp(name) {
|
|
44
|
+
run(`claude mcp remove "${name}" -s user`);
|
|
45
|
+
run(`claude mcp remove "${name}" -s local`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── 스냅샷: enable 전 기존 MCP 설정 백업 ──
|
|
49
|
+
|
|
50
|
+
function captureCurrentMcpState() {
|
|
51
|
+
const servers = {};
|
|
52
|
+
for (const { name } of GATEWAY_SERVERS) {
|
|
53
|
+
if (SKIP_SERVERS.has(name)) continue;
|
|
54
|
+
// claude mcp get으로 현재 등록 상태 확인
|
|
55
|
+
try {
|
|
56
|
+
const out = execSync(`claude mcp get "${name}" -s user`, {
|
|
57
|
+
stdio: 'pipe', encoding: 'utf8', timeout: 5000, env: EXEC_ENV,
|
|
58
|
+
}).trim();
|
|
59
|
+
servers[name] = { scope: 'user', raw: out };
|
|
60
|
+
} catch {
|
|
61
|
+
// user에 없으면 local 확인
|
|
62
|
+
try {
|
|
63
|
+
const out = execSync(`claude mcp get "${name}" -s local`, {
|
|
64
|
+
stdio: 'pipe', encoding: 'utf8', timeout: 5000, env: EXEC_ENV,
|
|
65
|
+
}).trim();
|
|
66
|
+
servers[name] = { scope: 'local', raw: out };
|
|
67
|
+
} catch {
|
|
68
|
+
servers[name] = null; // 기존에 없었음
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return servers;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function saveBackup(servers) {
|
|
76
|
+
const dir = dirname(BACKUP_FILE);
|
|
77
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
78
|
+
const backup = { captured_at: new Date().toISOString(), servers };
|
|
79
|
+
writeFileSync(BACKUP_FILE, JSON.stringify(backup, null, 2));
|
|
80
|
+
console.log(` [BACKUP] ${BACKUP_FILE}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function loadBackup() {
|
|
84
|
+
if (!existsSync(BACKUP_FILE)) return null;
|
|
85
|
+
try {
|
|
86
|
+
return JSON.parse(readFileSync(BACKUP_FILE, 'utf8'));
|
|
87
|
+
} catch { return null; }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── enable: 스냅샷 → remove → SSE add (실패 시 rollback) ──
|
|
91
|
+
|
|
92
|
+
function enableSse() {
|
|
93
|
+
console.log('Switching MCP servers to SSE mode...\n');
|
|
94
|
+
|
|
95
|
+
// 1) 현재 상태 스냅샷
|
|
96
|
+
const snapshot = captureCurrentMcpState();
|
|
97
|
+
saveBackup(snapshot);
|
|
98
|
+
|
|
99
|
+
let ok = 0;
|
|
100
|
+
let fail = 0;
|
|
101
|
+
|
|
102
|
+
for (const { name, port } of GATEWAY_SERVERS) {
|
|
103
|
+
if (SKIP_SERVERS.has(name)) continue;
|
|
104
|
+
if (!isServerEnabled(name)) {
|
|
105
|
+
console.log(` [SKIP] ${name} — manifest에서 비활성`);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
removeMcp(name);
|
|
110
|
+
const url = `http://localhost:${port}/sse`;
|
|
111
|
+
const success = run(`claude mcp add --transport sse -s user "${name}" ${url}`);
|
|
112
|
+
|
|
113
|
+
if (success) {
|
|
114
|
+
console.log(` [SSE] ${name} → ${url}`);
|
|
115
|
+
ok++;
|
|
116
|
+
} else {
|
|
117
|
+
// add 실패 → 원본 복원 시도
|
|
118
|
+
console.error(` [FAIL] ${name} — rollback 시도`);
|
|
119
|
+
const orig = snapshot[name];
|
|
120
|
+
if (orig) {
|
|
121
|
+
// H1 fix: orig.raw를 shell-escape하여 injection 방지
|
|
122
|
+
const safeRaw = (orig.raw || '').replace(/[;`$(){}|&<>]/g, '');
|
|
123
|
+
const restored = safeRaw ? run(`claude mcp add "${name}" -s ${orig.scope} -- ${safeRaw}`) : false;
|
|
124
|
+
console.error(` [ROLLBACK] ${name}: ${restored ? 'ok' : 'FAIL'}`);
|
|
125
|
+
}
|
|
126
|
+
fail++;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
console.log(`\nDone: ${ok} switched, ${fail} failed`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ── disable: 백업에서 서버별 원복 ──
|
|
134
|
+
|
|
135
|
+
function disableSse() {
|
|
136
|
+
console.log('Restoring MCP servers from backup...\n');
|
|
137
|
+
const backup = loadBackup();
|
|
138
|
+
|
|
139
|
+
// C1 fix: 백업 없으면 전체 삭제 방지
|
|
140
|
+
if (!backup) {
|
|
141
|
+
console.error('No backup found — cannot restore. Run --enable first to create a backup.');
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let ok = 0;
|
|
146
|
+
let fail = 0;
|
|
147
|
+
|
|
148
|
+
for (const { name, stdioCmd } of GATEWAY_SERVERS) {
|
|
149
|
+
if (SKIP_SERVERS.has(name)) continue;
|
|
150
|
+
|
|
151
|
+
const orig = backup.servers?.[name];
|
|
152
|
+
|
|
153
|
+
if (orig === null || orig === undefined) {
|
|
154
|
+
// 기존에 없었던 서버 → triflux가 추가한 것 → remove만
|
|
155
|
+
removeMcp(name);
|
|
156
|
+
console.log(` [REMOVE] ${name} — triflux가 추가한 서버, 원본 없음`);
|
|
157
|
+
ok++;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// H2 fix: 백업의 scope/raw를 사용하여 원본 복원, fallback으로 stdioCmd
|
|
162
|
+
removeMcp(name);
|
|
163
|
+
const restoreScope = orig.scope || 'user';
|
|
164
|
+
const restoreCmd = orig.raw && orig.raw.trim() ? orig.raw.trim() : stdioCmd;
|
|
165
|
+
const success = run(`claude mcp add "${name}" -s ${restoreScope} -- ${restoreCmd}`);
|
|
166
|
+
|
|
167
|
+
if (success) {
|
|
168
|
+
console.log(` [RESTORE] ${name} → scope=${restoreScope}`);
|
|
169
|
+
ok++;
|
|
170
|
+
} else {
|
|
171
|
+
// fallback: stdioCmd로 재시도
|
|
172
|
+
const fallback = run(`claude mcp add "${name}" -s user -- ${stdioCmd}`);
|
|
173
|
+
if (fallback) {
|
|
174
|
+
console.log(` [FALLBACK] ${name} → stdio (원본 복원 실패, 기본값 사용)`);
|
|
175
|
+
ok++;
|
|
176
|
+
} else {
|
|
177
|
+
console.error(` [FAIL] ${name}`);
|
|
178
|
+
fail++;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
console.log(`\nDone: ${ok} restored, ${fail} failed`);
|
|
184
|
+
console.log(`Backup preserved at: ${BACKUP_FILE}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function printUsage() {
|
|
188
|
+
console.log(`Usage: node mcp-gateway-config.mjs [--enable|--disable]
|
|
189
|
+
|
|
190
|
+
--enable Switch Claude Code MCP servers from stdio to SSE (supergateway)
|
|
191
|
+
--disable Restore Claude Code MCP servers to original stdio mode
|
|
192
|
+
|
|
193
|
+
Servers managed: ${GATEWAY_SERVERS.map((s) => s.name).join(', ')}
|
|
194
|
+
Servers skipped: ${[...SKIP_SERVERS].join(', ')}`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ── main ──
|
|
198
|
+
const flag = process.argv[2];
|
|
199
|
+
|
|
200
|
+
if (flag === '--enable') {
|
|
201
|
+
enableSse();
|
|
202
|
+
} else if (flag === '--disable') {
|
|
203
|
+
disableSse();
|
|
204
|
+
} else {
|
|
205
|
+
printUsage();
|
|
206
|
+
process.exit(flag ? 1 : 0);
|
|
207
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// mcp-gateway-ensure.mjs — SessionStart 훅에서 supergateway MCP 서비스 보장
|
|
3
|
+
// hub-ensure.mjs 패턴을 따름. 가볍게 헬스체크만 수행하고 필요시 기동.
|
|
4
|
+
|
|
5
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
6
|
+
import { join, dirname } from 'node:path';
|
|
7
|
+
import { execSync } from 'node:child_process';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
|
|
11
|
+
const PLUGIN_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
12
|
+
const PID_FILE = join(tmpdir(), 'tfx-gateway-pids.json');
|
|
13
|
+
const PROBE_PORT = 8100; // context7 — 첫 번째 게이트웨이 포트로 alive 프로브
|
|
14
|
+
const PROBE_TIMEOUT_MS = 1500;
|
|
15
|
+
const STARTUP_WAIT_MS = 4000;
|
|
16
|
+
const POLL_INTERVAL_MS = 500;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 단일 포트 /healthz 프로브로 게이트웨이 클러스터 alive 판정.
|
|
20
|
+
* 모든 포트를 체크하면 hook timeout(8s)에 걸리므로 대표 포트 1개만 확인.
|
|
21
|
+
*/
|
|
22
|
+
async function isGatewayAlive() {
|
|
23
|
+
try {
|
|
24
|
+
const res = await fetch(`http://127.0.0.1:${PROBE_PORT}/healthz`, {
|
|
25
|
+
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),
|
|
26
|
+
});
|
|
27
|
+
return res.ok;
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** 매니페스트 파일 존재 여부로 gateway 설치 판정 (빠른 경로) */
|
|
34
|
+
function hasManifest() {
|
|
35
|
+
return existsSync(PID_FILE);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** mcp-gateway-start.mjs를 독립 프로세스로 기동 */
|
|
39
|
+
function startGateway() {
|
|
40
|
+
const scriptPath = join(PLUGIN_ROOT, 'scripts', 'mcp-gateway-start.mjs');
|
|
41
|
+
if (!existsSync(scriptPath)) return false;
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
// PowerShell Start-Process: Windows Job Object에서 벗어나 부모 종료 후 생존
|
|
45
|
+
execSync(
|
|
46
|
+
`powershell -NoProfile -Command "Start-Process -WindowStyle Hidden -FilePath '${process.execPath}' -ArgumentList '${scriptPath.replaceAll("'", "''")}'"`
|
|
47
|
+
, { stdio: 'ignore', timeout: 10000 });
|
|
48
|
+
return true;
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** 게이트웨이 기동 후 프로브 포트 ready 대기 */
|
|
55
|
+
async function waitForGatewayReady(maxWaitMs = STARTUP_WAIT_MS) {
|
|
56
|
+
const deadline = Date.now() + maxWaitMs;
|
|
57
|
+
while (Date.now() < deadline) {
|
|
58
|
+
if (await isGatewayAlive()) return true;
|
|
59
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── main ──
|
|
65
|
+
|
|
66
|
+
// 빠른 경로: 매니페스트 존재 + 프로브 포트 살아있으면 즉시 OK
|
|
67
|
+
if (hasManifest() && await isGatewayAlive()) {
|
|
68
|
+
process.stdout.write('gateway: ok');
|
|
69
|
+
process.exit(0);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 매니페스트 없으면 gateway가 설정되지 않은 상태 — 조용히 스킵
|
|
73
|
+
if (!hasManifest()) {
|
|
74
|
+
process.stdout.write('gateway: not configured');
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 느린 경로: 게이트웨이 기동 시도
|
|
79
|
+
const started = startGateway();
|
|
80
|
+
if (started) {
|
|
81
|
+
const ready = await waitForGatewayReady();
|
|
82
|
+
process.stdout.write(ready ? 'gateway: ok' : 'gateway: starting');
|
|
83
|
+
} else {
|
|
84
|
+
process.stderr.write('[gateway-ensure] start failed');
|
|
85
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// mcp-gateway-integration-test.mjs — P0 integration test for MCP Gateway
|
|
3
|
+
// Usage: node scripts/mcp-gateway-integration-test.mjs
|
|
4
|
+
|
|
5
|
+
import { execSync } from 'node:child_process';
|
|
6
|
+
import { join, dirname } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const SCRIPTS_DIR = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const START_SCRIPT = join(SCRIPTS_DIR, 'mcp-gateway-start.mjs');
|
|
11
|
+
const CONFIG_SCRIPT = join(SCRIPTS_DIR, 'mcp-gateway-config.mjs');
|
|
12
|
+
|
|
13
|
+
const HEALTH_TIMEOUT_MS = 3000;
|
|
14
|
+
const STARTUP_WAIT_MS = 12000;
|
|
15
|
+
const POLL_INTERVAL_MS = 500;
|
|
16
|
+
|
|
17
|
+
const SERVERS = [
|
|
18
|
+
{ name: 'context7', port: 8100 },
|
|
19
|
+
{ name: 'brave-search', port: 8101 },
|
|
20
|
+
{ name: 'exa', port: 8102 },
|
|
21
|
+
{ name: 'tavily', port: 8103 },
|
|
22
|
+
{ name: 'jira', port: 8104 },
|
|
23
|
+
{ name: 'serena', port: 8105 },
|
|
24
|
+
{ name: 'notion', port: 8106 },
|
|
25
|
+
{ name: 'notion-guest', port: 8107 },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
// ── utilities ──
|
|
29
|
+
|
|
30
|
+
function sleep(ms) {
|
|
31
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function checkHealth(port) {
|
|
35
|
+
try {
|
|
36
|
+
const res = await fetch(`http://127.0.0.1:${port}/healthz`, {
|
|
37
|
+
signal: AbortSignal.timeout(HEALTH_TIMEOUT_MS),
|
|
38
|
+
});
|
|
39
|
+
return res.ok;
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function runScript(scriptPath, ...args) {
|
|
46
|
+
execSync(`node "${scriptPath}" ${args.join(' ')}`, {
|
|
47
|
+
stdio: 'inherit',
|
|
48
|
+
timeout: 30000,
|
|
49
|
+
env: { ...process.env, MSYS_NO_PATHCONV: '1' },
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function countSupergateways() {
|
|
54
|
+
try {
|
|
55
|
+
// Write the query as a PS1 file to avoid shell quoting issues
|
|
56
|
+
const ps1 = [
|
|
57
|
+
`$procs = Get-CimInstance Win32_Process -Filter "Name='node.exe' OR Name='cmd.exe'"`,
|
|
58
|
+
`$hits = $procs | Where-Object { $_.CommandLine -match 'supergateway' }`,
|
|
59
|
+
`Write-Output $hits.Count`,
|
|
60
|
+
].join('\n');
|
|
61
|
+
const out = execSync(
|
|
62
|
+
`powershell -NoProfile -Command "${ps1.replace(/\n/g, '; ')}"`,
|
|
63
|
+
{ encoding: 'utf8', timeout: 10000, stdio: ['pipe', 'pipe', 'ignore'] },
|
|
64
|
+
);
|
|
65
|
+
return parseInt(out.trim(), 10) || 0;
|
|
66
|
+
} catch {
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ── result tracking ──
|
|
72
|
+
|
|
73
|
+
const results = [];
|
|
74
|
+
let passed = 0;
|
|
75
|
+
let failed = 0;
|
|
76
|
+
|
|
77
|
+
function pass(label) {
|
|
78
|
+
console.log(` [PASS] ${label}`);
|
|
79
|
+
results.push({ label, ok: true });
|
|
80
|
+
passed++;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function fail(label, detail = '') {
|
|
84
|
+
const msg = detail ? `${label} — ${detail}` : label;
|
|
85
|
+
console.log(` [FAIL] ${msg}`);
|
|
86
|
+
results.push({ label, ok: false, detail });
|
|
87
|
+
failed++;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function printSummary() {
|
|
91
|
+
console.log('\n' + '='.repeat(56));
|
|
92
|
+
console.log('Integration Test Summary');
|
|
93
|
+
console.log('='.repeat(56));
|
|
94
|
+
for (const r of results) {
|
|
95
|
+
const mark = r.ok ? '\u2713' : '\u2717';
|
|
96
|
+
const detail = r.detail ? ` (${r.detail})` : '';
|
|
97
|
+
console.log(` ${mark} ${r.label}${detail}`);
|
|
98
|
+
}
|
|
99
|
+
console.log('='.repeat(56));
|
|
100
|
+
const total = passed + failed;
|
|
101
|
+
console.log(`Result: ${passed}/${total} passed, ${failed} failed`);
|
|
102
|
+
if (failed > 0) {
|
|
103
|
+
console.log('\n[FAIL] Integration test FAILED');
|
|
104
|
+
process.exitCode = 1;
|
|
105
|
+
} else {
|
|
106
|
+
console.log('\n[PASS] Integration test PASSED');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ── main ──
|
|
111
|
+
|
|
112
|
+
async function main() {
|
|
113
|
+
console.log('\nMCP Gateway Integration Test');
|
|
114
|
+
console.log('='.repeat(56));
|
|
115
|
+
|
|
116
|
+
// STEP 1: Start gateways
|
|
117
|
+
console.log('\n[STEP 1] Starting gateways...');
|
|
118
|
+
try {
|
|
119
|
+
runScript(START_SCRIPT);
|
|
120
|
+
pass('Gateway start script ran without error');
|
|
121
|
+
} catch (err) {
|
|
122
|
+
fail('Gateway start script', err.message);
|
|
123
|
+
console.log('\n[ABORT] Cannot continue without gateways running');
|
|
124
|
+
printSummary();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// STEP 2: Wait for health checks to pass (up to 12s)
|
|
129
|
+
console.log('\n[STEP 2] Waiting for health checks (up to 12s)...');
|
|
130
|
+
const deadline = Date.now() + STARTUP_WAIT_MS;
|
|
131
|
+
const pending = new Set(SERVERS.map((s) => s.port));
|
|
132
|
+
|
|
133
|
+
while (pending.size > 0 && Date.now() < deadline) {
|
|
134
|
+
await sleep(POLL_INTERVAL_MS);
|
|
135
|
+
for (const port of [...pending]) {
|
|
136
|
+
if (await checkHealth(port)) pending.delete(port);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let healthOk = 0;
|
|
141
|
+
let healthSkipped = 0;
|
|
142
|
+
|
|
143
|
+
for (const srv of SERVERS) {
|
|
144
|
+
const alive = !pending.has(srv.port);
|
|
145
|
+
if (alive) {
|
|
146
|
+
console.log(` [ok] ${srv.name.padEnd(16)} :${srv.port}`);
|
|
147
|
+
healthOk++;
|
|
148
|
+
} else {
|
|
149
|
+
// Servers that stay down are expected when env vars (API keys) are missing
|
|
150
|
+
console.log(` [skip] ${srv.name.padEnd(16)} :${srv.port} (not running — likely missing env)`);
|
|
151
|
+
healthSkipped++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (healthOk === 0) {
|
|
156
|
+
fail('Health check — no servers responded', `0/${SERVERS.length} up`);
|
|
157
|
+
} else {
|
|
158
|
+
pass(`Health check — ${healthOk} server(s) responding (${healthSkipped} skipped)`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// STEP 3: Switch Claude Code config to SSE
|
|
162
|
+
console.log('\n[STEP 3] Switching Claude Code config to SSE mode...');
|
|
163
|
+
try {
|
|
164
|
+
runScript(CONFIG_SCRIPT, '--enable');
|
|
165
|
+
pass('Config switch to SSE (--enable)');
|
|
166
|
+
} catch (err) {
|
|
167
|
+
fail('Config switch to SSE', err.message);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// STEP 4: Verify SSE endpoints respond on each active port
|
|
171
|
+
console.log('\n[STEP 4] Verifying SSE endpoints (/healthz)...');
|
|
172
|
+
const sseResults = await Promise.allSettled(
|
|
173
|
+
SERVERS.map(async (srv) => ({ ...srv, alive: await checkHealth(srv.port) })),
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
let sseOk = 0;
|
|
177
|
+
for (const r of sseResults) {
|
|
178
|
+
if (r.status !== 'fulfilled') continue;
|
|
179
|
+
const { name, port, alive } = r.value;
|
|
180
|
+
if (alive) {
|
|
181
|
+
console.log(` [ok] ${name.padEnd(16)} :${port}`);
|
|
182
|
+
sseOk++;
|
|
183
|
+
} else {
|
|
184
|
+
console.log(` [skip] ${name.padEnd(16)} :${port} (not running)`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (sseOk === 0 && healthOk > 0) {
|
|
189
|
+
fail('SSE endpoint verification — servers went down after config switch');
|
|
190
|
+
} else if (sseOk > 0) {
|
|
191
|
+
pass(`SSE endpoint verification — ${sseOk} endpoint(s) healthy`);
|
|
192
|
+
} else {
|
|
193
|
+
pass('SSE endpoint verification — no servers running (all skipped due to missing env)');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// STEP 5: Restore stdio config
|
|
197
|
+
console.log('\n[STEP 5] Restoring stdio config...');
|
|
198
|
+
try {
|
|
199
|
+
runScript(CONFIG_SCRIPT, '--disable');
|
|
200
|
+
pass('Config restore to stdio (--disable)');
|
|
201
|
+
} catch (err) {
|
|
202
|
+
fail('Config restore to stdio', err.message);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// STEP 6: Stop gateways
|
|
206
|
+
console.log('\n[STEP 6] Stopping gateways...');
|
|
207
|
+
try {
|
|
208
|
+
runScript(START_SCRIPT, '--stop');
|
|
209
|
+
pass('Gateway stop script ran without error');
|
|
210
|
+
} catch (err) {
|
|
211
|
+
fail('Gateway stop script', err.message);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// STEP 7: Orphan check — brief settle, then verify no supergateway processes remain
|
|
215
|
+
console.log('\n[STEP 7] Checking for orphan supergateway processes...');
|
|
216
|
+
await sleep(2000);
|
|
217
|
+
|
|
218
|
+
const orphanCount = countSupergateways();
|
|
219
|
+
if (orphanCount === 0) {
|
|
220
|
+
pass('No orphan supergateway processes (WMI/tasklist clean)');
|
|
221
|
+
} else {
|
|
222
|
+
fail('Orphan processes found', `${orphanCount} supergateway process(es) still running`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
printSummary();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
main();
|