triflux 10.3.4 → 10.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/bin/tfx-doctor-tui.mjs +1 -1
- package/bin/tfx-doctor.mjs +6 -1
- package/bin/tfx-profile.mjs +1 -1
- package/bin/tfx-setup-tui.mjs +1 -1
- package/bin/tfx-setup.mjs +6 -1
- package/bin/triflux.mjs +2396 -1140
- package/hooks/agent-route-guard.mjs +12 -8
- package/hooks/cross-review-tracker.mjs +21 -8
- package/hooks/error-context.mjs +19 -7
- package/hooks/hook-adaptive-collector.mjs +18 -16
- package/hooks/hook-manager.mjs +93 -32
- package/hooks/hook-orchestrator.mjs +108 -24
- package/hooks/hook-registry.json +11 -0
- package/hooks/keyword-rules.json +6 -10
- package/hooks/lib/resolve-root.mjs +1 -1
- package/hooks/mcp-config-watcher.mjs +6 -2
- package/hooks/pipeline-stop.mjs +3 -6
- package/hooks/safety-guard.mjs +99 -28
- package/hooks/session-start-fast.mjs +143 -0
- package/hooks/subagent-verifier.mjs +5 -4
- package/hub/account-broker.mjs +256 -60
- package/hub/adaptive-diagnostic.mjs +75 -48
- package/hub/adaptive-inject.mjs +95 -57
- package/hub/adaptive-memory.mjs +156 -42
- package/hub/adaptive.mjs +60 -31
- package/hub/assign-callbacks.mjs +67 -30
- package/hub/bridge.mjs +0 -1
- package/hub/cli-adapter-base.mjs +200 -48
- package/hub/codex-adapter.mjs +76 -96
- package/hub/codex-compat.mjs +3 -3
- package/hub/codex-preflight.mjs +63 -37
- package/hub/delegator/contracts.mjs +19 -23
- package/hub/delegator/index.mjs +3 -3
- package/hub/delegator/service.mjs +88 -64
- package/hub/delegator/tool-definitions.mjs +5 -5
- package/hub/fullcycle.mjs +33 -17
- package/hub/gemini-adapter.mjs +69 -94
- package/hub/hitl.mjs +89 -30
- package/hub/intent.mjs +161 -38
- package/hub/lib/cache-guard.mjs +43 -17
- package/hub/lib/mcp-response-cache.mjs +66 -32
- package/hub/lib/memory-store.mjs +285 -111
- package/hub/lib/path-utils.mjs +35 -37
- package/hub/lib/process-utils.mjs +106 -37
- package/hub/lib/spawn-trace.mjs +527 -0
- package/hub/lib/ssh-command.mjs +34 -4
- package/hub/lib/ssh-retry.mjs +5 -1
- package/hub/lib/uuidv7.mjs +4 -3
- package/hub/memory-doctor.mjs +266 -106
- package/hub/middleware/request-logger.mjs +61 -34
- package/hub/paths.mjs +9 -9
- package/hub/pipeline/gates/confidence.mjs +34 -15
- package/hub/pipeline/gates/consensus.mjs +27 -15
- package/hub/pipeline/gates/index.mjs +7 -3
- package/hub/pipeline/gates/selfcheck.mjs +57 -19
- package/hub/pipeline/index.mjs +77 -42
- package/hub/pipeline/state.mjs +10 -10
- package/hub/pipeline/transitions.mjs +40 -23
- package/hub/platform.mjs +57 -48
- package/hub/promote-penalties.mjs +25 -7
- package/hub/quality/deslop.mjs +70 -49
- package/hub/research.mjs +32 -25
- package/hub/router.mjs +240 -107
- package/hub/routing/complexity.mjs +132 -29
- package/hub/routing/index.mjs +17 -12
- package/hub/routing/q-learning.mjs +76 -28
- package/hub/server.mjs +4 -4
- package/hub/session-fingerprint.mjs +126 -60
- package/hub/state.mjs +84 -43
- package/hub/store-adapter.mjs +59 -26
- package/hub/store.mjs +356 -153
- package/hub/team/agent-map.json +22 -7
- package/hub/team/ansi.mjs +186 -122
- package/hub/team/backend.mjs +28 -10
- package/hub/team/cli/commands/attach.mjs +29 -9
- package/hub/team/cli/commands/control.mjs +29 -8
- package/hub/team/cli/commands/debug.mjs +32 -11
- package/hub/team/cli/commands/focus.mjs +38 -11
- package/hub/team/cli/commands/interrupt.mjs +18 -6
- package/hub/team/cli/commands/kill.mjs +16 -5
- package/hub/team/cli/commands/list.mjs +11 -4
- package/hub/team/cli/commands/send.mjs +19 -6
- package/hub/team/cli/commands/start/index.mjs +154 -31
- package/hub/team/cli/commands/start/parse-args.mjs +38 -11
- package/hub/team/cli/commands/start/start-headless.mjs +112 -36
- package/hub/team/cli/commands/start/start-in-process.mjs +12 -2
- package/hub/team/cli/commands/start/start-mux.mjs +70 -21
- package/hub/team/cli/commands/start/start-wt.mjs +29 -12
- package/hub/team/cli/commands/status.mjs +43 -14
- package/hub/team/cli/commands/stop.mjs +11 -4
- package/hub/team/cli/commands/task.mjs +8 -3
- package/hub/team/cli/commands/tasks.mjs +1 -1
- package/hub/team/cli/index.mjs +2 -2
- package/hub/team/cli/manifest.mjs +38 -8
- package/hub/team/cli/render.mjs +30 -8
- package/hub/team/cli/services/attach-fallback.mjs +31 -11
- package/hub/team/cli/services/hub-client.mjs +42 -14
- package/hub/team/cli/services/member-selector.mjs +11 -4
- package/hub/team/cli/services/native-control.mjs +48 -21
- package/hub/team/cli/services/runtime-mode.mjs +2 -1
- package/hub/team/cli/services/state-store.mjs +25 -8
- package/hub/team/cli/services/task-model.mjs +16 -6
- package/hub/team/conductor-mesh-bridge.mjs +24 -23
- package/hub/team/conductor.mjs +8 -4
- package/hub/team/dashboard-anchor.mjs +4 -5
- package/hub/team/dashboard-layout.mjs +3 -1
- package/hub/team/dashboard-open.mjs +41 -21
- package/hub/team/dashboard.mjs +76 -28
- package/hub/team/event-log.mjs +18 -10
- package/hub/team/handoff.mjs +31 -15
- package/hub/team/headless.mjs +2 -1
- package/hub/team/health-probe.mjs +69 -54
- package/hub/team/launcher-template.mjs +16 -13
- package/hub/team/native-supervisor.mjs +65 -21
- package/hub/team/native.mjs +74 -35
- package/hub/team/nativeProxy.mjs +184 -113
- package/hub/team/notify.mjs +119 -76
- package/hub/team/orchestrator.mjs +9 -4
- package/hub/team/pane.mjs +12 -7
- package/hub/team/process-cleanup.mjs +25 -16
- package/hub/team/psmux.mjs +491 -201
- package/hub/team/remote-probe.mjs +68 -52
- package/hub/team/remote-session.mjs +117 -59
- package/hub/team/remote-watcher.mjs +61 -33
- package/hub/team/routing.mjs +51 -25
- package/hub/team/runtime-strategy.mjs +3 -1
- package/hub/team/session.mjs +98 -34
- package/hub/team/staleState.mjs +72 -30
- package/hub/team/swarm-locks.mjs +15 -13
- package/hub/team/swarm-planner.mjs +32 -21
- package/hub/team/swarm-reconciler.mjs +48 -23
- package/hub/team/tui-lite.mjs +266 -68
- package/hub/team/tui-remote-adapter.mjs +14 -10
- package/hub/team/tui-viewer.mjs +99 -43
- package/hub/team/tui.mjs +708 -271
- package/hub/team/worktree-lifecycle.mjs +152 -58
- package/hub/team/wt-manager.mjs +24 -14
- package/hub/token-mode.mjs +71 -71
- package/hub/tray.mjs +66 -23
- package/hub/workers/claude-worker.mjs +162 -118
- package/hub/workers/codex-mcp.mjs +192 -141
- package/hub/workers/delegator-mcp.mjs +507 -333
- package/hub/workers/factory.mjs +8 -8
- package/hub/workers/gemini-worker.mjs +115 -84
- package/hub/workers/interface.mjs +6 -1
- package/hub/workers/worker-utils.mjs +21 -14
- package/hud/colors.mjs +27 -9
- package/hud/constants.mjs +162 -26
- package/hud/context-monitor.mjs +82 -41
- package/hud/hud-qos-status.mjs +129 -49
- package/hud/mission-board.mjs +6 -3
- package/hud/providers/claude.mjs +226 -115
- package/hud/providers/codex.mjs +62 -22
- package/hud/providers/gemini.mjs +168 -56
- package/hud/renderers.mjs +384 -119
- package/hud/terminal.mjs +101 -31
- package/hud/utils.mjs +78 -38
- package/mesh/index.mjs +11 -5
- package/mesh/mesh-budget.mjs +18 -9
- package/mesh/mesh-heartbeat.mjs +1 -1
- package/mesh/mesh-queue.mjs +3 -5
- package/mesh/mesh-router.mjs +5 -4
- package/package.json +2 -1
- package/scripts/__tests__/gen-skill-docs.test.mjs +36 -7
- package/scripts/__tests__/keyword-detector.test.mjs +77 -28
- package/scripts/__tests__/mcp-guard-engine.test.mjs +58 -20
- package/scripts/__tests__/remote-spawn-transfer.test.mjs +30 -19
- package/scripts/__tests__/remote-spawn.test.mjs +10 -4
- package/scripts/__tests__/session-start-fast.test.mjs +36 -0
- package/scripts/__tests__/skill-template.test.mjs +98 -50
- package/scripts/__tests__/smoke.test.mjs +1 -1
- package/scripts/__tests__/spawn-trace.test.mjs +102 -0
- package/scripts/__tests__/tfx-doctor-diagnose.test.mjs +48 -0
- package/scripts/cache-doctor.mjs +11 -4
- package/scripts/cache-warmup.mjs +96 -37
- package/scripts/claudemd-sync.mjs +27 -17
- package/scripts/codex-gateway-preflight.mjs +52 -37
- package/scripts/codex-mcp-gateway-sync.mjs +59 -39
- package/scripts/completions/tfx.bash +47 -47
- package/scripts/completions/tfx.fish +44 -44
- package/scripts/completions/tfx.zsh +83 -83
- package/scripts/config-audit.mjs +232 -0
- package/scripts/convert-to-tmpl.mjs +54 -0
- package/scripts/cross-review-gate.mjs +35 -12
- package/scripts/cross-review-tracker.mjs +21 -8
- package/scripts/demo.mjs +35 -17
- package/scripts/doctor-diagnose.mjs +284 -0
- package/scripts/gen-skill-docs.mjs +7 -2
- package/scripts/gen-skill-manifest.mjs +2 -1
- package/scripts/headless-guard.mjs +86 -48
- package/scripts/hub-ensure.mjs +45 -26
- package/scripts/keyword-detector.mjs +41 -20
- package/scripts/keyword-rules-expander.mjs +47 -30
- package/scripts/lib/claudemd-scanner.mjs +6 -1
- package/scripts/lib/context.mjs +3 -3
- package/scripts/lib/cross-review-utils.mjs +6 -3
- package/scripts/lib/env-probe.mjs +47 -28
- package/scripts/lib/gemini-profiles.mjs +44 -10
- package/scripts/lib/handoff.mjs +33 -17
- package/scripts/lib/hook-utils.mjs +8 -6
- package/scripts/lib/keyword-rules.mjs +43 -19
- package/scripts/lib/logger.mjs +24 -24
- package/scripts/lib/mcp-filter.mjs +377 -239
- package/scripts/lib/mcp-guard-engine.mjs +194 -79
- package/scripts/lib/mcp-manifest.mjs +23 -13
- package/scripts/lib/mcp-server-catalog.mjs +300 -63
- package/scripts/lib/psmux-info.mjs +11 -6
- package/scripts/lib/remote-spawn-transfer.mjs +44 -14
- package/scripts/lib/skill-template.mjs +30 -7
- package/scripts/mcp-check.mjs +58 -39
- package/scripts/mcp-gateway-config.mjs +83 -39
- package/scripts/mcp-gateway-ensure.mjs +43 -35
- package/scripts/mcp-gateway-integration-test.mjs +70 -58
- package/scripts/mcp-gateway-start.mjs +126 -60
- package/scripts/mcp-gateway-verify.mjs +24 -22
- package/scripts/mcp-safety-guard.mjs +44 -11
- package/scripts/notion-read.mjs +199 -84
- package/scripts/pack.mjs +94 -89
- package/scripts/preflight-cache.mjs +27 -10
- package/scripts/preinstall.mjs +42 -13
- package/scripts/remote-spawn.mjs +309 -94
- package/scripts/run.cjs +8 -5
- package/scripts/session-spawn-helper.mjs +130 -39
- package/scripts/session-stale-cleanup.mjs +123 -0
- package/scripts/setup.mjs +941 -492
- package/scripts/test-lock.mjs +20 -7
- package/scripts/test-tfx-route-no-claude-native.mjs +16 -12
- package/scripts/tfx-batch-stats.mjs +32 -11
- package/scripts/tfx-gate-activate.mjs +11 -4
- package/scripts/tfx-route-post.mjs +87 -20
- package/scripts/tfx-route-worker.mjs +57 -51
- package/scripts/tfx-route.sh +41 -124
- package/scripts/tmp-cleanup.mjs +21 -7
- package/scripts/token-snapshot.mjs +204 -85
- package/skills/.omc/state/agent-replay-8f0e10a9-9693-4410-96f5-a6b07e8ed995.jsonl +1 -0
- package/skills/.omc/state/idle-notif-cooldown.json +3 -0
- package/skills/.omc/state/last-tool-error.json +7 -0
- package/skills/.omc/state/subagent-tracking.json +7 -0
- package/skills/_templates/base.md +1 -6
- package/skills/merge-worktree/SKILL.md.tmpl +144 -0
- package/skills/shared/telemetry-segment.md +6 -0
- package/skills/star-prompt/SKILL.md.tmpl +222 -0
- package/skills/tfx-analysis/SKILL.md.tmpl +107 -0
- package/skills/tfx-analysis/skill.json +1 -6
- package/skills/tfx-auto/SKILL.md +1 -0
- package/skills/tfx-auto-codex/SKILL.md.tmpl +106 -0
- package/skills/tfx-auto-codex/skill.json +1 -3
- package/skills/tfx-autopilot/SKILL.md.tmpl +116 -0
- package/skills/tfx-autopilot/skill.json +1 -5
- package/skills/tfx-autoresearch/SKILL.md.tmpl +136 -0
- package/skills/tfx-autoroute/SKILL.md.tmpl +189 -0
- package/skills/tfx-autoroute/skill.json +1 -7
- package/skills/tfx-codex/SKILL.md +1 -0
- package/skills/tfx-codex/skill.json +1 -3
- package/skills/tfx-codex-swarm/SKILL.md.tmpl +16 -0
- package/skills/tfx-codex-swarm/evals/evals.json +1 -1
- package/skills/tfx-codex-swarm/skill.json +1 -4
- package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +54 -12
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +35 -7
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +35 -7
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +25 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +25 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +20 -4
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +16 -4
- package/skills/tfx-consensus/SKILL.md.tmpl +146 -0
- package/skills/tfx-debate/SKILL.md.tmpl +192 -0
- package/skills/tfx-debate/skill.json +1 -7
- package/skills/tfx-deep-analysis/SKILL.md.tmpl +228 -0
- package/skills/tfx-deep-analysis/skill.json +1 -5
- package/skills/tfx-deep-interview/SKILL.md.tmpl +203 -0
- package/skills/tfx-deep-plan/SKILL.md.tmpl +282 -0
- package/skills/tfx-deep-qa/SKILL.md.tmpl +165 -0
- package/skills/tfx-deep-qa/skill.json +1 -6
- package/skills/tfx-deep-research/SKILL.md.tmpl +217 -0
- package/skills/tfx-deep-review/SKILL.md.tmpl +179 -0
- package/skills/tfx-doctor/SKILL.md +21 -0
- package/skills/tfx-doctor/SKILL.md.tmpl +172 -0
- package/skills/tfx-doctor/skill.json +1 -3
- package/skills/tfx-find/SKILL.md +1 -0
- package/skills/tfx-forge/SKILL.md.tmpl +187 -0
- package/skills/tfx-fullcycle/SKILL.md.tmpl +286 -0
- package/skills/tfx-fullcycle/skill.json +1 -6
- package/skills/tfx-gemini/SKILL.md.tmpl +91 -0
- package/skills/tfx-gemini/skill.json +1 -3
- package/skills/tfx-hooks/SKILL.md.tmpl +216 -0
- package/skills/tfx-hooks/skill.json +1 -3
- package/skills/tfx-hub/SKILL.md.tmpl +212 -0
- package/skills/tfx-hub/skill.json +1 -3
- package/skills/tfx-index/SKILL.md +1 -0
- package/skills/tfx-index/skill.json +1 -6
- package/skills/tfx-interview/SKILL.md.tmpl +285 -0
- package/skills/tfx-multi/SKILL.md.tmpl +183 -0
- package/skills/tfx-multi/skill.json +1 -3
- package/skills/tfx-panel/SKILL.md.tmpl +189 -0
- package/skills/tfx-panel/skill.json +1 -7
- package/skills/tfx-persist/SKILL.md.tmpl +270 -0
- package/skills/tfx-persist/skill.json +1 -7
- package/skills/tfx-plan/SKILL.md +1 -0
- package/skills/tfx-plan/skill.json +1 -6
- package/skills/tfx-profile/SKILL.md.tmpl +239 -0
- package/skills/tfx-profile/skill.json +1 -3
- package/skills/tfx-prune/SKILL.md.tmpl +200 -0
- package/skills/tfx-prune/skill.json +1 -7
- package/skills/tfx-psmux-rules/SKILL.md.tmpl +326 -0
- package/skills/tfx-psmux-rules/skill.json +1 -4
- package/skills/tfx-qa/SKILL.md +1 -0
- package/skills/tfx-qa/skill.json +1 -6
- package/skills/tfx-ralph/SKILL.md.tmpl +28 -0
- package/skills/tfx-ralph/skill.json +1 -4
- package/skills/tfx-remote-setup/SKILL.md.tmpl +576 -0
- package/skills/tfx-remote-setup/skill.json +1 -3
- package/skills/tfx-remote-spawn/SKILL.md.tmpl +263 -0
- package/skills/tfx-remote-spawn/references/hosts.json +16 -0
- package/skills/tfx-remote-spawn/skill.json +1 -4
- package/skills/tfx-research/SKILL.md +1 -0
- package/skills/tfx-review/SKILL.md +1 -0
- package/skills/tfx-review/skill.json +1 -6
- package/skills/tfx-setup/SKILL.md.tmpl +504 -0
- package/skills/tfx-setup/skill.json +1 -3
- package/skills/tfx-swarm/SKILL.md +22 -0
- package/skills/tfx-swarm/SKILL.md.tmpl +218 -0
- package/tui/codex-profile.mjs +88 -33
- package/tui/core.mjs +45 -15
- package/tui/doctor.mjs +75 -28
- package/tui/gemini-profile.mjs +74 -29
- package/tui/monitor-data.mjs +8 -4
- package/tui/monitor.mjs +71 -27
- package/tui/setup.mjs +133 -42
package/scripts/cache-warmup.mjs
CHANGED
|
@@ -1,25 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
3
4
|
import {
|
|
4
5
|
existsSync,
|
|
5
6
|
mkdirSync,
|
|
6
|
-
readFileSync,
|
|
7
7
|
readdirSync,
|
|
8
|
+
readFileSync,
|
|
8
9
|
statSync,
|
|
9
10
|
writeFileSync,
|
|
10
11
|
} from "node:fs";
|
|
11
|
-
import { execSync } from "node:child_process";
|
|
12
|
-
import { join, basename, dirname } from "node:path";
|
|
13
12
|
import { homedir } from "node:os";
|
|
13
|
+
import { basename, dirname, join } from "node:path";
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
|
-
|
|
15
|
+
import {
|
|
16
|
+
checkCliSync,
|
|
17
|
+
checkHub,
|
|
18
|
+
detectCodexAuthState,
|
|
19
|
+
} from "./lib/env-probe.mjs";
|
|
20
|
+
import {
|
|
21
|
+
MCP_SERVER_DOMAIN_TAGS,
|
|
22
|
+
SEARCH_SERVER_ORDER,
|
|
23
|
+
} from "./lib/mcp-server-catalog.mjs";
|
|
16
24
|
import { readPreflightCache } from "./preflight-cache.mjs";
|
|
17
|
-
import { checkCliSync, checkHub, detectCodexAuthState } from "./lib/env-probe.mjs";
|
|
18
|
-
import { SEARCH_SERVER_ORDER, MCP_SERVER_DOMAIN_TAGS } from "./lib/mcp-server-catalog.mjs";
|
|
19
25
|
|
|
20
26
|
export const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
21
27
|
const WARMUP_METADATA_FILE = ["state", "warmup-metadata.json"];
|
|
22
|
-
const AUTH_SENSITIVE_TARGETS = new Set([
|
|
28
|
+
const AUTH_SENSITIVE_TARGETS = new Set([
|
|
29
|
+
"codexSkills",
|
|
30
|
+
"tierEnvironment",
|
|
31
|
+
"searchEngines",
|
|
32
|
+
]);
|
|
23
33
|
|
|
24
34
|
export const CACHE_TARGETS = Object.freeze({
|
|
25
35
|
codexSkills: Object.freeze({
|
|
@@ -118,7 +128,7 @@ function isFresh(target, options = {}) {
|
|
|
118
128
|
const ttlMs = resolveTtlMs(target, options);
|
|
119
129
|
const now = options.now ?? Date.now();
|
|
120
130
|
const stat = statSync(filePath);
|
|
121
|
-
return ttlMs > 0 &&
|
|
131
|
+
return ttlMs > 0 && now - stat.mtimeMs < ttlMs;
|
|
122
132
|
} catch {
|
|
123
133
|
return false;
|
|
124
134
|
}
|
|
@@ -138,7 +148,8 @@ function parseSkillFrontmatter(content) {
|
|
|
138
148
|
|
|
139
149
|
const frontmatter = match[1];
|
|
140
150
|
const name = frontmatter.match(/^name:\s*(.+)$/m)?.[1]?.trim() || null;
|
|
141
|
-
const description =
|
|
151
|
+
const description =
|
|
152
|
+
frontmatter.match(/^description:\s*(.+)$/m)?.[1]?.trim() || null;
|
|
142
153
|
return name ? { name, description } : null;
|
|
143
154
|
}
|
|
144
155
|
|
|
@@ -179,10 +190,18 @@ export function scanCodexSkills(options = {}) {
|
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
const builtinSkills = [
|
|
182
|
-
{
|
|
193
|
+
{
|
|
194
|
+
name: "web-clone",
|
|
195
|
+
role: "general",
|
|
196
|
+
description: "Clone and analyze web pages",
|
|
197
|
+
},
|
|
183
198
|
{ name: "help", role: "general", description: "Show available commands" },
|
|
184
199
|
{ name: "note", role: "general", description: "Save notes during session" },
|
|
185
|
-
{
|
|
200
|
+
{
|
|
201
|
+
name: "worker",
|
|
202
|
+
role: "auto",
|
|
203
|
+
description: "Spawn background worker for tasks",
|
|
204
|
+
},
|
|
186
205
|
];
|
|
187
206
|
|
|
188
207
|
for (const builtin of builtinSkills) {
|
|
@@ -207,15 +226,21 @@ export function probeTierEnvironment(options = {}) {
|
|
|
207
226
|
const execSyncFn = options.execSyncFn || execSync;
|
|
208
227
|
const codexAuth = preflight?.codex_plan ?? detectCodexAuthState({ homeDir });
|
|
209
228
|
|
|
210
|
-
const codexCheck =
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
229
|
+
const codexCheck =
|
|
230
|
+
preflight?.codex ||
|
|
231
|
+
checkCliSync("codex", { whichCommandFn: options.whichCommandFn });
|
|
232
|
+
const geminiCheck =
|
|
233
|
+
preflight?.gemini ||
|
|
234
|
+
checkCliSync("gemini", { whichCommandFn: options.whichCommandFn });
|
|
235
|
+
const hubCheck =
|
|
236
|
+
preflight?.hub ||
|
|
237
|
+
checkHub({
|
|
238
|
+
pkgRoot: options.pkgRoot,
|
|
239
|
+
restart: options.hubRestart === true,
|
|
240
|
+
requestTimeoutMs: options.hubTimeoutMs ?? 1000,
|
|
241
|
+
pollAttempts: options.hubRestart === true ? 8 : 0,
|
|
242
|
+
execSyncFn,
|
|
243
|
+
});
|
|
219
244
|
const checks = {
|
|
220
245
|
psmux: false,
|
|
221
246
|
hub: !!hubCheck?.ok,
|
|
@@ -246,7 +271,8 @@ export function probeTierEnvironment(options = {}) {
|
|
|
246
271
|
|
|
247
272
|
let tier = "minimal";
|
|
248
273
|
if (checks.codex || checks.gemini) tier = "standard";
|
|
249
|
-
if (checks.psmux && checks.hub && (checks.codex || checks.gemini))
|
|
274
|
+
if (checks.psmux && checks.hub && (checks.codex || checks.gemini))
|
|
275
|
+
tier = "full";
|
|
250
276
|
|
|
251
277
|
const agents = ["claude"];
|
|
252
278
|
if (checks.codex) agents.push("codex");
|
|
@@ -257,9 +283,10 @@ export function probeTierEnvironment(options = {}) {
|
|
|
257
283
|
tier,
|
|
258
284
|
checks,
|
|
259
285
|
available_agents: agents,
|
|
260
|
-
codex_plan:
|
|
261
|
-
|
|
262
|
-
|
|
286
|
+
codex_plan:
|
|
287
|
+
codexAuth.source == null
|
|
288
|
+
? { plan: codexAuth.plan }
|
|
289
|
+
: { plan: codexAuth.plan, source: codexAuth.source },
|
|
263
290
|
source: {
|
|
264
291
|
preflight: !!preflight,
|
|
265
292
|
home_dir: homeDir,
|
|
@@ -272,13 +299,15 @@ function getCodexAuthFingerprint(options = {}) {
|
|
|
272
299
|
if (typeof options.preflight?.codex_plan?.fingerprint === "string") {
|
|
273
300
|
return options.preflight.codex_plan.fingerprint;
|
|
274
301
|
}
|
|
275
|
-
return detectCodexAuthState({ homeDir: resolveHomeDir(options.homeDir) })
|
|
302
|
+
return detectCodexAuthState({ homeDir: resolveHomeDir(options.homeDir) })
|
|
303
|
+
.fingerprint;
|
|
276
304
|
}
|
|
277
305
|
|
|
278
306
|
function hasAuthFingerprintChanged(target, options = {}) {
|
|
279
307
|
if (!AUTH_SENSITIVE_TARGETS.has(target)) return false;
|
|
280
308
|
const nextFingerprint = getCodexAuthFingerprint(options);
|
|
281
|
-
const previousFingerprint =
|
|
309
|
+
const previousFingerprint =
|
|
310
|
+
readWarmupMetadata(options)?.codex_auth_fingerprint || null;
|
|
282
311
|
if (previousFingerprint === null) return false;
|
|
283
312
|
return previousFingerprint !== nextFingerprint;
|
|
284
313
|
}
|
|
@@ -314,7 +343,10 @@ export function extractProjectMeta(options = {}) {
|
|
|
314
343
|
testCmd = pkg.scripts?.test || null;
|
|
315
344
|
lang = "JavaScript/ESM (Node.js)";
|
|
316
345
|
} catch {}
|
|
317
|
-
} else if (
|
|
346
|
+
} else if (
|
|
347
|
+
existsSync(join(cwd, "pyproject.toml")) ||
|
|
348
|
+
existsSync(join(cwd, "setup.py"))
|
|
349
|
+
) {
|
|
318
350
|
lang = "Python";
|
|
319
351
|
} else if (existsSync(join(cwd, "Cargo.toml"))) {
|
|
320
352
|
lang = "Rust";
|
|
@@ -333,7 +365,12 @@ export function extractProjectMeta(options = {}) {
|
|
|
333
365
|
}
|
|
334
366
|
|
|
335
367
|
function loadMcpInventory(options = {}) {
|
|
336
|
-
const inventoryPath = join(
|
|
368
|
+
const inventoryPath = join(
|
|
369
|
+
resolveHomeDir(options.homeDir),
|
|
370
|
+
".claude",
|
|
371
|
+
"cache",
|
|
372
|
+
"mcp-inventory.json",
|
|
373
|
+
);
|
|
337
374
|
try {
|
|
338
375
|
return JSON.parse(readFileSync(inventoryPath, "utf8"));
|
|
339
376
|
} catch {
|
|
@@ -372,7 +409,8 @@ function loadMcpConfigs(options = {}) {
|
|
|
372
409
|
|
|
373
410
|
export function checkSearchEngines(options = {}) {
|
|
374
411
|
const inventory = options.inventory ?? loadMcpInventory(options);
|
|
375
|
-
const configuredServers =
|
|
412
|
+
const configuredServers =
|
|
413
|
+
options.configuredServers ?? loadMcpConfigs(options);
|
|
376
414
|
const engines = [];
|
|
377
415
|
|
|
378
416
|
const knownSearchServers = [...SEARCH_SERVER_ORDER, "context7"];
|
|
@@ -383,8 +421,13 @@ export function checkSearchEngines(options = {}) {
|
|
|
383
421
|
const scopeData = inventory[scope];
|
|
384
422
|
if (!scopeData?.servers) continue;
|
|
385
423
|
for (const server of scopeData.servers) {
|
|
386
|
-
const tags =
|
|
387
|
-
|
|
424
|
+
const tags =
|
|
425
|
+
server.domain_tags || MCP_SERVER_DOMAIN_TAGS[server.name] || [];
|
|
426
|
+
if (
|
|
427
|
+
tags.includes("search") ||
|
|
428
|
+
tags.includes("web") ||
|
|
429
|
+
tags.includes("research")
|
|
430
|
+
) {
|
|
388
431
|
allServerNames.add(server.name);
|
|
389
432
|
}
|
|
390
433
|
}
|
|
@@ -393,7 +436,11 @@ export function checkSearchEngines(options = {}) {
|
|
|
393
436
|
|
|
394
437
|
for (const name of Object.keys(configuredServers)) {
|
|
395
438
|
const tags = MCP_SERVER_DOMAIN_TAGS[name] || [];
|
|
396
|
-
if (
|
|
439
|
+
if (
|
|
440
|
+
tags.includes("search") ||
|
|
441
|
+
tags.includes("web") ||
|
|
442
|
+
knownSearchServers.includes(name)
|
|
443
|
+
) {
|
|
397
444
|
allServerNames.add(name);
|
|
398
445
|
}
|
|
399
446
|
}
|
|
@@ -405,7 +452,9 @@ export function checkSearchEngines(options = {}) {
|
|
|
405
452
|
let inventoryStatus = null;
|
|
406
453
|
if (inventory) {
|
|
407
454
|
for (const scope of ["codex", "gemini", "claude"]) {
|
|
408
|
-
const server = inventory[scope]?.servers?.find(
|
|
455
|
+
const server = inventory[scope]?.servers?.find(
|
|
456
|
+
(item) => item.name === name,
|
|
457
|
+
);
|
|
409
458
|
if (server) {
|
|
410
459
|
inventoryStatus = {
|
|
411
460
|
scope,
|
|
@@ -418,7 +467,10 @@ export function checkSearchEngines(options = {}) {
|
|
|
418
467
|
}
|
|
419
468
|
|
|
420
469
|
let status = "unavailable";
|
|
421
|
-
if (
|
|
470
|
+
if (
|
|
471
|
+
inventoryStatus?.status === "enabled" ||
|
|
472
|
+
inventoryStatus?.status === "configured"
|
|
473
|
+
) {
|
|
422
474
|
status = "available";
|
|
423
475
|
} else if (configured) {
|
|
424
476
|
status = "configured";
|
|
@@ -456,13 +508,18 @@ export function checkSearchEngines(options = {}) {
|
|
|
456
508
|
|
|
457
509
|
function buildTarget(target, options = {}) {
|
|
458
510
|
const filePath = resolveTargetPath(target, options);
|
|
459
|
-
if (
|
|
511
|
+
if (
|
|
512
|
+
!options.force &&
|
|
513
|
+
isFresh(target, options) &&
|
|
514
|
+
!hasAuthFingerprintChanged(target, options)
|
|
515
|
+
) {
|
|
460
516
|
return { target, status: "skipped", file: filePath, reason: "fresh" };
|
|
461
517
|
}
|
|
462
518
|
|
|
463
519
|
let payload;
|
|
464
520
|
if (target === "codexSkills") payload = scanCodexSkills(options);
|
|
465
|
-
else if (target === "tierEnvironment")
|
|
521
|
+
else if (target === "tierEnvironment")
|
|
522
|
+
payload = probeTierEnvironment(options);
|
|
466
523
|
else if (target === "projectMeta") payload = extractProjectMeta(options);
|
|
467
524
|
else if (target === "searchEngines") payload = checkSearchEngines(options);
|
|
468
525
|
else throw new Error(`unknown cache target: ${target}`);
|
|
@@ -508,7 +565,9 @@ export function buildAll(options = {}) {
|
|
|
508
565
|
}
|
|
509
566
|
|
|
510
567
|
const built = results.filter((result) => result.status === "built").length;
|
|
511
|
-
const skipped = results.filter(
|
|
568
|
+
const skipped = results.filter(
|
|
569
|
+
(result) => result.status === "skipped",
|
|
570
|
+
).length;
|
|
512
571
|
const failed = results.filter((result) => result.status === "failed").length;
|
|
513
572
|
const authFingerprint = getCodexAuthFingerprint(options);
|
|
514
573
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
2
3
|
import { join, resolve } from "node:path";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import {
|
|
5
|
-
import { TFX_START, OMC_END, writeSection } from "./lib/claudemd-scanner.mjs";
|
|
5
|
+
import { OMC_END, TFX_START, writeSection } from "./lib/claudemd-scanner.mjs";
|
|
6
6
|
|
|
7
7
|
const PKG_ROOT = fileURLToPath(new URL("..", import.meta.url));
|
|
8
8
|
const GLOBAL_CLAUDE_MD_PATH = join(homedir(), ".claude", "CLAUDE.md");
|
|
@@ -29,7 +29,10 @@ function findRoutingSection(markdown) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// Legacy heading fallback
|
|
32
|
-
const headingPattern = new RegExp(
|
|
32
|
+
const headingPattern = new RegExp(
|
|
33
|
+
`(^|\\n)${ROUTING_SECTION_HEADING.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}(?=\\n|$)`,
|
|
34
|
+
"u",
|
|
35
|
+
);
|
|
33
36
|
const match = headingPattern.exec(content);
|
|
34
37
|
|
|
35
38
|
if (!match) {
|
|
@@ -37,8 +40,12 @@ function findRoutingSection(markdown) {
|
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
const startIndex = match.index + match[1].length;
|
|
40
|
-
const nextHeadingIndex = content.indexOf(
|
|
41
|
-
|
|
43
|
+
const nextHeadingIndex = content.indexOf(
|
|
44
|
+
"\n## ",
|
|
45
|
+
startIndex + ROUTING_SECTION_HEADING.length,
|
|
46
|
+
);
|
|
47
|
+
const endIndex =
|
|
48
|
+
nextHeadingIndex === -1 ? content.length : nextHeadingIndex + 1;
|
|
42
49
|
|
|
43
50
|
return {
|
|
44
51
|
found: true,
|
|
@@ -66,7 +73,11 @@ function buildNextMarkdown(currentMarkdown, routingSection) {
|
|
|
66
73
|
return nextSection;
|
|
67
74
|
}
|
|
68
75
|
|
|
69
|
-
const separator = current.endsWith("\n\n")
|
|
76
|
+
const separator = current.endsWith("\n\n")
|
|
77
|
+
? ""
|
|
78
|
+
: current.endsWith("\n")
|
|
79
|
+
? "\n"
|
|
80
|
+
: "\n\n";
|
|
70
81
|
return `${current}${separator}${nextSection}`;
|
|
71
82
|
}
|
|
72
83
|
|
|
@@ -82,7 +93,9 @@ export function getLatestRoutingTable() {
|
|
|
82
93
|
if (section.found) return section.section.trim();
|
|
83
94
|
}
|
|
84
95
|
// 2차 fallback: 패키지 CLAUDE.md도 없으면 에러
|
|
85
|
-
throw new Error(
|
|
96
|
+
throw new Error(
|
|
97
|
+
`routing section not found in: ${GLOBAL_CLAUDE_MD_PATH} or ${PKG_CLAUDE_MD_PATH}`,
|
|
98
|
+
);
|
|
86
99
|
}
|
|
87
100
|
|
|
88
101
|
export function ensureTfxSection(claudeMdPath, routingTable) {
|
|
@@ -132,15 +145,12 @@ export function ensureTfxCrown(claudeMdPath, options = {}) {
|
|
|
132
145
|
}
|
|
133
146
|
|
|
134
147
|
export function ensureGlobalClaudeRoutingSection(claudeDir) {
|
|
148
|
+
// routing은 프로젝트 CLAUDE.md에만 유지. global 중복 주입 중단.
|
|
135
149
|
const claudeMdPath = join(claudeDir, "CLAUDE.md");
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
} catch (error) {
|
|
143
|
-
const reason = error instanceof Error ? error.message : "routing_table_unavailable";
|
|
144
|
-
return toSkippedResult(claudeMdPath, reason);
|
|
145
|
-
}
|
|
150
|
+
return {
|
|
151
|
+
action: "unchanged",
|
|
152
|
+
path: claudeMdPath,
|
|
153
|
+
skipped: true,
|
|
154
|
+
reason: "global_sync_disabled",
|
|
155
|
+
};
|
|
146
156
|
}
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
// gateway가 alive인지 확인하고 죽었으면 기동한다.
|
|
5
5
|
// 실제 MCP 기능은 없음 (no-op). 역할은 gateway 보장뿐.
|
|
6
6
|
|
|
7
|
-
import { existsSync, readFileSync, writeFileSync } from
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
11
|
|
|
12
12
|
const PLUGIN_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
13
13
|
const PROBE_PORT = 8100;
|
|
@@ -15,21 +15,25 @@ const PROBE_TIMEOUT_MS = 2000;
|
|
|
15
15
|
const STARTUP_WAIT_MS = 6000;
|
|
16
16
|
const POLL_MS = 500;
|
|
17
17
|
const CACHE_TTL_MS = 5 * 60 * 1000; // 5분
|
|
18
|
-
const CACHE_FILE = join(tmpdir(),
|
|
18
|
+
const CACHE_FILE = join(tmpdir(), "tfx-gateway-alive.json");
|
|
19
19
|
|
|
20
20
|
function readCache() {
|
|
21
21
|
try {
|
|
22
22
|
if (!existsSync(CACHE_FILE)) return null;
|
|
23
|
-
const data = JSON.parse(readFileSync(CACHE_FILE,
|
|
23
|
+
const data = JSON.parse(readFileSync(CACHE_FILE, "utf8"));
|
|
24
24
|
if (Date.now() - data.ts < CACHE_TTL_MS) return data;
|
|
25
|
-
} catch {
|
|
25
|
+
} catch {
|
|
26
|
+
/* ignore */
|
|
27
|
+
}
|
|
26
28
|
return null;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
function writeCache() {
|
|
30
32
|
try {
|
|
31
33
|
writeFileSync(CACHE_FILE, JSON.stringify({ ts: Date.now(), alive: true }));
|
|
32
|
-
} catch {
|
|
34
|
+
} catch {
|
|
35
|
+
/* ignore */
|
|
36
|
+
}
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
async function isGatewayAlive() {
|
|
@@ -41,7 +45,10 @@ async function isGatewayAlive() {
|
|
|
41
45
|
const res = await fetch(`http://127.0.0.1:${PROBE_PORT}/healthz`, {
|
|
42
46
|
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),
|
|
43
47
|
});
|
|
44
|
-
if (res.ok) {
|
|
48
|
+
if (res.ok) {
|
|
49
|
+
writeCache();
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
45
52
|
return false;
|
|
46
53
|
} catch {
|
|
47
54
|
return false;
|
|
@@ -49,16 +56,18 @@ async function isGatewayAlive() {
|
|
|
49
56
|
}
|
|
50
57
|
|
|
51
58
|
async function startGateway() {
|
|
52
|
-
const script = join(PLUGIN_ROOT,
|
|
59
|
+
const script = join(PLUGIN_ROOT, "scripts", "mcp-gateway-start.mjs");
|
|
53
60
|
if (!existsSync(script)) {
|
|
54
|
-
process.stderr.write(
|
|
61
|
+
process.stderr.write(
|
|
62
|
+
"[gateway-preflight] mcp-gateway-start.mjs not found\n",
|
|
63
|
+
);
|
|
55
64
|
return false;
|
|
56
65
|
}
|
|
57
66
|
|
|
58
|
-
const { execSync } = await import(
|
|
67
|
+
const { execSync } = await import("node:child_process");
|
|
59
68
|
try {
|
|
60
69
|
execSync(`node "${script}"`, {
|
|
61
|
-
stdio:
|
|
70
|
+
stdio: "ignore",
|
|
62
71
|
timeout: STARTUP_WAIT_MS + 2000,
|
|
63
72
|
cwd: PLUGIN_ROOT,
|
|
64
73
|
});
|
|
@@ -81,53 +90,59 @@ async function main() {
|
|
|
81
90
|
// 1) gateway 보장
|
|
82
91
|
const alive = await isGatewayAlive();
|
|
83
92
|
if (!alive) {
|
|
84
|
-
process.stderr.write(
|
|
93
|
+
process.stderr.write("[gateway-preflight] gateway down, starting...\n");
|
|
85
94
|
const ok = await startGateway();
|
|
86
|
-
process.stderr.write(
|
|
87
|
-
|
|
88
|
-
|
|
95
|
+
process.stderr.write(
|
|
96
|
+
ok
|
|
97
|
+
? "[gateway-preflight] gateway started\n"
|
|
98
|
+
: "[gateway-preflight] gateway start failed\n",
|
|
99
|
+
);
|
|
89
100
|
}
|
|
90
101
|
|
|
91
102
|
// 2) MCP JSON-RPC stdio — initialize 핸드셰이크만 처리하고 idle 유지
|
|
92
|
-
const { createInterface } = await import(
|
|
103
|
+
const { createInterface } = await import("node:readline");
|
|
93
104
|
const rl = createInterface({ input: process.stdin });
|
|
94
105
|
|
|
95
|
-
rl.on(
|
|
106
|
+
rl.on("line", (line) => {
|
|
96
107
|
try {
|
|
97
108
|
const msg = JSON.parse(line);
|
|
98
|
-
if (msg.method ===
|
|
109
|
+
if (msg.method === "initialize") {
|
|
99
110
|
const response = {
|
|
100
|
-
jsonrpc:
|
|
111
|
+
jsonrpc: "2.0",
|
|
101
112
|
id: msg.id,
|
|
102
113
|
result: {
|
|
103
|
-
protocolVersion:
|
|
114
|
+
protocolVersion: "2024-11-05",
|
|
104
115
|
capabilities: {},
|
|
105
|
-
serverInfo: { name:
|
|
116
|
+
serverInfo: { name: "tfx-gateway-preflight", version: "1.0.0" },
|
|
106
117
|
},
|
|
107
118
|
};
|
|
108
|
-
process.stdout.write(JSON.stringify(response) +
|
|
109
|
-
} else if (msg.method ===
|
|
119
|
+
process.stdout.write(JSON.stringify(response) + "\n");
|
|
120
|
+
} else if (msg.method === "notifications/initialized") {
|
|
110
121
|
// ack, no response needed
|
|
111
|
-
} else if (msg.method ===
|
|
112
|
-
process.stdout.write(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
122
|
+
} else if (msg.method === "tools/list") {
|
|
123
|
+
process.stdout.write(
|
|
124
|
+
JSON.stringify({
|
|
125
|
+
jsonrpc: "2.0",
|
|
126
|
+
id: msg.id,
|
|
127
|
+
result: { tools: [] },
|
|
128
|
+
}) + "\n",
|
|
129
|
+
);
|
|
117
130
|
} else if (msg.id !== undefined) {
|
|
118
131
|
// unknown method with id — respond empty
|
|
119
|
-
process.stdout.write(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
132
|
+
process.stdout.write(
|
|
133
|
+
JSON.stringify({
|
|
134
|
+
jsonrpc: "2.0",
|
|
135
|
+
id: msg.id,
|
|
136
|
+
result: {},
|
|
137
|
+
}) + "\n",
|
|
138
|
+
);
|
|
124
139
|
}
|
|
125
140
|
} catch {
|
|
126
141
|
// ignore parse errors
|
|
127
142
|
}
|
|
128
143
|
});
|
|
129
144
|
|
|
130
|
-
rl.on(
|
|
145
|
+
rl.on("close", () => process.exit(0));
|
|
131
146
|
}
|
|
132
147
|
|
|
133
148
|
main();
|