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,88 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 상수 / 경로
|
|
3
|
+
// ============================================================================
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
export const VERSION = "2.0";
|
|
8
|
+
|
|
9
|
+
export const QOS_PATH = join(homedir(), ".omc", "state", "cli_qos_profile.json");
|
|
10
|
+
export const ACCOUNTS_CONFIG_PATH = join(homedir(), ".omc", "router", "accounts.json");
|
|
11
|
+
export const ACCOUNTS_STATE_PATH = join(homedir(), ".omc", "state", "cli_accounts_state.json");
|
|
12
|
+
|
|
13
|
+
// tfx-multi 상태 (v2.2 HUD 통합)
|
|
14
|
+
export const TEAM_STATE_PATH = join(homedir(), ".claude", "cache", "tfx-hub", "team-state.json");
|
|
15
|
+
export const CONTEXT_MONITOR_CACHE_PATH = join(homedir(), ".claude", "cache", "tfx-hub", "context-monitor.json");
|
|
16
|
+
export const CONTEXT_MONITOR_LEGACY_PATH = join(homedir(), ".omc", "state", "context-monitor.json");
|
|
17
|
+
export const CONTEXT_MONITOR_LOG_DIR = join(homedir(), ".omc", "logs");
|
|
18
|
+
|
|
19
|
+
// 원격 프로브 캐시 (tfx-remote-spawn)
|
|
20
|
+
export const REMOTE_ENV_CACHE_DIR = join(homedir(), ".claude", "cache", "tfx-hub", "remote-env");
|
|
21
|
+
export const REMOTE_ENV_CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24시간
|
|
22
|
+
|
|
23
|
+
// Claude OAuth Usage API (api.anthropic.com/api/oauth/usage)
|
|
24
|
+
export const CLAUDE_CREDENTIALS_PATH = join(homedir(), ".claude", ".credentials.json");
|
|
25
|
+
export const CLAUDE_USAGE_CACHE_PATH = join(homedir(), ".claude", "cache", "claude-usage-cache.json");
|
|
26
|
+
export const OMC_PLUGIN_USAGE_CACHE_PATH = join(homedir(), ".claude", "plugins", "oh-my-claudecode", ".usage-cache.json");
|
|
27
|
+
export const CLAUDE_USAGE_STALE_MS_SOLO = 5 * 60 * 1000; // OMC 없을 때: 5분 캐시
|
|
28
|
+
export const CLAUDE_USAGE_STALE_MS_WITH_OMC = 15 * 60 * 1000; // OMC 있을 때: 15분 (OMC가 30초마다 갱신)
|
|
29
|
+
export const CLAUDE_USAGE_429_BACKOFF_MS = 10 * 60 * 1000; // 429 에러 시 10분 backoff
|
|
30
|
+
export const GEMINI_429_BASE_DELAY_MS = 2000;
|
|
31
|
+
export const GEMINI_429_MAX_RETRIES = 3;
|
|
32
|
+
export const GEMINI_429_COOLDOWN_MS = 30000;
|
|
33
|
+
export const CLAUDE_USAGE_ERROR_BACKOFF_MS = 3 * 60 * 1000; // 기타 에러 시 3분 backoff
|
|
34
|
+
export const CLAUDE_API_TIMEOUT_MS = 10_000;
|
|
35
|
+
export const FIVE_HOUR_MS = 5 * 60 * 60 * 1000;
|
|
36
|
+
export const SEVEN_DAY_MS = 7 * 24 * 60 * 60 * 1000;
|
|
37
|
+
export const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
|
38
|
+
export const DEFAULT_OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
39
|
+
|
|
40
|
+
export const CODEX_AUTH_PATH = join(homedir(), ".codex", "auth.json");
|
|
41
|
+
export const CODEX_QUOTA_CACHE_PATH = join(homedir(), ".claude", "cache", "codex-rate-limits-cache.json");
|
|
42
|
+
export const CODEX_QUOTA_STALE_MS = 15 * 1000; // 15초
|
|
43
|
+
export const CODEX_MIN_BUCKETS = 2;
|
|
44
|
+
|
|
45
|
+
// Gemini 쿼터 API 관련
|
|
46
|
+
export const GEMINI_OAUTH_PATH = join(homedir(), ".gemini", "oauth_creds.json");
|
|
47
|
+
export const GEMINI_QUOTA_CACHE_PATH = join(homedir(), ".claude", "cache", "gemini-quota-cache.json");
|
|
48
|
+
export const GEMINI_PROJECT_CACHE_PATH = join(homedir(), ".claude", "cache", "gemini-project-id.json");
|
|
49
|
+
export const GEMINI_SESSION_CACHE_PATH = join(homedir(), ".claude", "cache", "gemini-session-cache.json");
|
|
50
|
+
export const GEMINI_RPM_TRACKER_PATH = join(homedir(), ".claude", "cache", "gemini-rpm-tracker.json");
|
|
51
|
+
export const SV_ACCUMULATOR_PATH = join(homedir(), ".claude", "cache", "sv-accumulator.json");
|
|
52
|
+
// 이전 .omc/ 경로 fallback (기존 환경 호환)
|
|
53
|
+
export const LEGACY_GEMINI_QUOTA_CACHE = join(homedir(), ".omc", "state", "gemini_quota_cache.json");
|
|
54
|
+
export const LEGACY_GEMINI_PROJECT_CACHE = join(homedir(), ".omc", "state", "gemini_project_id.json");
|
|
55
|
+
export const LEGACY_GEMINI_SESSION_CACHE = join(homedir(), ".omc", "state", "gemini_session_tokens_cache.json");
|
|
56
|
+
export const LEGACY_GEMINI_RPM_TRACKER = join(homedir(), ".omc", "state", "gemini_rpm_tracker.json");
|
|
57
|
+
export const LEGACY_SV_ACCUMULATOR = join(homedir(), ".omc", "state", "sv-accumulator.json");
|
|
58
|
+
|
|
59
|
+
export const GEMINI_RPM_WINDOW_MS = 60 * 1000; // 60초 슬라이딩 윈도우
|
|
60
|
+
export const GEMINI_QUOTA_STALE_MS = 5 * 60 * 1000; // 5분
|
|
61
|
+
export const GEMINI_SESSION_STALE_MS = 15 * 1000; // 15초
|
|
62
|
+
export const GEMINI_API_TIMEOUT_MS = 3000; // 3초
|
|
63
|
+
|
|
64
|
+
export const ACCOUNT_LABEL_WIDTH = 10;
|
|
65
|
+
export const PROVIDER_PREFIX_WIDTH = 2;
|
|
66
|
+
export const PERCENT_CELL_WIDTH = 3;
|
|
67
|
+
export const TIME_CELL_INNER_WIDTH = 6;
|
|
68
|
+
export const SV_CELL_WIDTH = 5;
|
|
69
|
+
|
|
70
|
+
export const CLAUDE_REFRESH_FLAG = "--refresh-claude-usage";
|
|
71
|
+
export const CODEX_REFRESH_FLAG = "--refresh-codex-rate-limits";
|
|
72
|
+
export const GEMINI_REFRESH_FLAG = "--refresh-gemini-quota";
|
|
73
|
+
export const GEMINI_SESSION_REFRESH_FLAG = "--refresh-gemini-session";
|
|
74
|
+
|
|
75
|
+
// 모바일/Termux 컴팩트 모드 감지
|
|
76
|
+
export const HUD_CONFIG_PATH = join(homedir(), ".omc", "config", "hud.json");
|
|
77
|
+
export const COMPACT_COLS_THRESHOLD = 80;
|
|
78
|
+
export const MINIMAL_COLS_THRESHOLD = 60;
|
|
79
|
+
|
|
80
|
+
// rows 임계값 상수 (selectTier 에서 tier 결정에 사용)
|
|
81
|
+
export const ROWS_BUDGET_FULL = 40;
|
|
82
|
+
export const ROWS_BUDGET_LARGE = 35;
|
|
83
|
+
export const ROWS_BUDGET_MEDIUM = 28;
|
|
84
|
+
export const ROWS_BUDGET_SMALL = 22;
|
|
85
|
+
|
|
86
|
+
// Gemini Pro 풀 공유 그룹: 같은 remainingFraction을 공유하는 모델 ID들
|
|
87
|
+
export const GEMINI_PRO_POOL = new Set(["gemini-2.5-pro", "gemini-3-pro-preview", "gemini-3.1-pro-preview"]);
|
|
88
|
+
export const GEMINI_FLASH_POOL = new Set(["gemini-2.5-flash", "gemini-3-flash-preview"]);
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
CONTEXT_MONITOR_CACHE_PATH,
|
|
8
|
+
CONTEXT_MONITOR_LEGACY_PATH,
|
|
9
|
+
CONTEXT_MONITOR_LOG_DIR,
|
|
10
|
+
} from "./constants.mjs";
|
|
11
|
+
import { clampPercent, formatTokenCount, readJsonMigrate } from "./utils.mjs";
|
|
12
|
+
|
|
13
|
+
const DEFAULT_CONTEXT_LIMIT = 200_000;
|
|
14
|
+
const MAX_CAPTURE_BYTES = 256 * 1024;
|
|
15
|
+
const MAX_TOP_KEYS = 20;
|
|
16
|
+
|
|
17
|
+
const WARNING_LEVELS = Object.freeze({
|
|
18
|
+
ok: { min: 0, message: "" },
|
|
19
|
+
info: { min: 60, message: "컨텍스트 절반 이상 사용" },
|
|
20
|
+
warn: { min: 80, message: "압축 권장" },
|
|
21
|
+
critical: { min: 90, message: "에이전트 분할 또는 세션 교체 권장" },
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Unlike clampPercent (rounds), this preserves decimals for precise threshold comparison.
|
|
25
|
+
function clampThresholdPercent(value) {
|
|
26
|
+
const numeric = Number(value);
|
|
27
|
+
if (!Number.isFinite(numeric)) return 0;
|
|
28
|
+
return Math.max(0, Math.min(100, numeric));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function safeWriteJson(filePath, data) {
|
|
32
|
+
try {
|
|
33
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
34
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
35
|
+
} catch {
|
|
36
|
+
// noop
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function normalizeText(input) {
|
|
41
|
+
if (typeof input === "string") return input;
|
|
42
|
+
if (input == null) return "";
|
|
43
|
+
try {
|
|
44
|
+
return JSON.stringify(input);
|
|
45
|
+
} catch {
|
|
46
|
+
return String(input);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function safeJsonParse(raw) {
|
|
51
|
+
if (typeof raw !== "string" || !raw.trim()) return null;
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(raw);
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function toTokenEstimate(bytesOrText) {
|
|
60
|
+
if (typeof bytesOrText === "number" && Number.isFinite(bytesOrText)) {
|
|
61
|
+
if (bytesOrText <= 0) return 0;
|
|
62
|
+
return Math.max(1, Math.ceil(bytesOrText / 4));
|
|
63
|
+
}
|
|
64
|
+
const text = normalizeText(bytesOrText);
|
|
65
|
+
const bytes = Buffer.byteLength(text, "utf8");
|
|
66
|
+
if (bytes <= 0) return 0;
|
|
67
|
+
return Math.max(1, Math.ceil(bytes / 4));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function normalizeUsage(usage) {
|
|
71
|
+
if (!usage || typeof usage !== "object") return null;
|
|
72
|
+
const input = Number(usage.input_tokens ?? usage.inputTokens ?? 0);
|
|
73
|
+
const output = Number(usage.output_tokens ?? usage.outputTokens ?? 0);
|
|
74
|
+
const cacheCreation = Number(
|
|
75
|
+
usage.cache_creation_input_tokens
|
|
76
|
+
?? usage.cacheCreationInputTokens
|
|
77
|
+
?? usage.cache_creation_tokens
|
|
78
|
+
?? 0,
|
|
79
|
+
);
|
|
80
|
+
const cacheRead = Number(
|
|
81
|
+
usage.cache_read_input_tokens
|
|
82
|
+
?? usage.cacheReadInputTokens
|
|
83
|
+
?? usage.cache_read_tokens
|
|
84
|
+
?? 0,
|
|
85
|
+
);
|
|
86
|
+
const totalCandidate = Number(usage.total_tokens ?? usage.totalTokens ?? Number.NaN);
|
|
87
|
+
const total = Number.isFinite(totalCandidate) && totalCandidate > 0
|
|
88
|
+
? totalCandidate
|
|
89
|
+
: input + output + cacheCreation + cacheRead;
|
|
90
|
+
if (!Number.isFinite(total) || total <= 0) return null;
|
|
91
|
+
return {
|
|
92
|
+
input: Math.max(0, Math.round(input)),
|
|
93
|
+
output: Math.max(0, Math.round(output)),
|
|
94
|
+
cacheCreation: Math.max(0, Math.round(cacheCreation)),
|
|
95
|
+
cacheRead: Math.max(0, Math.round(cacheRead)),
|
|
96
|
+
total: Math.max(0, Math.round(total)),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function extractUsage(payload) {
|
|
101
|
+
if (!payload || typeof payload !== "object") return null;
|
|
102
|
+
|
|
103
|
+
const queue = [payload];
|
|
104
|
+
const seen = new Set();
|
|
105
|
+
|
|
106
|
+
while (queue.length > 0) {
|
|
107
|
+
const current = queue.shift();
|
|
108
|
+
if (!current || typeof current !== "object") continue;
|
|
109
|
+
if (seen.has(current)) continue;
|
|
110
|
+
seen.add(current);
|
|
111
|
+
|
|
112
|
+
const directUsage = normalizeUsage(current.usage);
|
|
113
|
+
if (directUsage) return directUsage;
|
|
114
|
+
|
|
115
|
+
if (Array.isArray(current.content)) {
|
|
116
|
+
for (const item of current.content) queue.push(item);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for (const key of ["result", "payload", "response", "message", "data"]) {
|
|
120
|
+
if (current[key] && typeof current[key] === "object") {
|
|
121
|
+
queue.push(current[key]);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function bumpCounter(target, key, tokens) {
|
|
129
|
+
if (!key) return;
|
|
130
|
+
const prev = target[key] || 0;
|
|
131
|
+
target[key] = prev + tokens;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function pushTopKeys(inputMap, maxKeys = MAX_TOP_KEYS) {
|
|
135
|
+
const entries = Object.entries(inputMap || {});
|
|
136
|
+
entries.sort((a, b) => b[1] - a[1]);
|
|
137
|
+
return Object.fromEntries(entries.slice(0, maxKeys));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function extractFileKeys(args) {
|
|
141
|
+
if (!args || typeof args !== "object") return [];
|
|
142
|
+
const out = [];
|
|
143
|
+
const add = (value) => {
|
|
144
|
+
if (typeof value !== "string" || !value.trim()) return;
|
|
145
|
+
out.push(value.trim());
|
|
146
|
+
};
|
|
147
|
+
add(args.path);
|
|
148
|
+
add(args.file);
|
|
149
|
+
add(args.filename);
|
|
150
|
+
add(args.relative_path);
|
|
151
|
+
add(args.requestFilePath);
|
|
152
|
+
add(args.responseFilePath);
|
|
153
|
+
if (Array.isArray(args.paths)) {
|
|
154
|
+
for (const p of args.paths) add(p);
|
|
155
|
+
}
|
|
156
|
+
return Array.from(new Set(out)).slice(0, 5);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function detectSkillHints(payloadText) {
|
|
160
|
+
if (!payloadText) return [];
|
|
161
|
+
const matches = payloadText.match(/\$[a-z0-9_-]+/gi) || [];
|
|
162
|
+
return Array.from(new Set(matches.map((m) => m.replace(/^\$/, "")))).slice(0, 5);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function estimateTokens(input) {
|
|
166
|
+
return toTokenEstimate(input);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function parseUsageFromPayload(payload) {
|
|
170
|
+
return extractUsage(payload);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function classifyContextThreshold(percent) {
|
|
174
|
+
const p = clampThresholdPercent(percent);
|
|
175
|
+
if (p >= WARNING_LEVELS.critical.min) return { level: "critical", message: WARNING_LEVELS.critical.message };
|
|
176
|
+
if (p >= WARNING_LEVELS.warn.min) return { level: "warn", message: WARNING_LEVELS.warn.message };
|
|
177
|
+
if (p >= WARNING_LEVELS.info.min) return { level: "info", message: WARNING_LEVELS.info.message };
|
|
178
|
+
return { level: "ok", message: "" };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function formatContextUsage(usedTokens, limitTokens, percent = null) {
|
|
182
|
+
const used = Math.max(0, Math.round(Number(usedTokens) || 0));
|
|
183
|
+
const limit = Math.max(1, Math.round(Number(limitTokens) || DEFAULT_CONTEXT_LIMIT));
|
|
184
|
+
const pct = percent == null ? clampPercent((used / limit) * 100) : clampPercent(percent);
|
|
185
|
+
return `${formatTokenCount(used)}/${formatTokenCount(limit)} (${pct}%)`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function readContextMonitorSnapshot() {
|
|
189
|
+
return readJsonMigrate(CONTEXT_MONITOR_CACHE_PATH, CONTEXT_MONITOR_LEGACY_PATH, null);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function getStdinContextUsage(stdin) {
|
|
193
|
+
const limitTokens = Number(stdin?.context_window?.context_window_size || 0);
|
|
194
|
+
const nativePercent = Number(stdin?.context_window?.used_percentage);
|
|
195
|
+
const usage = stdin?.context_window?.current_usage || {};
|
|
196
|
+
const explicitUsed = Number(usage.total_tokens || 0);
|
|
197
|
+
const calculatedUsed = Number(usage.input_tokens || 0)
|
|
198
|
+
+ Number(usage.cache_creation_input_tokens || 0)
|
|
199
|
+
+ Number(usage.cache_read_input_tokens || 0);
|
|
200
|
+
const usedTokens = explicitUsed > 0 ? explicitUsed : calculatedUsed;
|
|
201
|
+
|
|
202
|
+
if (limitTokens > 0 && usedTokens > 0) {
|
|
203
|
+
return {
|
|
204
|
+
usedTokens: Math.round(usedTokens),
|
|
205
|
+
limitTokens: Math.round(limitTokens),
|
|
206
|
+
percent: clampPercent((usedTokens / limitTokens) * 100),
|
|
207
|
+
source: "stdin.tokens",
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (limitTokens > 0 && Number.isFinite(nativePercent)) {
|
|
212
|
+
const percent = clampPercent(nativePercent);
|
|
213
|
+
return {
|
|
214
|
+
usedTokens: Math.round((limitTokens * percent) / 100),
|
|
215
|
+
limitTokens: Math.round(limitTokens),
|
|
216
|
+
percent,
|
|
217
|
+
source: "stdin.percent",
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function buildContextUsageView(stdin, snapshot = null) {
|
|
224
|
+
const stdinUsage = getStdinContextUsage(stdin);
|
|
225
|
+
const monitor = snapshot || readContextMonitorSnapshot();
|
|
226
|
+
const fallbackLimit = Number(monitor?.limitTokens || DEFAULT_CONTEXT_LIMIT);
|
|
227
|
+
|
|
228
|
+
const usedTokens = stdinUsage?.usedTokens
|
|
229
|
+
?? Number(monitor?.usedTokens || 0);
|
|
230
|
+
const limitTokens = stdinUsage?.limitTokens
|
|
231
|
+
?? Math.max(1, fallbackLimit);
|
|
232
|
+
const percent = stdinUsage?.percent
|
|
233
|
+
?? (limitTokens > 0 ? clampPercent((usedTokens / limitTokens) * 100) : 0);
|
|
234
|
+
|
|
235
|
+
const warning = classifyContextThreshold(percent);
|
|
236
|
+
return {
|
|
237
|
+
usedTokens,
|
|
238
|
+
limitTokens,
|
|
239
|
+
percent,
|
|
240
|
+
display: formatContextUsage(usedTokens, limitTokens, percent),
|
|
241
|
+
warningLevel: warning.level,
|
|
242
|
+
warningMessage: warning.message,
|
|
243
|
+
warningTag: warning.level === "warn" ? "⚠ 압축 권장"
|
|
244
|
+
: warning.level === "critical" ? "‼ 분할 권장"
|
|
245
|
+
: warning.level === "info" ? "ℹ 절반 이상 사용"
|
|
246
|
+
: "",
|
|
247
|
+
source: stdinUsage?.source || (monitor ? "monitor" : "none"),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export function createContextMonitor(options = {}) {
|
|
252
|
+
const limitTokens = Number(options.limitTokens || DEFAULT_CONTEXT_LIMIT);
|
|
253
|
+
const cachePath = options.cachePath || CONTEXT_MONITOR_CACHE_PATH;
|
|
254
|
+
const logsDir = options.logsDir || CONTEXT_MONITOR_LOG_DIR;
|
|
255
|
+
const sessionId = options.sessionId || randomUUID().slice(0, 8);
|
|
256
|
+
const registerExitHooks = options.registerExitHooks !== false;
|
|
257
|
+
|
|
258
|
+
const state = {
|
|
259
|
+
sessionId,
|
|
260
|
+
startedAt: new Date().toISOString(),
|
|
261
|
+
updatedAt: null,
|
|
262
|
+
limitTokens,
|
|
263
|
+
usedTokens: 0,
|
|
264
|
+
requestTokens: 0,
|
|
265
|
+
responseTokens: 0,
|
|
266
|
+
exactUsageTokens: 0,
|
|
267
|
+
totalUpdates: 0,
|
|
268
|
+
maxPercent: 0,
|
|
269
|
+
warningLevel: "ok",
|
|
270
|
+
warningMessage: "",
|
|
271
|
+
bySkill: {},
|
|
272
|
+
byFile: {},
|
|
273
|
+
byTool: {},
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const writeSnapshot = () => {
|
|
277
|
+
const percent = clampPercent((state.usedTokens / state.limitTokens) * 100);
|
|
278
|
+
const warning = classifyContextThreshold(percent);
|
|
279
|
+
state.maxPercent = Math.max(state.maxPercent, percent);
|
|
280
|
+
state.warningLevel = warning.level;
|
|
281
|
+
state.warningMessage = warning.message;
|
|
282
|
+
state.updatedAt = new Date().toISOString();
|
|
283
|
+
safeWriteJson(cachePath, {
|
|
284
|
+
...state,
|
|
285
|
+
display: formatContextUsage(state.usedTokens, state.limitTokens, percent),
|
|
286
|
+
percent,
|
|
287
|
+
bySkill: pushTopKeys(state.bySkill),
|
|
288
|
+
byFile: pushTopKeys(state.byFile),
|
|
289
|
+
byTool: pushTopKeys(state.byTool),
|
|
290
|
+
});
|
|
291
|
+
return { percent, warning };
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const writeReport = (reason = "shutdown") => {
|
|
295
|
+
const percent = clampPercent((state.usedTokens / state.limitTokens) * 100);
|
|
296
|
+
const warning = classifyContextThreshold(percent);
|
|
297
|
+
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
298
|
+
const reportPath = join(logsDir, `context-usage-${state.sessionId}-${ts}.json`);
|
|
299
|
+
safeWriteJson(reportPath, {
|
|
300
|
+
sessionId: state.sessionId,
|
|
301
|
+
reason,
|
|
302
|
+
startedAt: state.startedAt,
|
|
303
|
+
endedAt: new Date().toISOString(),
|
|
304
|
+
summary: {
|
|
305
|
+
usedTokens: state.usedTokens,
|
|
306
|
+
limitTokens: state.limitTokens,
|
|
307
|
+
percent,
|
|
308
|
+
warningLevel: warning.level,
|
|
309
|
+
warningMessage: warning.message,
|
|
310
|
+
requestTokens: state.requestTokens,
|
|
311
|
+
responseTokens: state.responseTokens,
|
|
312
|
+
exactUsageTokens: state.exactUsageTokens,
|
|
313
|
+
updates: state.totalUpdates,
|
|
314
|
+
},
|
|
315
|
+
breakdown: {
|
|
316
|
+
skills: pushTopKeys(state.bySkill),
|
|
317
|
+
files: pushTopKeys(state.byFile),
|
|
318
|
+
tools: pushTopKeys(state.byTool),
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
return reportPath;
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
const record = ({
|
|
325
|
+
requestBody = null,
|
|
326
|
+
requestBytes = 0,
|
|
327
|
+
responseBody = null,
|
|
328
|
+
responseBytes = 0,
|
|
329
|
+
toolName = "",
|
|
330
|
+
} = {}) => {
|
|
331
|
+
const started = process.hrtime.bigint();
|
|
332
|
+
const reqObj = typeof requestBody === "object" ? requestBody : safeJsonParse(String(requestBody || ""));
|
|
333
|
+
const resObj = typeof responseBody === "object" ? responseBody : safeJsonParse(String(responseBody || ""));
|
|
334
|
+
|
|
335
|
+
const usage = parseUsageFromPayload(resObj);
|
|
336
|
+
const requestTokens = requestBytes > 0 ? toTokenEstimate(requestBytes) : toTokenEstimate(requestBody);
|
|
337
|
+
const responseTokens = usage?.total ?? (responseBytes > 0 ? toTokenEstimate(responseBytes) : toTokenEstimate(responseBody));
|
|
338
|
+
const totalTokens = Math.max(0, requestTokens + responseTokens);
|
|
339
|
+
|
|
340
|
+
const method = reqObj?.method || reqObj?.params?.name || "";
|
|
341
|
+
const name = toolName || reqObj?.params?.name || reqObj?.tool || "";
|
|
342
|
+
const args = reqObj?.params?.arguments || reqObj?.arguments || reqObj?.params || {};
|
|
343
|
+
const payloadText = normalizeText(requestBody).slice(0, MAX_CAPTURE_BYTES);
|
|
344
|
+
const skills = detectSkillHints(payloadText);
|
|
345
|
+
const files = extractFileKeys(args);
|
|
346
|
+
|
|
347
|
+
if (name) bumpCounter(state.byTool, String(name), totalTokens);
|
|
348
|
+
if (method?.includes("tool")) {
|
|
349
|
+
bumpCounter(state.byTool, String(method), totalTokens);
|
|
350
|
+
}
|
|
351
|
+
for (const file of files) bumpCounter(state.byFile, file, totalTokens);
|
|
352
|
+
for (const skill of skills) bumpCounter(state.bySkill, skill, totalTokens);
|
|
353
|
+
|
|
354
|
+
state.requestTokens += requestTokens;
|
|
355
|
+
state.responseTokens += responseTokens;
|
|
356
|
+
state.exactUsageTokens += usage?.total || 0;
|
|
357
|
+
state.usedTokens += totalTokens;
|
|
358
|
+
state.totalUpdates += 1;
|
|
359
|
+
|
|
360
|
+
const { percent, warning } = writeSnapshot();
|
|
361
|
+
const overheadMs = Number(process.hrtime.bigint() - started) / 1_000_000;
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
requestTokens,
|
|
365
|
+
responseTokens,
|
|
366
|
+
totalTokens,
|
|
367
|
+
usedTokens: state.usedTokens,
|
|
368
|
+
limitTokens: state.limitTokens,
|
|
369
|
+
percent,
|
|
370
|
+
warningLevel: warning.level,
|
|
371
|
+
warningMessage: warning.message,
|
|
372
|
+
display: formatContextUsage(state.usedTokens, state.limitTokens, percent),
|
|
373
|
+
overheadMs: Math.round(overheadMs * 1000) / 1000,
|
|
374
|
+
};
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
let reportWritten = false;
|
|
378
|
+
const flush = (reason = "shutdown") => {
|
|
379
|
+
if (reportWritten) return null;
|
|
380
|
+
reportWritten = true;
|
|
381
|
+
return writeReport(reason);
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
if (registerExitHooks) {
|
|
385
|
+
const flushOnExit = () => {
|
|
386
|
+
try { flush("process.exit"); } catch {}
|
|
387
|
+
};
|
|
388
|
+
process.once("exit", flushOnExit);
|
|
389
|
+
process.once("SIGINT", flushOnExit);
|
|
390
|
+
process.once("SIGTERM", flushOnExit);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return {
|
|
394
|
+
record,
|
|
395
|
+
flush,
|
|
396
|
+
snapshot: () => ({
|
|
397
|
+
...state,
|
|
398
|
+
bySkill: pushTopKeys(state.bySkill),
|
|
399
|
+
byFile: pushTopKeys(state.byFile),
|
|
400
|
+
byTool: pushTopKeys(state.byTool),
|
|
401
|
+
}),
|
|
402
|
+
};
|
|
403
|
+
}
|