triflux 10.4.0 → 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/.claude-plugin/marketplace.json +34 -0
- package/.claude-plugin/plugin.json +22 -0
- 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/config/mcp-registry.json +29 -0
- 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 +267 -256
- 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 +96 -58
- package/hub/adaptive-memory.mjs +156 -42
- package/hub/adaptive.mjs +60 -31
- package/hub/assign-callbacks.mjs +163 -126
- 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 +14 -14
- package/hub/delegator/service.mjs +88 -64
- package/hub/delegator/tool-definitions.mjs +35 -35
- package/hub/fullcycle.mjs +33 -17
- package/hub/gemini-adapter.mjs +69 -94
- package/hub/hitl.mjs +202 -143
- 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 +924 -791
- 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 +127 -61
- 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 +57 -37
- package/hub/team/cli/commands/control.mjs +29 -8
- package/hub/team/cli/commands/debug.mjs +95 -74
- package/hub/team/cli/commands/focus.mjs +80 -53
- 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 +31 -24
- 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 +50 -40
- package/hub/team/cli/commands/start/start-mux.mjs +122 -73
- package/hub/team/cli/commands/start/start-wt.mjs +86 -69
- 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 +13 -13
- package/hub/team/cli/index.mjs +2 -2
- package/hub/team/cli/manifest.mjs +38 -8
- package/hub/team/cli/render.mjs +52 -30
- package/hub/team/cli/services/attach-fallback.mjs +74 -54
- package/hub/team/cli/services/hub-client.mjs +42 -14
- package/hub/team/cli/services/member-selector.mjs +37 -30
- package/hub/team/cli/services/native-control.mjs +143 -116
- 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 +40 -30
- 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 +120 -77
- package/hub/team/orchestrator.mjs +166 -161
- 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 +675 -611
- package/hub/team/shared.mjs +13 -13
- 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 +411 -368
- package/hub/workers/claude-worker.mjs +162 -118
- package/hub/workers/codex-mcp.mjs +558 -507
- package/hub/workers/delegator-mcp.mjs +507 -333
- package/hub/workers/factory.mjs +21 -21
- 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 +56 -21
- 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/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 +139 -120
- package/scripts/keyword-detector.mjs +293 -272
- package/scripts/keyword-rules-expander.mjs +538 -521
- 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 +355 -118
- 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 +669 -554
- 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 +61 -57
- package/scripts/tfx-batch-stats.mjs +117 -96
- 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/idle-notif-cooldown.json +1 -1
- package/skills/.omc/state/last-tool-error.json +1 -1
- package/skills/.omc/state/subagent-tracking.json +1 -1
- 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-workspace/skill-snapshot/tfx-auto-codex/SKILL.md → tfx-auto-codex/SKILL.md.tmpl} +33 -4
- 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-workspace/skill-snapshot/tfx-gemini/SKILL.md → tfx-gemini/SKILL.md.tmpl} +16 -7
- 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 -16
- 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 +457 -0
- package/tui/core.mjs +266 -0
- package/tui/doctor.mjs +375 -0
- package/tui/gemini-profile.mjs +299 -0
- package/tui/monitor-data.mjs +152 -0
- package/tui/monitor.mjs +339 -0
- package/tui/setup.mjs +533 -0
- package/CLAUDE.md +0 -193
- package/references/hosts.json +0 -33
- package/skills/tfx-workspace/async-tests/run-tests.sh +0 -203
- package/skills/tfx-workspace/evals/evals.json +0 -79
- package/skills/tfx-workspace/iteration-1/benchmark.json +0 -162
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/eval_metadata.json +0 -11
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/grading.json +0 -9
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/outputs/analysis.md +0 -154
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/grading.json +0 -9
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/outputs/analysis.md +0 -126
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/eval_metadata.json +0 -11
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/grading.json +0 -9
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/outputs/analysis.md +0 -119
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/grading.json +0 -9
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/outputs/analysis.md +0 -115
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/eval_metadata.json +0 -10
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/grading.json +0 -8
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/outputs/analysis.md +0 -86
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/grading.json +0 -8
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/outputs/analysis.md +0 -81
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/multi-team-creation/eval_metadata.json +0 -12
- package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/grading.json +0 -10
- package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/outputs/analysis.md +0 -316
- package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/grading.json +0 -10
- package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/outputs/analysis.md +0 -352
- package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/review.html +0 -1325
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/eval_metadata.json +0 -12
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/grading.json +0 -10
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/outputs/analysis.md +0 -97
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/grading.json +0 -10
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/outputs/analysis.md +0 -94
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/eval_metadata.json +0 -12
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/grading.json +0 -10
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/outputs/analysis.md +0 -209
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/grading.json +0 -10
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/outputs/analysis.md +0 -193
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-2/benchmark.json +0 -62
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/eval_metadata.json +0 -13
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/grading.json +0 -11
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/outputs/analysis.md +0 -382
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/grading.json +0 -11
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/outputs/analysis.md +0 -333
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-2/review.html +0 -1325
- package/skills/tfx-workspace/skill-snapshot/tfx-auto/SKILL.md +0 -217
- package/skills/tfx-workspace/skill-snapshot/tfx-codex/SKILL.md +0 -65
- package/skills/tfx-workspace/skill-snapshot/tfx-doctor/SKILL.md +0 -94
- package/skills/tfx-workspace/skill-snapshot/tfx-hub/SKILL.md +0 -133
- package/skills/tfx-workspace/skill-snapshot/tfx-multi/SKILL.md +0 -426
- package/skills/tfx-workspace/skill-snapshot/tfx-setup/SKILL.md +0 -101
package/hub/pipeline/index.mjs
CHANGED
|
@@ -2,21 +2,25 @@
|
|
|
2
2
|
//
|
|
3
3
|
// 상태(state.mjs) + 전이(transitions.mjs) 통합 인터페이스
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import {
|
|
5
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import { join, resolve } from "node:path";
|
|
8
|
+
import { classifyIntent as _classifyIntent } from "../intent.mjs";
|
|
9
|
+
import { runConfidenceCheck } from "./gates/confidence.mjs";
|
|
10
|
+
import { runSelfCheck } from "./gates/selfcheck.mjs";
|
|
10
11
|
import {
|
|
11
12
|
ensurePipelineTable,
|
|
12
13
|
initPipelineState,
|
|
13
14
|
readPipelineState,
|
|
14
|
-
updatePipelineState,
|
|
15
15
|
removePipelineState,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import {
|
|
19
|
-
|
|
16
|
+
updatePipelineState,
|
|
17
|
+
} from "./state.mjs";
|
|
18
|
+
import {
|
|
19
|
+
canTransition,
|
|
20
|
+
ralphRestart,
|
|
21
|
+
TERMINAL,
|
|
22
|
+
transitionPhase,
|
|
23
|
+
} from "./transitions.mjs";
|
|
20
24
|
// deslop gate: 호출자가 scanDirectory/detectSlop 결과를 전달
|
|
21
25
|
|
|
22
26
|
/**
|
|
@@ -127,12 +131,12 @@ export function createPipeline(db, teamName, opts = {}) {
|
|
|
127
131
|
* @returns {string} 절대 경로
|
|
128
132
|
*/
|
|
129
133
|
writePlanFile(content) {
|
|
130
|
-
const safeName = teamName.replace(/[<>:"/\\|?*\x00-\x1f]/g,
|
|
131
|
-
const planDir = resolve(process.cwd(),
|
|
134
|
+
const safeName = teamName.replace(/[<>:"/\\|?*\x00-\x1f]/g, "_");
|
|
135
|
+
const planDir = resolve(process.cwd(), ".tfx", "plans");
|
|
132
136
|
mkdirSync(planDir, { recursive: true });
|
|
133
137
|
const planPath = join(planDir, `${safeName}-plan.md`);
|
|
134
|
-
writeFileSync(planPath, content,
|
|
135
|
-
this.setArtifact(
|
|
138
|
+
writeFileSync(planPath, content, "utf8");
|
|
139
|
+
this.setArtifact("plan_path", planPath);
|
|
136
140
|
return planPath;
|
|
137
141
|
},
|
|
138
142
|
|
|
@@ -170,20 +174,23 @@ export function createPipeline(db, teamName, opts = {}) {
|
|
|
170
174
|
const current = readPipelineState(db, teamName);
|
|
171
175
|
if (!current) return { ok: false, error: `파이프라인 없음: ${teamName}` };
|
|
172
176
|
|
|
173
|
-
if (current.phase !==
|
|
174
|
-
return {
|
|
177
|
+
if (current.phase !== "confidence") {
|
|
178
|
+
return {
|
|
179
|
+
ok: false,
|
|
180
|
+
error: `confidence gate는 confidence 단계에서만 실행 가능 (현재: ${current.phase})`,
|
|
181
|
+
};
|
|
175
182
|
}
|
|
176
183
|
|
|
177
184
|
const gate = runConfidenceCheck(planArtifact, context);
|
|
178
|
-
this.setArtifact(
|
|
185
|
+
this.setArtifact("confidence_result", gate);
|
|
179
186
|
|
|
180
|
-
if (gate.decision ===
|
|
181
|
-
const result = this.advance(
|
|
187
|
+
if (gate.decision === "abort") {
|
|
188
|
+
const result = this.advance("failed");
|
|
182
189
|
return { ok: true, gate, state: result.state };
|
|
183
190
|
}
|
|
184
191
|
|
|
185
192
|
// proceed 또는 alternative → exec로 전이
|
|
186
|
-
const result = this.advance(
|
|
193
|
+
const result = this.advance("exec");
|
|
187
194
|
return { ok: result.ok, gate, state: result.state, error: result.error };
|
|
188
195
|
},
|
|
189
196
|
|
|
@@ -198,15 +205,21 @@ export function createPipeline(db, teamName, opts = {}) {
|
|
|
198
205
|
const current = readPipelineState(db, teamName);
|
|
199
206
|
if (!current) return { ok: false, error: `파이프라인 없음: ${teamName}` };
|
|
200
207
|
|
|
201
|
-
if (current.phase !==
|
|
202
|
-
return {
|
|
208
|
+
if (current.phase !== "deslop") {
|
|
209
|
+
return {
|
|
210
|
+
ok: false,
|
|
211
|
+
error: `deslop gate는 deslop 단계에서만 실행 가능 (현재: ${current.phase})`,
|
|
212
|
+
};
|
|
203
213
|
}
|
|
204
214
|
|
|
205
|
-
const gate = deslopResult || {
|
|
206
|
-
|
|
215
|
+
const gate = deslopResult || {
|
|
216
|
+
files: [],
|
|
217
|
+
summary: { total: 0, clean: 0 },
|
|
218
|
+
};
|
|
219
|
+
this.setArtifact("deslop_result", gate);
|
|
207
220
|
|
|
208
221
|
// deslop은 항상 verify로 전이 (정보 제공 게이트, 차단 없음)
|
|
209
|
-
const result = this.advance(
|
|
222
|
+
const result = this.advance("verify");
|
|
210
223
|
return { ok: result.ok, gate, state: result.state, error: result.error };
|
|
211
224
|
},
|
|
212
225
|
|
|
@@ -222,20 +235,28 @@ export function createPipeline(db, teamName, opts = {}) {
|
|
|
222
235
|
const current = readPipelineState(db, teamName);
|
|
223
236
|
if (!current) return { ok: false, error: `파이프라인 없음: ${teamName}` };
|
|
224
237
|
|
|
225
|
-
if (current.phase !==
|
|
226
|
-
return {
|
|
238
|
+
if (current.phase !== "selfcheck") {
|
|
239
|
+
return {
|
|
240
|
+
ok: false,
|
|
241
|
+
error: `selfcheck gate는 selfcheck 단계에서만 실행 가능 (현재: ${current.phase})`,
|
|
242
|
+
};
|
|
227
243
|
}
|
|
228
244
|
|
|
229
245
|
const gate = runSelfCheck(execResult, verifyResult, requirements);
|
|
230
|
-
this.setArtifact(
|
|
246
|
+
this.setArtifact("selfcheck_result", gate);
|
|
231
247
|
|
|
232
248
|
if (gate.passed) {
|
|
233
|
-
const result = this.advance(
|
|
234
|
-
return {
|
|
249
|
+
const result = this.advance("complete");
|
|
250
|
+
return {
|
|
251
|
+
ok: result.ok,
|
|
252
|
+
gate,
|
|
253
|
+
state: result.state,
|
|
254
|
+
error: result.error,
|
|
255
|
+
};
|
|
235
256
|
}
|
|
236
257
|
|
|
237
258
|
// Red Flag 탐지 또는 필수 질문 실패 → fix
|
|
238
|
-
const result = this.advance(
|
|
259
|
+
const result = this.advance("fix");
|
|
239
260
|
return { ok: result.ok, gate, state: result.state, error: result.error };
|
|
240
261
|
},
|
|
241
262
|
};
|
|
@@ -248,7 +269,7 @@ let _tokenSnapshotMod = null;
|
|
|
248
269
|
async function loadTokenSnapshot() {
|
|
249
270
|
if (_tokenSnapshotMod) return _tokenSnapshotMod;
|
|
250
271
|
try {
|
|
251
|
-
_tokenSnapshotMod = await import(
|
|
272
|
+
_tokenSnapshotMod = await import("../../scripts/token-snapshot.mjs");
|
|
252
273
|
} catch {
|
|
253
274
|
_tokenSnapshotMod = null;
|
|
254
275
|
}
|
|
@@ -266,7 +287,9 @@ export async function benchmarkStart(label) {
|
|
|
266
287
|
try {
|
|
267
288
|
const snapshot = mod.takeSnapshot(label);
|
|
268
289
|
return { label, snapshot };
|
|
269
|
-
} catch {
|
|
290
|
+
} catch {
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
270
293
|
}
|
|
271
294
|
|
|
272
295
|
/**
|
|
@@ -286,14 +309,22 @@ export async function benchmarkEnd(preLabel, postLabel, options = {}) {
|
|
|
286
309
|
const diff = mod.computeDiff(preLabel, postLabel, options);
|
|
287
310
|
|
|
288
311
|
// 추가로 타임스탬프 기반 사본 저장
|
|
289
|
-
const diffsDir = join(
|
|
312
|
+
const diffsDir = join(
|
|
313
|
+
homedir(),
|
|
314
|
+
".omc",
|
|
315
|
+
"state",
|
|
316
|
+
"cx-auto-tokens",
|
|
317
|
+
"diffs",
|
|
318
|
+
);
|
|
290
319
|
mkdirSync(diffsDir, { recursive: true });
|
|
291
|
-
const ts = new Date().toISOString().replace(/[:.]/g,
|
|
320
|
+
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
292
321
|
const outPath = join(diffsDir, `${ts}.json`);
|
|
293
322
|
writeFileSync(outPath, JSON.stringify(diff, null, 2));
|
|
294
323
|
|
|
295
324
|
return diff;
|
|
296
|
-
} catch {
|
|
325
|
+
} catch {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
297
328
|
}
|
|
298
329
|
|
|
299
330
|
/**
|
|
@@ -310,9 +341,13 @@ export function triageWithIntent(prompt, threshold = 0.8) {
|
|
|
310
341
|
return { skip: false, routing: null, classification };
|
|
311
342
|
}
|
|
312
343
|
|
|
313
|
-
export {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
export {
|
|
344
|
+
export {
|
|
345
|
+
classifyIntent,
|
|
346
|
+
INTENT_CATEGORIES,
|
|
347
|
+
quickClassify,
|
|
348
|
+
} from "../intent.mjs";
|
|
349
|
+
export { autoFixSlop, detectSlop, scanDirectory } from "../quality/deslop.mjs";
|
|
350
|
+
export { CRITERIA, runConfidenceCheck } from "./gates/confidence.mjs";
|
|
351
|
+
export { QUESTIONS, RED_FLAGS, runSelfCheck } from "./gates/selfcheck.mjs";
|
|
352
|
+
export { ensurePipelineTable } from "./state.mjs";
|
|
353
|
+
export { ALLOWED, canTransition, PHASES, TERMINAL } from "./transitions.mjs";
|
package/hub/pipeline/state.mjs
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
// store.mjs의 기존 SQLite 연결(db)을 활용한다.
|
|
4
4
|
// pipeline_state 테이블은 schema.sql에 정의.
|
|
5
5
|
|
|
6
|
-
import { join } from
|
|
6
|
+
import { join } from "node:path";
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { ensureTfxDirs, TFX_STATE_DIR } from "../paths.mjs";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* 파이프라인 상태 DB 경로를 계산한다.
|
|
@@ -13,7 +13,7 @@ import { TFX_STATE_DIR, ensureTfxDirs } from '../paths.mjs';
|
|
|
13
13
|
* @returns {string}
|
|
14
14
|
*/
|
|
15
15
|
export function getPipelineStateDbPath(baseDir) {
|
|
16
|
-
return join(baseDir, TFX_STATE_DIR,
|
|
16
|
+
return join(baseDir, TFX_STATE_DIR, "state.db");
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -54,7 +54,7 @@ function getStatements(db) {
|
|
|
54
54
|
if (s) return s;
|
|
55
55
|
|
|
56
56
|
s = {
|
|
57
|
-
get: db.prepare(
|
|
57
|
+
get: db.prepare("SELECT * FROM pipeline_state WHERE team_name = ?"),
|
|
58
58
|
insert: db.prepare(`
|
|
59
59
|
INSERT INTO pipeline_state (team_name, phase, fix_attempt, fix_max, ralph_iteration, ralph_max, artifacts, phase_history, created_at, updated_at)
|
|
60
60
|
VALUES (@team_name, @phase, @fix_attempt, @fix_max, @ralph_iteration, @ralph_max, @artifacts, @phase_history, @created_at, @updated_at)
|
|
@@ -71,8 +71,8 @@ function getStatements(db) {
|
|
|
71
71
|
updated_at = @updated_at
|
|
72
72
|
WHERE team_name = @team_name
|
|
73
73
|
`),
|
|
74
|
-
remove: db.prepare(
|
|
75
|
-
list: db.prepare(
|
|
74
|
+
remove: db.prepare("DELETE FROM pipeline_state WHERE team_name = ?"),
|
|
75
|
+
list: db.prepare("SELECT * FROM pipeline_state ORDER BY updated_at DESC"),
|
|
76
76
|
};
|
|
77
77
|
STATEMENTS.set(db, s);
|
|
78
78
|
return s;
|
|
@@ -82,15 +82,15 @@ function parseRow(row) {
|
|
|
82
82
|
if (!row) return null;
|
|
83
83
|
return {
|
|
84
84
|
...row,
|
|
85
|
-
artifacts: JSON.parse(row.artifacts ||
|
|
86
|
-
phase_history: JSON.parse(row.phase_history ||
|
|
85
|
+
artifacts: JSON.parse(row.artifacts || "{}"),
|
|
86
|
+
phase_history: JSON.parse(row.phase_history || "[]"),
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
function serializeState(state) {
|
|
91
91
|
return {
|
|
92
92
|
team_name: state.team_name,
|
|
93
|
-
phase: state.phase ||
|
|
93
|
+
phase: state.phase || "plan",
|
|
94
94
|
fix_attempt: state.fix_attempt ?? 0,
|
|
95
95
|
fix_max: state.fix_max ?? 3,
|
|
96
96
|
ralph_iteration: state.ralph_iteration ?? 0,
|
|
@@ -115,7 +115,7 @@ export function initPipelineState(db, teamName, opts = {}) {
|
|
|
115
115
|
const now = Date.now();
|
|
116
116
|
const state = {
|
|
117
117
|
team_name: teamName,
|
|
118
|
-
phase:
|
|
118
|
+
phase: "plan",
|
|
119
119
|
fix_attempt: 0,
|
|
120
120
|
fix_max: opts.fix_max ?? 3,
|
|
121
121
|
ralph_iteration: 0,
|
|
@@ -5,23 +5,31 @@
|
|
|
5
5
|
// complete, failed = 터미널 상태
|
|
6
6
|
|
|
7
7
|
export const PHASES = [
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
"plan",
|
|
9
|
+
"prd",
|
|
10
|
+
"confidence",
|
|
11
|
+
"exec",
|
|
12
|
+
"deslop",
|
|
13
|
+
"verify",
|
|
14
|
+
"selfcheck",
|
|
15
|
+
"fix",
|
|
16
|
+
"complete",
|
|
17
|
+
"failed",
|
|
10
18
|
];
|
|
11
19
|
|
|
12
|
-
export const TERMINAL = new Set([
|
|
20
|
+
export const TERMINAL = new Set(["complete", "failed"]);
|
|
13
21
|
|
|
14
22
|
export const ALLOWED = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
plan: ["prd"],
|
|
24
|
+
prd: ["confidence"],
|
|
25
|
+
confidence: ["exec", "failed"],
|
|
26
|
+
exec: ["deslop"],
|
|
27
|
+
deslop: ["verify"],
|
|
28
|
+
verify: ["selfcheck", "fix", "failed"],
|
|
29
|
+
selfcheck: ["complete", "fix"],
|
|
30
|
+
fix: ["exec", "verify", "complete", "failed"],
|
|
31
|
+
complete: [],
|
|
32
|
+
failed: [],
|
|
25
33
|
};
|
|
26
34
|
|
|
27
35
|
/**
|
|
@@ -48,14 +56,14 @@ export function transitionPhase(state, nextPhase) {
|
|
|
48
56
|
if (!canTransition(current, nextPhase)) {
|
|
49
57
|
return {
|
|
50
58
|
ok: false,
|
|
51
|
-
error: `전이 불가: ${current} → ${nextPhase}. 허용: [${(ALLOWED[current] || []).join(
|
|
59
|
+
error: `전이 불가: ${current} → ${nextPhase}. 허용: [${(ALLOWED[current] || []).join(", ")}]`,
|
|
52
60
|
};
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
const next = { ...state, phase: nextPhase, updated_at: Date.now() };
|
|
56
64
|
|
|
57
65
|
// fix 단계 진입 시 attempt 증가 + 바운딩
|
|
58
|
-
if (nextPhase ===
|
|
66
|
+
if (nextPhase === "fix") {
|
|
59
67
|
next.fix_attempt = (state.fix_attempt || 0) + 1;
|
|
60
68
|
if (next.fix_attempt > (state.fix_max || 3)) {
|
|
61
69
|
return {
|
|
@@ -66,22 +74,24 @@ export function transitionPhase(state, nextPhase) {
|
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
// fix → exec 재진입 시 (fix 후 재실행)
|
|
69
|
-
if (current ===
|
|
77
|
+
if (current === "fix" && nextPhase === "exec") {
|
|
70
78
|
// fix_attempt 유지 (이미 fix 진입 시 증가됨)
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
// verify → fix → ... → verify 반복 후 fix_max 초과 시 ralph loop
|
|
74
|
-
if (nextPhase ===
|
|
82
|
+
if (nextPhase === "failed" && current === "fix") {
|
|
75
83
|
// ralph loop 반복 증가
|
|
76
84
|
next.ralph_iteration = (state.ralph_iteration || 0) + 1;
|
|
77
85
|
if (next.ralph_iteration > (state.ralph_max || 10)) {
|
|
78
86
|
// 최종 실패 — ralph loop도 초과
|
|
79
|
-
next.phase =
|
|
87
|
+
next.phase = "failed";
|
|
80
88
|
}
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
// phase_history 기록
|
|
84
|
-
const history = Array.isArray(state.phase_history)
|
|
92
|
+
const history = Array.isArray(state.phase_history)
|
|
93
|
+
? [...state.phase_history]
|
|
94
|
+
: [];
|
|
85
95
|
history.push({ from: current, to: nextPhase, at: Date.now() });
|
|
86
96
|
next.phase_history = history;
|
|
87
97
|
|
|
@@ -96,7 +106,7 @@ export function transitionPhase(state, nextPhase) {
|
|
|
96
106
|
*/
|
|
97
107
|
export function ralphRestart(state) {
|
|
98
108
|
if (TERMINAL.has(state.phase)) {
|
|
99
|
-
return { ok: false, error:
|
|
109
|
+
return { ok: false, error: "터미널 상태에서 재시작 불가" };
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
const iteration = (state.ralph_iteration || 0) + 1;
|
|
@@ -107,14 +117,21 @@ export function ralphRestart(state) {
|
|
|
107
117
|
};
|
|
108
118
|
}
|
|
109
119
|
|
|
110
|
-
const history = Array.isArray(state.phase_history)
|
|
111
|
-
|
|
120
|
+
const history = Array.isArray(state.phase_history)
|
|
121
|
+
? [...state.phase_history]
|
|
122
|
+
: [];
|
|
123
|
+
history.push({
|
|
124
|
+
from: state.phase,
|
|
125
|
+
to: "plan",
|
|
126
|
+
at: Date.now(),
|
|
127
|
+
ralph_restart: true,
|
|
128
|
+
});
|
|
112
129
|
|
|
113
130
|
return {
|
|
114
131
|
ok: true,
|
|
115
132
|
state: {
|
|
116
133
|
...state,
|
|
117
|
-
phase:
|
|
134
|
+
phase: "plan",
|
|
118
135
|
fix_attempt: 0,
|
|
119
136
|
ralph_iteration: iteration,
|
|
120
137
|
phase_history: history,
|
package/hub/platform.mjs
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
export const IS_WINDOWS = process.platform ===
|
|
6
|
-
export const IS_MAC = process.platform ===
|
|
7
|
-
export const IS_LINUX = process.platform ===
|
|
8
|
-
export const TEMP_DIR = IS_WINDOWS ? os.tmpdir() :
|
|
1
|
+
import { execFile, execFileSync, execSync } from "node:child_process";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
export const IS_WINDOWS = process.platform === "win32";
|
|
6
|
+
export const IS_MAC = process.platform === "darwin";
|
|
7
|
+
export const IS_LINUX = process.platform === "linux";
|
|
8
|
+
export const TEMP_DIR = IS_WINDOWS ? os.tmpdir() : "/tmp";
|
|
9
9
|
export const PATH_SEP = path.sep;
|
|
10
10
|
|
|
11
11
|
function getPathApi(platform) {
|
|
12
|
-
return platform ===
|
|
12
|
+
return platform === "win32" ? path.win32 : path.posix;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function coercePathInput(value, platform) {
|
|
16
|
-
const text = String(value ??
|
|
17
|
-
if (platform ===
|
|
18
|
-
return text.replaceAll(
|
|
16
|
+
const text = String(value ?? "");
|
|
17
|
+
if (platform === "win32") {
|
|
18
|
+
return text.replaceAll("/", "\\");
|
|
19
19
|
}
|
|
20
|
-
return text.replaceAll(
|
|
20
|
+
return text.replaceAll("\\", "/");
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function sanitizePipeSegment(value) {
|
|
24
|
-
return String(value ??
|
|
24
|
+
return String(value ?? "")
|
|
25
25
|
.trim()
|
|
26
|
-
.replace(/[<>:"/\\|?*\u0000-\u001f]+/gu,
|
|
27
|
-
.replace(/-+/g,
|
|
28
|
-
.replace(/^-|-$/g,
|
|
26
|
+
.replace(/[<>:"/\\|?*\u0000-\u001f]+/gu, "-")
|
|
27
|
+
.replace(/-+/g, "-")
|
|
28
|
+
.replace(/^-|-$/g, "");
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
function buildWhichCommandSpec(name, options = {}) {
|
|
32
|
-
const commandName = String(name ??
|
|
32
|
+
const commandName = String(name ?? "").trim();
|
|
33
33
|
if (!commandName) return null;
|
|
34
34
|
|
|
35
35
|
const platform = options.platform || process.platform;
|
|
36
36
|
return {
|
|
37
|
-
lookupCommand: platform ===
|
|
37
|
+
lookupCommand: platform === "win32" ? "where" : "which",
|
|
38
38
|
args: [commandName],
|
|
39
39
|
execOptions: {
|
|
40
|
-
encoding:
|
|
40
|
+
encoding: "utf8",
|
|
41
41
|
timeout: options.timeout ?? 5000,
|
|
42
|
-
stdio: [
|
|
42
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
43
43
|
windowsHide: true,
|
|
44
44
|
env: options.env || process.env,
|
|
45
45
|
cwd: options.cwd,
|
|
@@ -48,10 +48,12 @@ function buildWhichCommandSpec(name, options = {}) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
function parseWhichCommandOutput(output) {
|
|
51
|
-
return
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
return (
|
|
52
|
+
String(output)
|
|
53
|
+
.split(/\r?\n/u)
|
|
54
|
+
.map((line) => line.trim())
|
|
55
|
+
.find(Boolean) || null
|
|
56
|
+
);
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
function execFileAsync(command, args, options, execFileFn = execFile) {
|
|
@@ -69,7 +71,7 @@ function execFileAsync(command, args, options, execFileFn = execFile) {
|
|
|
69
71
|
/**
|
|
70
72
|
* 경로를 플랫폼에 맞게 정규화합니다.
|
|
71
73
|
* Windows 환경에서는 역슬래시(\)를 슬래시(/)로 변환하여 반환합니다.
|
|
72
|
-
*
|
|
74
|
+
*
|
|
73
75
|
* @param {string} value - 정규화할 경로 문자열
|
|
74
76
|
* @param {object} [options] - 옵션
|
|
75
77
|
* @param {string} [options.platform] - 대상 플랫폼 (기본값: process.platform)
|
|
@@ -80,8 +82,8 @@ export function normalizePath(value, options = {}) {
|
|
|
80
82
|
const pathApi = getPathApi(platform);
|
|
81
83
|
const normalized = pathApi.normalize(coercePathInput(value, platform));
|
|
82
84
|
|
|
83
|
-
if (platform ===
|
|
84
|
-
return normalized.replaceAll(
|
|
85
|
+
if (platform === "win32") {
|
|
86
|
+
return normalized.replaceAll("\\", "/");
|
|
85
87
|
}
|
|
86
88
|
return normalized;
|
|
87
89
|
}
|
|
@@ -89,7 +91,7 @@ export function normalizePath(value, options = {}) {
|
|
|
89
91
|
/**
|
|
90
92
|
* 시스템에서 실행 가능한 명령의 절대 경로를 찾습니다.
|
|
91
93
|
* Windows에서는 'where', Unix 계열에서는 'which' 명령을 사용합니다.
|
|
92
|
-
*
|
|
94
|
+
*
|
|
93
95
|
* @param {string} name - 찾을 명령어 이름
|
|
94
96
|
* @param {object} [options] - 옵션
|
|
95
97
|
* @param {string} [options.platform] - 대상 플랫폼
|
|
@@ -103,7 +105,11 @@ export function whichCommand(name, options = {}) {
|
|
|
103
105
|
if (!spec) return null;
|
|
104
106
|
|
|
105
107
|
try {
|
|
106
|
-
const output = execFileSync(
|
|
108
|
+
const output = execFileSync(
|
|
109
|
+
spec.lookupCommand,
|
|
110
|
+
spec.args,
|
|
111
|
+
spec.execOptions,
|
|
112
|
+
);
|
|
107
113
|
return parseWhichCommandOutput(output);
|
|
108
114
|
} catch {
|
|
109
115
|
return null;
|
|
@@ -130,7 +136,7 @@ export async function whichCommandAsync(name, options = {}) {
|
|
|
130
136
|
/**
|
|
131
137
|
* 프로세스를 종료합니다.
|
|
132
138
|
* Windows에서는 트리 구조 종료(/T) 및 강제 종료(/F)를 지원합니다.
|
|
133
|
-
*
|
|
139
|
+
*
|
|
134
140
|
* @param {number|string} pid - 종료할 프로세스 ID
|
|
135
141
|
* @param {object} [options] - 옵션
|
|
136
142
|
* @param {string} [options.platform] - 대상 플랫폼
|
|
@@ -145,23 +151,23 @@ export function killProcess(pid, options = {}) {
|
|
|
145
151
|
if (!Number.isInteger(numericPid) || numericPid <= 0) return false;
|
|
146
152
|
|
|
147
153
|
const platform = options.platform || process.platform;
|
|
148
|
-
const signal = options.signal ||
|
|
154
|
+
const signal = options.signal || "SIGTERM";
|
|
149
155
|
const tree = options.tree === true;
|
|
150
|
-
const force = options.force === true || signal ===
|
|
156
|
+
const force = options.force === true || signal === "SIGKILL";
|
|
151
157
|
|
|
152
158
|
try {
|
|
153
|
-
if (platform ===
|
|
159
|
+
if (platform === "win32" && (tree || force)) {
|
|
154
160
|
const command = [
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
"taskkill",
|
|
162
|
+
"/PID",
|
|
157
163
|
String(numericPid),
|
|
158
|
-
tree ?
|
|
159
|
-
force ?
|
|
164
|
+
tree ? "/T" : "",
|
|
165
|
+
force ? "/F" : "",
|
|
160
166
|
]
|
|
161
167
|
.filter(Boolean)
|
|
162
|
-
.join(
|
|
168
|
+
.join(" ");
|
|
163
169
|
execSync(command, {
|
|
164
|
-
stdio:
|
|
170
|
+
stdio: "ignore",
|
|
165
171
|
timeout: options.timeout ?? 5000,
|
|
166
172
|
windowsHide: true,
|
|
167
173
|
});
|
|
@@ -178,7 +184,7 @@ export function killProcess(pid, options = {}) {
|
|
|
178
184
|
/**
|
|
179
185
|
* 플랫폼별 IPC 파이프 또는 소켓 경로를 생성합니다.
|
|
180
186
|
* Windows에서는 네임드 파이프 경로를, Unix 계열에서는 도메인 소켓 파일 경로를 반환합니다.
|
|
181
|
-
*
|
|
187
|
+
*
|
|
182
188
|
* @param {string} name - 파이프/소켓 기본 이름
|
|
183
189
|
* @param {number|string} [pid=process.pid] - 프로세스 ID (식별자 추가용)
|
|
184
190
|
* @param {object} [options] - 옵션
|
|
@@ -188,10 +194,10 @@ export function killProcess(pid, options = {}) {
|
|
|
188
194
|
*/
|
|
189
195
|
export function pipePath(name, pid = process.pid, options = {}) {
|
|
190
196
|
const platform = options.platform || process.platform;
|
|
191
|
-
const safeName = sanitizePipeSegment(name) ||
|
|
192
|
-
const suffix = pid == null || pid ===
|
|
197
|
+
const safeName = sanitizePipeSegment(name) || "triflux";
|
|
198
|
+
const suffix = pid == null || pid === "" ? safeName : `${safeName}-${pid}`;
|
|
193
199
|
|
|
194
|
-
if (platform ===
|
|
200
|
+
if (platform === "win32") {
|
|
195
201
|
return `\\\\.\\pipe\\${suffix}`;
|
|
196
202
|
}
|
|
197
203
|
|
|
@@ -202,7 +208,7 @@ export function pipePath(name, pid = process.pid, options = {}) {
|
|
|
202
208
|
/**
|
|
203
209
|
* 특정 경로가 대상 디렉토리 내부에 포함되는지 확인합니다.
|
|
204
210
|
* 대소문자 구분 및 상대 경로 처리를 플랫폼 규격에 맞게 수행합니다.
|
|
205
|
-
*
|
|
211
|
+
*
|
|
206
212
|
* @param {string} resolvedPath - 검사할 절대 경로
|
|
207
213
|
* @param {string} dir - 기준이 되는 대상 디렉토리 경로
|
|
208
214
|
* @param {object} [options] - 옵션
|
|
@@ -217,9 +223,12 @@ export function isPathWithin(resolvedPath, dir, options = {}) {
|
|
|
217
223
|
const left = pathApi.resolve(coercePathInput(resolvedPath, platform));
|
|
218
224
|
const right = pathApi.resolve(coercePathInput(dir, platform));
|
|
219
225
|
|
|
220
|
-
const normalizedLeft = platform ===
|
|
221
|
-
const normalizedRight = platform ===
|
|
226
|
+
const normalizedLeft = platform === "win32" ? left.toLowerCase() : left;
|
|
227
|
+
const normalizedRight = platform === "win32" ? right.toLowerCase() : right;
|
|
222
228
|
const relative = pathApi.relative(normalizedRight, normalizedLeft);
|
|
223
229
|
|
|
224
|
-
return
|
|
230
|
+
return (
|
|
231
|
+
relative === "" ||
|
|
232
|
+
(!relative.startsWith("..") && !pathApi.isAbsolute(relative))
|
|
233
|
+
);
|
|
225
234
|
}
|