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/hub-ensure.mjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
|
|
2
3
|
// SessionStart 훅에서 호출되는 Hub 보장 스크립트.
|
|
3
4
|
// - /status 기반 헬스체크
|
|
4
5
|
// - 비정상 시 Hub를 detached로 기동
|
|
5
6
|
|
|
7
|
+
import { spawn } from "child_process";
|
|
6
8
|
import { existsSync, readFileSync } from "fs";
|
|
7
|
-
import { join, dirname } from "path";
|
|
8
9
|
import { homedir } from "os";
|
|
9
|
-
import {
|
|
10
|
+
import { dirname, join } from "path";
|
|
10
11
|
import { fileURLToPath } from "url";
|
|
11
12
|
|
|
12
13
|
const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1"]);
|
|
@@ -23,7 +24,8 @@ function buildHubBaseUrl(host, port) {
|
|
|
23
24
|
|
|
24
25
|
function resolveHubTarget() {
|
|
25
26
|
const envPortRaw = Number(process.env.TFX_HUB_PORT || "");
|
|
26
|
-
const envPort =
|
|
27
|
+
const envPort =
|
|
28
|
+
Number.isFinite(envPortRaw) && envPortRaw > 0 ? envPortRaw : null;
|
|
27
29
|
const target = {
|
|
28
30
|
host: "127.0.0.1",
|
|
29
31
|
port: envPort || 27888,
|
|
@@ -68,13 +70,15 @@ function startHubDetached(port) {
|
|
|
68
70
|
try {
|
|
69
71
|
const env = { ...process.env, TFX_HUB_PORT: String(port) };
|
|
70
72
|
if (process.platform === "win32") {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
const child = spawn(
|
|
74
|
+
"cmd.exe",
|
|
75
|
+
["/c", "start", "/b", "", process.execPath, serverPath],
|
|
76
|
+
{
|
|
77
|
+
env,
|
|
78
|
+
stdio: "ignore",
|
|
79
|
+
windowsHide: true,
|
|
80
|
+
},
|
|
81
|
+
);
|
|
78
82
|
child.unref();
|
|
79
83
|
} else {
|
|
80
84
|
const child = spawn(process.execPath, [serverPath], {
|
|
@@ -90,31 +94,46 @@ function startHubDetached(port) {
|
|
|
90
94
|
}
|
|
91
95
|
}
|
|
92
96
|
|
|
93
|
-
/** Hub 기동 후 ready 상태까지 대기 (최대 maxWaitMs) */
|
|
94
97
|
async function waitForHubReady(host, port, maxWaitMs = 5000) {
|
|
95
98
|
const interval = 250;
|
|
96
99
|
const deadline = Date.now() + maxWaitMs;
|
|
97
100
|
while (Date.now() < deadline) {
|
|
98
101
|
if (await isHubHealthy(host, port)) return true;
|
|
99
|
-
await new Promise((
|
|
102
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
100
103
|
}
|
|
101
104
|
return false;
|
|
102
105
|
}
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
export async function run(stdinData) {
|
|
108
|
+
void stdinData;
|
|
109
|
+
|
|
110
|
+
const { host, port } = resolveHubTarget();
|
|
111
|
+
if (await isHubHealthy(host, port)) {
|
|
112
|
+
return { code: 0, stdout: "hub: ok", stderr: "" };
|
|
113
|
+
}
|
|
114
|
+
|
|
106
115
|
const started = startHubDetached(port);
|
|
107
|
-
if (started) {
|
|
108
|
-
|
|
109
|
-
if (ready) {
|
|
110
|
-
process.stdout.write("hub: ok");
|
|
111
|
-
} else {
|
|
112
|
-
// fire-and-forget: hub이 아직 기동 중일 수 있음 — 에러가 아닌 경고
|
|
113
|
-
process.stdout.write("hub: starting");
|
|
114
|
-
}
|
|
115
|
-
} else {
|
|
116
|
-
process.stderr.write("[hub-ensure] hub 시작 실패");
|
|
116
|
+
if (!started) {
|
|
117
|
+
return { code: 0, stdout: "", stderr: "[hub-ensure] hub 시작 실패" };
|
|
117
118
|
}
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
|
|
120
|
+
const ready = await waitForHubReady(host, port, 3000);
|
|
121
|
+
return {
|
|
122
|
+
code: 0,
|
|
123
|
+
stdout: ready ? "hub: ok" : "hub: starting",
|
|
124
|
+
stderr: "",
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const isMain =
|
|
129
|
+
process.argv[1] &&
|
|
130
|
+
import.meta.url.endsWith(
|
|
131
|
+
process.argv[1].replace(/\\/g, "/").split("/").pop(),
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
if (isMain) {
|
|
135
|
+
const result = await run();
|
|
136
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
137
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
138
|
+
process.exit(result.code);
|
|
120
139
|
}
|
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
compileRules,
|
|
8
|
+
loadRules,
|
|
9
|
+
matchRules,
|
|
10
|
+
resolveConflicts,
|
|
11
|
+
} from "./lib/keyword-rules.mjs";
|
|
7
12
|
|
|
8
13
|
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
9
14
|
const PROJECT_ROOT = dirname(SCRIPT_DIR);
|
|
@@ -33,7 +38,10 @@ export function extractPrompt(payload) {
|
|
|
33
38
|
return payload.prompt;
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
if (
|
|
41
|
+
if (
|
|
42
|
+
typeof payload.message?.content === "string" &&
|
|
43
|
+
payload.message.content.trim()
|
|
44
|
+
) {
|
|
37
45
|
return payload.message.content;
|
|
38
46
|
}
|
|
39
47
|
|
|
@@ -87,8 +95,8 @@ function createHookOutput(additionalContext) {
|
|
|
87
95
|
continue: true,
|
|
88
96
|
hookSpecificOutput: {
|
|
89
97
|
hookEventName: "UserPromptSubmit",
|
|
90
|
-
additionalContext
|
|
91
|
-
}
|
|
98
|
+
additionalContext,
|
|
99
|
+
},
|
|
92
100
|
};
|
|
93
101
|
}
|
|
94
102
|
|
|
@@ -144,17 +152,19 @@ function isSkipRequested() {
|
|
|
144
152
|
}
|
|
145
153
|
|
|
146
154
|
function activateState(baseDir, stateConfig, prompt, payload) {
|
|
147
|
-
if (!stateConfig || stateConfig.activate !== true || !stateConfig.name)
|
|
155
|
+
if (!stateConfig || stateConfig.activate !== true || !stateConfig.name)
|
|
156
|
+
return;
|
|
148
157
|
|
|
149
158
|
try {
|
|
150
159
|
const stateRoot = join(baseDir, ".triflux", "state");
|
|
151
160
|
mkdirSync(stateRoot, { recursive: true });
|
|
152
161
|
|
|
153
|
-
const sessionId =
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
const sessionId =
|
|
163
|
+
typeof payload?.session_id === "string"
|
|
164
|
+
? payload.session_id
|
|
165
|
+
: typeof payload?.sessionId === "string"
|
|
166
|
+
? payload.sessionId
|
|
167
|
+
: "";
|
|
158
168
|
|
|
159
169
|
let stateDir = stateRoot;
|
|
160
170
|
if (sessionId && /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,255}$/.test(sessionId)) {
|
|
@@ -167,12 +177,14 @@ function activateState(baseDir, stateConfig, prompt, payload) {
|
|
|
167
177
|
active: true,
|
|
168
178
|
name: stateConfig.name,
|
|
169
179
|
started_at: new Date().toISOString(),
|
|
170
|
-
original_prompt: prompt
|
|
180
|
+
original_prompt: prompt,
|
|
171
181
|
};
|
|
172
182
|
|
|
173
183
|
writeFileSync(statePath, JSON.stringify(statePayload, null, 2), "utf8");
|
|
174
184
|
} catch (error) {
|
|
175
|
-
console.error(
|
|
185
|
+
console.error(
|
|
186
|
+
`[triflux-keyword-detector] 상태 저장 실패: ${error.message}`,
|
|
187
|
+
);
|
|
176
188
|
}
|
|
177
189
|
}
|
|
178
190
|
|
|
@@ -238,26 +250,35 @@ function main() {
|
|
|
238
250
|
}
|
|
239
251
|
|
|
240
252
|
const selected = resolvedMatches[0];
|
|
241
|
-
const baseDir =
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
253
|
+
const baseDir =
|
|
254
|
+
typeof payload.cwd === "string" && payload.cwd
|
|
255
|
+
? payload.cwd
|
|
256
|
+
: typeof payload.directory === "string" && payload.directory
|
|
257
|
+
? payload.directory
|
|
258
|
+
: process.cwd();
|
|
246
259
|
|
|
247
260
|
activateState(baseDir, selected.state, prompt, payload);
|
|
248
261
|
|
|
249
262
|
if (selected.action === "suppress_omc") {
|
|
250
|
-
console.log(
|
|
263
|
+
console.log(
|
|
264
|
+
JSON.stringify(
|
|
265
|
+
createHookOutput(createSuppressOmcContext(selected, prompt)),
|
|
266
|
+
),
|
|
267
|
+
);
|
|
251
268
|
return;
|
|
252
269
|
}
|
|
253
270
|
|
|
254
271
|
if (selected.skill) {
|
|
255
|
-
console.log(
|
|
272
|
+
console.log(
|
|
273
|
+
JSON.stringify(createHookOutput(createSkillContext(selected, prompt))),
|
|
274
|
+
);
|
|
256
275
|
return;
|
|
257
276
|
}
|
|
258
277
|
|
|
259
278
|
if (selected.mcp_route) {
|
|
260
|
-
console.log(
|
|
279
|
+
console.log(
|
|
280
|
+
JSON.stringify(createHookOutput(createMcpRouteContext(selected, prompt))),
|
|
281
|
+
);
|
|
261
282
|
return;
|
|
262
283
|
}
|
|
263
284
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
|
|
2
3
|
// session-vault 태그 빈도 기반으로 keyword-rules.json 확장 후보를 제안하는 스크립트
|
|
3
4
|
|
|
4
|
-
import Database from "better-sqlite3";
|
|
5
5
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import { dirname, join, resolve } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
+
import Database from "better-sqlite3";
|
|
9
10
|
|
|
10
11
|
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
11
12
|
const PROJECT_ROOT = dirname(SCRIPT_DIR);
|
|
@@ -25,7 +26,7 @@ const MCP_SERVICE_ROUTE_MAP = {
|
|
|
25
26
|
gmail: "gemini",
|
|
26
27
|
email: "gemini",
|
|
27
28
|
github: "codex",
|
|
28
|
-
figma: "gemini"
|
|
29
|
+
figma: "gemini",
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
const MCP_SERVICE_NAMES = new Set([
|
|
@@ -37,7 +38,7 @@ const MCP_SERVICE_NAMES = new Set([
|
|
|
37
38
|
"asana",
|
|
38
39
|
"drive",
|
|
39
40
|
"sheets",
|
|
40
|
-
"docs"
|
|
41
|
+
"docs",
|
|
41
42
|
]);
|
|
42
43
|
|
|
43
44
|
function printUsage() {
|
|
@@ -54,7 +55,7 @@ function parseArgs(argv) {
|
|
|
54
55
|
apply: false,
|
|
55
56
|
threshold: DEFAULT_THRESHOLD,
|
|
56
57
|
dbPath: DEFAULT_DB_PATH,
|
|
57
|
-
help: false
|
|
58
|
+
help: false,
|
|
58
59
|
};
|
|
59
60
|
|
|
60
61
|
for (let i = 0; i < argv.length; i += 1) {
|
|
@@ -202,7 +203,7 @@ function aggregateByNormalizedTag(rows) {
|
|
|
202
203
|
normalized,
|
|
203
204
|
frequency: 0,
|
|
204
205
|
variants: new Set(),
|
|
205
|
-
sources: new Set()
|
|
206
|
+
sources: new Set(),
|
|
206
207
|
});
|
|
207
208
|
}
|
|
208
209
|
|
|
@@ -230,8 +231,11 @@ function readRulesDocument(rulesPath) {
|
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
function extractLiteralWords(patternSource) {
|
|
233
|
-
const words =
|
|
234
|
-
|
|
234
|
+
const words =
|
|
235
|
+
patternSource.toLowerCase().match(/[a-z0-9][a-z0-9-]{1,}/g) || [];
|
|
236
|
+
return words.filter(
|
|
237
|
+
(word) => !["true", "false", "null", "route", "skill"].includes(word),
|
|
238
|
+
);
|
|
235
239
|
}
|
|
236
240
|
|
|
237
241
|
function buildRuleIndex(rules) {
|
|
@@ -243,16 +247,24 @@ function buildRuleIndex(rules) {
|
|
|
243
247
|
|
|
244
248
|
const ruleId = typeof rule.id === "string" ? rule.id.trim() : "";
|
|
245
249
|
const skill = typeof rule.skill === "string" ? rule.skill.trim() : "";
|
|
246
|
-
const route =
|
|
250
|
+
const route =
|
|
251
|
+
typeof rule.mcp_route === "string" ? rule.mcp_route.trim() : "";
|
|
247
252
|
|
|
248
253
|
if (ruleId) aliases.add(normalizeKeyword(ruleId));
|
|
249
|
-
if (ruleId.endsWith("-route"))
|
|
250
|
-
|
|
254
|
+
if (ruleId.endsWith("-route"))
|
|
255
|
+
aliases.add(normalizeKeyword(ruleId.slice(0, -"-route".length)));
|
|
256
|
+
if (ruleId.endsWith("-skill"))
|
|
257
|
+
aliases.add(normalizeKeyword(ruleId.slice(0, -"-skill".length)));
|
|
251
258
|
if (skill) aliases.add(normalizeKeyword(skill));
|
|
252
259
|
if (route) aliases.add(normalizeKeyword(route));
|
|
253
260
|
|
|
254
261
|
for (const pattern of Array.isArray(rule.patterns) ? rule.patterns : []) {
|
|
255
|
-
if (
|
|
262
|
+
if (
|
|
263
|
+
!pattern ||
|
|
264
|
+
typeof pattern.source !== "string" ||
|
|
265
|
+
typeof pattern.flags !== "string"
|
|
266
|
+
)
|
|
267
|
+
continue;
|
|
256
268
|
try {
|
|
257
269
|
regexes.push(new RegExp(pattern.source, pattern.flags));
|
|
258
270
|
} catch {
|
|
@@ -267,7 +279,7 @@ function buildRuleIndex(rules) {
|
|
|
267
279
|
indexed.push({
|
|
268
280
|
id: ruleId || "(unknown-rule)",
|
|
269
281
|
aliases,
|
|
270
|
-
regexes
|
|
282
|
+
regexes,
|
|
271
283
|
});
|
|
272
284
|
}
|
|
273
285
|
|
|
@@ -300,7 +312,7 @@ function classifyCandidate(keyword) {
|
|
|
300
312
|
type: "skill",
|
|
301
313
|
label: "skill 규칙 후보",
|
|
302
314
|
skill: normalized,
|
|
303
|
-
mcpRoute: null
|
|
315
|
+
mcpRoute: null,
|
|
304
316
|
};
|
|
305
317
|
}
|
|
306
318
|
|
|
@@ -309,7 +321,7 @@ function classifyCandidate(keyword) {
|
|
|
309
321
|
type: "mcp_route",
|
|
310
322
|
label: "mcp_route 규칙 후보",
|
|
311
323
|
skill: null,
|
|
312
|
-
mcpRoute: MCP_SERVICE_ROUTE_MAP[normalized] || "gemini"
|
|
324
|
+
mcpRoute: MCP_SERVICE_ROUTE_MAP[normalized] || "gemini",
|
|
313
325
|
};
|
|
314
326
|
}
|
|
315
327
|
|
|
@@ -317,7 +329,7 @@ function classifyCandidate(keyword) {
|
|
|
317
329
|
type: "general",
|
|
318
330
|
label: "분류 미정",
|
|
319
331
|
skill: null,
|
|
320
|
-
mcpRoute: null
|
|
332
|
+
mcpRoute: null,
|
|
321
333
|
};
|
|
322
334
|
}
|
|
323
335
|
|
|
@@ -353,15 +365,15 @@ function buildRuleFromCandidate(candidate, existingIds) {
|
|
|
353
365
|
patterns: [
|
|
354
366
|
{
|
|
355
367
|
source: createPatternSource(candidate.keyword),
|
|
356
|
-
flags: "i"
|
|
357
|
-
}
|
|
368
|
+
flags: "i",
|
|
369
|
+
},
|
|
358
370
|
],
|
|
359
371
|
skill: candidate.classification.skill,
|
|
360
372
|
priority: 20,
|
|
361
373
|
supersedes: [],
|
|
362
374
|
exclusive: false,
|
|
363
375
|
state: null,
|
|
364
|
-
mcp_route: null
|
|
376
|
+
mcp_route: null,
|
|
365
377
|
};
|
|
366
378
|
}
|
|
367
379
|
|
|
@@ -373,15 +385,15 @@ function buildRuleFromCandidate(candidate, existingIds) {
|
|
|
373
385
|
patterns: [
|
|
374
386
|
{
|
|
375
387
|
source: createPatternSource(candidate.keyword),
|
|
376
|
-
flags: "i"
|
|
377
|
-
}
|
|
388
|
+
flags: "i",
|
|
389
|
+
},
|
|
378
390
|
],
|
|
379
391
|
skill: null,
|
|
380
392
|
priority: 20,
|
|
381
393
|
supersedes: [],
|
|
382
394
|
exclusive: false,
|
|
383
395
|
state: null,
|
|
384
|
-
mcp_route: candidate.classification.mcpRoute
|
|
396
|
+
mcp_route: candidate.classification.mcpRoute,
|
|
385
397
|
};
|
|
386
398
|
}
|
|
387
399
|
|
|
@@ -405,7 +417,7 @@ function printAnalysis({
|
|
|
405
417
|
coveredCount,
|
|
406
418
|
threshold,
|
|
407
419
|
candidates,
|
|
408
|
-
covered
|
|
420
|
+
covered,
|
|
409
421
|
}) {
|
|
410
422
|
console.log("=== keyword-rules-expander 분석 결과 ===");
|
|
411
423
|
console.log("");
|
|
@@ -419,7 +431,9 @@ function printAnalysis({
|
|
|
419
431
|
console.log(" (없음)");
|
|
420
432
|
} else {
|
|
421
433
|
for (const item of candidates) {
|
|
422
|
-
console.log(
|
|
434
|
+
console.log(
|
|
435
|
+
` ${item.keyword} (${item.frequency}회) → ${item.classification.label}`,
|
|
436
|
+
);
|
|
423
437
|
}
|
|
424
438
|
}
|
|
425
439
|
|
|
@@ -429,7 +443,9 @@ function printAnalysis({
|
|
|
429
443
|
console.log(" (없음)");
|
|
430
444
|
} else {
|
|
431
445
|
for (const item of covered) {
|
|
432
|
-
console.log(
|
|
446
|
+
console.log(
|
|
447
|
+
` ${item.keyword} (${item.frequency}회) → ${item.ruleId} 규칙 있음`,
|
|
448
|
+
);
|
|
433
449
|
}
|
|
434
450
|
}
|
|
435
451
|
}
|
|
@@ -458,7 +474,7 @@ function main() {
|
|
|
458
474
|
covered.push({
|
|
459
475
|
keyword: tag.keyword,
|
|
460
476
|
frequency: tag.frequency,
|
|
461
|
-
ruleId: matchedRuleId
|
|
477
|
+
ruleId: matchedRuleId,
|
|
462
478
|
});
|
|
463
479
|
continue;
|
|
464
480
|
}
|
|
@@ -469,7 +485,7 @@ function main() {
|
|
|
469
485
|
keyword: tag.keyword,
|
|
470
486
|
normalized: tag.normalized,
|
|
471
487
|
frequency: tag.frequency,
|
|
472
|
-
classification: classifyCandidate(tag.keyword)
|
|
488
|
+
classification: classifyCandidate(tag.keyword),
|
|
473
489
|
});
|
|
474
490
|
}
|
|
475
491
|
|
|
@@ -480,7 +496,7 @@ function main() {
|
|
|
480
496
|
coveredCount: covered.length,
|
|
481
497
|
threshold: args.threshold,
|
|
482
498
|
candidates,
|
|
483
|
-
covered
|
|
499
|
+
covered,
|
|
484
500
|
});
|
|
485
501
|
|
|
486
502
|
if (!args.apply) return;
|
|
@@ -488,10 +504,12 @@ function main() {
|
|
|
488
504
|
const existingIds = new Set(
|
|
489
505
|
rulesDoc.rules
|
|
490
506
|
.map((rule) => (typeof rule.id === "string" ? rule.id.trim() : ""))
|
|
491
|
-
.filter(Boolean)
|
|
507
|
+
.filter(Boolean),
|
|
492
508
|
);
|
|
493
509
|
|
|
494
|
-
const autoApplicable = candidates.filter(
|
|
510
|
+
const autoApplicable = candidates.filter(
|
|
511
|
+
(item) => item.classification.type !== "general",
|
|
512
|
+
);
|
|
495
513
|
const manualReviewCount = candidates.length - autoApplicable.length;
|
|
496
514
|
|
|
497
515
|
const newRules = autoApplicable
|
|
@@ -518,4 +536,3 @@ try {
|
|
|
518
536
|
console.error(`[keyword-rules-expander] 오류: ${error.message}`);
|
|
519
537
|
process.exit(1);
|
|
520
538
|
}
|
|
521
|
-
|
|
@@ -23,7 +23,12 @@ const DEFAULT_TFX_TEMPLATE = [
|
|
|
23
23
|
].join("\n");
|
|
24
24
|
|
|
25
25
|
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
26
|
-
const DEFAULT_TEMPLATE_PATH = join(
|
|
26
|
+
const DEFAULT_TEMPLATE_PATH = join(
|
|
27
|
+
SCRIPT_DIR,
|
|
28
|
+
"..",
|
|
29
|
+
"templates",
|
|
30
|
+
"claudemd-tfx-section.md",
|
|
31
|
+
);
|
|
27
32
|
|
|
28
33
|
function resolveVersion(version) {
|
|
29
34
|
if (version) return version;
|
package/scripts/lib/context.mjs
CHANGED
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
* log.info('result.processed'); // correlationId 자동 포함
|
|
20
20
|
* }
|
|
21
21
|
*/
|
|
22
|
-
import { AsyncLocalStorage } from
|
|
23
|
-
import { randomUUID } from
|
|
22
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
23
|
+
import { randomUUID } from "node:crypto";
|
|
24
24
|
|
|
25
|
-
import { logger } from
|
|
25
|
+
import { logger } from "./logger.mjs";
|
|
26
26
|
|
|
27
27
|
/** @type {AsyncLocalStorage<{logger: import('pino').Logger, correlationId: string}>} */
|
|
28
28
|
export const asyncLocalStorage = new AsyncLocalStorage();
|
|
@@ -28,8 +28,10 @@ export function nowSec() {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export function resolveBaseDir(payload) {
|
|
31
|
-
if (typeof payload?.cwd === "string" && payload.cwd.trim())
|
|
32
|
-
|
|
31
|
+
if (typeof payload?.cwd === "string" && payload.cwd.trim())
|
|
32
|
+
return payload.cwd;
|
|
33
|
+
if (typeof payload?.directory === "string" && payload.directory.trim())
|
|
34
|
+
return payload.directory;
|
|
33
35
|
return process.cwd();
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -38,7 +40,8 @@ export function shouldTrackPath(filePath) {
|
|
|
38
40
|
|
|
39
41
|
const lower = filePath.toLowerCase();
|
|
40
42
|
if (lower.startsWith(".omc/") || lower.startsWith(".claude/")) return false;
|
|
41
|
-
if (lower === "package-lock.json" || lower.endsWith("/package-lock.json"))
|
|
43
|
+
if (lower === "package-lock.json" || lower.endsWith("/package-lock.json"))
|
|
44
|
+
return false;
|
|
42
45
|
if (/\.(md|lock|yml|yaml)$/i.test(lower)) return false;
|
|
43
46
|
return true;
|
|
44
47
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { execSync, spawn } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
1
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import { join, dirname } from "node:path";
|
|
3
4
|
import { homedir } from "node:os";
|
|
4
|
-
import {
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { createHash } from "node:crypto";
|
|
7
7
|
import { whichCommand, whichCommandAsync } from "../../hub/platform.mjs";
|
|
8
8
|
|
|
9
9
|
const DEFAULT_STATUS_URL = "http://127.0.0.1:27888/status";
|
|
@@ -73,10 +73,13 @@ function normalizeCliNames(names) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
function mapCliResults(names, results) {
|
|
76
|
-
return names.reduce(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
return names.reduce(
|
|
77
|
+
(acc, name, index) => ({
|
|
78
|
+
...acc,
|
|
79
|
+
[name]: results[index],
|
|
80
|
+
}),
|
|
81
|
+
{},
|
|
82
|
+
);
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
async function resolveCliProbe(name, options = {}) {
|
|
@@ -115,13 +118,18 @@ export function checkCliSync(name, options = {}) {
|
|
|
115
118
|
const cached = readCachedCliResult(cliName);
|
|
116
119
|
if (cached) return cached;
|
|
117
120
|
|
|
118
|
-
const path = (options.whichCommandFn || whichCommand)(
|
|
121
|
+
const path = (options.whichCommandFn || whichCommand)(
|
|
122
|
+
cliName,
|
|
123
|
+
buildCliProbeOptions(options),
|
|
124
|
+
);
|
|
119
125
|
return storeCliResult(cliName, toCliResult(path));
|
|
120
126
|
}
|
|
121
127
|
|
|
122
128
|
export async function probeClis(names, options = {}) {
|
|
123
129
|
const cliNames = normalizeCliNames(names);
|
|
124
|
-
const results = await Promise.all(
|
|
130
|
+
const results = await Promise.all(
|
|
131
|
+
cliNames.map((name) => checkCli(name, options)),
|
|
132
|
+
);
|
|
125
133
|
return mapCliResults(cliNames, results);
|
|
126
134
|
}
|
|
127
135
|
|
|
@@ -137,15 +145,18 @@ export function detectCodexAuthState({
|
|
|
137
145
|
} = {}) {
|
|
138
146
|
try {
|
|
139
147
|
const authPath = join(homeDir, ".codex", "auth.json");
|
|
140
|
-
if (!existsSyncFn(authPath))
|
|
148
|
+
if (!existsSyncFn(authPath))
|
|
149
|
+
return { plan: "unknown", source: "no_auth", fingerprint: "no_auth" };
|
|
141
150
|
|
|
142
151
|
const auth = JSON.parse(readFileSyncFn(authPath, "utf8"));
|
|
143
152
|
if (auth.auth_mode !== "chatgpt") {
|
|
144
153
|
const fingerprint = createHash("sha256")
|
|
145
|
-
.update(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
154
|
+
.update(
|
|
155
|
+
JSON.stringify({
|
|
156
|
+
auth_mode: auth.auth_mode || "api_key",
|
|
157
|
+
has_api_key: Boolean(auth.api_key || auth.apiKey),
|
|
158
|
+
}),
|
|
159
|
+
)
|
|
149
160
|
.digest("hex");
|
|
150
161
|
return { plan: "api", source: "api_key", fingerprint };
|
|
151
162
|
}
|
|
@@ -156,20 +167,30 @@ export function detectCodexAuthState({
|
|
|
156
167
|
plan: "unknown",
|
|
157
168
|
source: "no_token",
|
|
158
169
|
fingerprint: createHash("sha256")
|
|
159
|
-
.update(
|
|
170
|
+
.update(
|
|
171
|
+
JSON.stringify({
|
|
172
|
+
auth_mode: auth.auth_mode || "chatgpt",
|
|
173
|
+
token: null,
|
|
174
|
+
}),
|
|
175
|
+
)
|
|
160
176
|
.digest("hex"),
|
|
161
177
|
};
|
|
162
178
|
}
|
|
163
179
|
|
|
164
|
-
const payload = JSON.parse(
|
|
165
|
-
|
|
180
|
+
const payload = JSON.parse(
|
|
181
|
+
Buffer.from(token.split(".")[1], "base64url").toString(),
|
|
182
|
+
);
|
|
183
|
+
const plan =
|
|
184
|
+
payload?.["https://api.openai.com/auth"]?.chatgpt_plan_type || "unknown";
|
|
166
185
|
const fingerprint = createHash("sha256")
|
|
167
|
-
.update(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
186
|
+
.update(
|
|
187
|
+
JSON.stringify({
|
|
188
|
+
auth_mode: auth.auth_mode || "chatgpt",
|
|
189
|
+
plan,
|
|
190
|
+
sub: payload?.sub || null,
|
|
191
|
+
exp: payload?.exp || null,
|
|
192
|
+
}),
|
|
193
|
+
)
|
|
173
194
|
.digest("hex");
|
|
174
195
|
return { plan, source: "jwt", fingerprint };
|
|
175
196
|
} catch {
|
|
@@ -205,7 +226,8 @@ export function checkHub({
|
|
|
205
226
|
if (!restart) return { ok: false, state: "unreachable", restart: "disabled" };
|
|
206
227
|
|
|
207
228
|
const serverPath = join(pkgRoot, "hub", "server.mjs");
|
|
208
|
-
if (!existsSyncFn(serverPath))
|
|
229
|
+
if (!existsSyncFn(serverPath))
|
|
230
|
+
return { ok: false, state: "unreachable", restart: "no_server" };
|
|
209
231
|
|
|
210
232
|
try {
|
|
211
233
|
const child = spawnFn(process.execPath, [serverPath], {
|
|
@@ -235,7 +257,4 @@ export function checkHub({
|
|
|
235
257
|
return { ok: false, state: "unreachable", restart: "timeout" };
|
|
236
258
|
}
|
|
237
259
|
|
|
238
|
-
export {
|
|
239
|
-
DEFAULT_PKG_ROOT,
|
|
240
|
-
DEFAULT_STATUS_URL,
|
|
241
|
-
};
|
|
260
|
+
export { DEFAULT_PKG_ROOT, DEFAULT_STATUS_URL };
|