triflux 10.0.6 → 10.1.1
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/LICENSE +21 -21
- package/bin/triflux.mjs +30 -20
- package/config/mcp-registry.json +29 -0
- package/hooks/error-context.mjs +35 -7
- package/hooks/hook-orchestrator.mjs +14 -0
- package/hooks/hook-registry.json +10 -0
- package/hooks/safety-guard.mjs +70 -1
- package/hub/adaptive-inject.mjs +1 -1
- package/hub/assign-callbacks.mjs +120 -120
- package/hub/bridge.mjs +1 -1
- package/hub/codex-adapter.mjs +1 -1
- package/hub/codex-compat.mjs +1 -0
- package/hub/delegator/index.mjs +14 -14
- package/hub/delegator/tool-definitions.mjs +35 -35
- package/hub/fullcycle.mjs +1 -0
- package/hub/hitl.mjs +143 -143
- package/hub/intent.mjs +4 -1
- package/hub/lib/memory-store.mjs +22 -0
- package/hub/promote-penalties.mjs +120 -0
- package/hub/public/dashboard.html +7 -7
- package/hub/quality/deslop.mjs +1 -1
- package/hub/reflexion.mjs +40 -56
- package/hub/research.mjs +1 -0
- package/hub/router.mjs +791 -791
- package/hub/server.mjs +23 -0
- package/hub/session-fingerprint.mjs +3 -3
- package/hub/store-adapter.mjs +51 -20
- package/hub/store.mjs +8 -8
- package/hub/team/cli/commands/attach.mjs +37 -37
- package/hub/team/cli/commands/debug.mjs +74 -74
- package/hub/team/cli/commands/focus.mjs +53 -53
- package/hub/team/cli/commands/list.mjs +24 -24
- package/hub/team/cli/commands/start/start-headless.mjs +5 -3
- package/hub/team/cli/commands/start/start-in-process.mjs +40 -40
- package/hub/team/cli/commands/start/start-mux.mjs +73 -73
- package/hub/team/cli/commands/start/start-wt.mjs +69 -69
- package/hub/team/cli/commands/tasks.mjs +13 -13
- package/hub/team/cli/render.mjs +30 -30
- package/hub/team/cli/services/attach-fallback.mjs +54 -54
- package/hub/team/cli/services/hub-client.mjs +1 -1
- package/hub/team/cli/services/member-selector.mjs +30 -30
- package/hub/team/cli/services/native-control.mjs +116 -116
- package/hub/team/cli/services/task-model.mjs +30 -30
- package/hub/team/conductor.mjs +671 -671
- package/hub/team/dashboard-open.mjs +1 -1
- package/hub/team/headless.mjs +1156 -1156
- package/hub/team/notify.mjs +1 -1
- package/hub/team/orchestrator.mjs +161 -161
- package/hub/team/psmux.mjs +67 -5
- package/hub/team/remote-probe.mjs +1 -1
- package/hub/team/remote-watcher.mjs +1 -1
- package/hub/team/session.mjs +611 -611
- package/hub/team/shared.mjs +13 -13
- package/hub/team/swarm-hypervisor.mjs +3 -4
- package/hub/team/tui-remote-adapter.mjs +3 -3
- package/hub/team/tui-viewer.mjs +0 -1
- package/hub/team/tui.mjs +12 -15
- package/hub/team/worktree-lifecycle.mjs +1 -1
- package/hub/token-mode.mjs +4 -1
- package/hub/tray.mjs +368 -368
- package/hub/workers/codex-mcp.mjs +507 -507
- package/hub/workers/delegator-mcp.mjs +1 -2
- package/hub/workers/factory.mjs +21 -21
- package/hud/providers/codex.mjs +24 -2
- package/package.json +55 -22
- package/scripts/__tests__/skill-template.test.mjs +0 -1
- package/scripts/claudemd-sync.mjs +1 -1
- package/scripts/cli-route.sh +3 -3
- package/scripts/completions/tfx.bash +47 -47
- package/scripts/completions/tfx.fish +44 -44
- package/scripts/completions/tfx.zsh +83 -83
- package/scripts/cross-review-gate.mjs +1 -1
- package/scripts/headless-guard.mjs +44 -16
- package/scripts/hub-ensure.mjs +120 -120
- package/scripts/keyword-detector.mjs +272 -272
- package/scripts/keyword-rules-expander.mjs +521 -521
- package/scripts/lib/mcp-filter.mjs +2 -2
- package/scripts/lib/mcp-guard-engine.mjs +1 -1
- package/scripts/lib/mcp-server-catalog.mjs +118 -118
- package/scripts/lib/psmux-info.mjs +2 -2
- package/scripts/lib/skill-template.mjs +4 -4
- package/scripts/mcp-check.mjs +1 -1
- package/scripts/mcp-gateway-config.mjs +1 -1
- package/scripts/mcp-gateway-ensure.mjs +1 -1
- package/scripts/mcp-gateway-start.mjs +1 -1
- package/scripts/notion-read.mjs +553 -553
- package/scripts/remote-spawn.mjs +1 -1
- package/scripts/session-spawn-helper.mjs +1 -3
- package/scripts/setup.mjs +1 -1
- package/scripts/test-lock.mjs +1 -1
- package/scripts/test-tfx-route-no-claude-native.mjs +57 -57
- package/scripts/tfx-batch-stats.mjs +96 -96
- package/scripts/tfx-route-post.mjs +6 -6
- package/scripts/tfx-route.sh +6 -0
- package/tui/codex-profile.mjs +402 -0
- package/tui/core.mjs +236 -0
- package/tui/doctor.mjs +328 -0
- package/tui/gemini-profile.mjs +254 -0
- package/tui/monitor-data.mjs +148 -0
- package/tui/monitor.mjs +295 -0
- package/tui/setup.mjs +442 -0
- package/CLAUDE.md +0 -171
- package/mesh/index.mjs +0 -63
- package/mesh/mesh-budget.mjs +0 -128
- package/mesh/mesh-heartbeat.mjs +0 -100
- package/mesh/mesh-protocol.mjs +0 -96
- package/mesh/mesh-queue.mjs +0 -165
- package/mesh/mesh-registry.mjs +0 -78
- package/mesh/mesh-router.mjs +0 -76
- package/references/hosts.json +0 -33
- package/skills/.omc/state/agent-replay-8f0e10a9-9693-4410-96f5-a6b07e8ed995.jsonl +0 -1
- package/skills/.omc/state/idle-notif-cooldown.json +0 -3
- package/skills/.omc/state/last-tool-error.json +0 -7
- package/skills/.omc/state/subagent-tracking.json +0 -7
- package/skills/tfx-remote-spawn/references/hosts.json +0 -16
- 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-auto-codex/SKILL.md +0 -77
- 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-gemini/SKILL.md +0 -82
- 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
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
|
3
|
+
"name": "triflux",
|
|
4
|
+
"description": "CLI-first multi-model orchestrator — Codex/Gemini/Claude routing with DAG execution, auto-triage, and cost optimization",
|
|
5
|
+
"owner": {
|
|
6
|
+
"name": "tellang"
|
|
7
|
+
},
|
|
8
|
+
"plugins": [
|
|
9
|
+
{
|
|
10
|
+
"name": "triflux",
|
|
11
|
+
"description": "CLI-first multi-model orchestrator for Claude Code. Routes tasks to Codex, Gemini, and Claude CLIs with automatic triage, DAG-based parallel execution, headless psmux sessions, and cost-optimized routing. Includes 41 skills, HUD status bar, hook orchestrator, and shell-based CLI routing.",
|
|
12
|
+
"version": "9.7.14",
|
|
13
|
+
"author": {
|
|
14
|
+
"name": "tellang"
|
|
15
|
+
},
|
|
16
|
+
"source": {
|
|
17
|
+
"source": "npm",
|
|
18
|
+
"package": "triflux"
|
|
19
|
+
},
|
|
20
|
+
"category": "productivity",
|
|
21
|
+
"homepage": "https://github.com/tellang/triflux",
|
|
22
|
+
"tags": [
|
|
23
|
+
"multi-model",
|
|
24
|
+
"codex",
|
|
25
|
+
"gemini",
|
|
26
|
+
"cli-routing",
|
|
27
|
+
"orchestration",
|
|
28
|
+
"cost-optimization",
|
|
29
|
+
"dag-execution"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"version": "9.7.14"
|
|
34
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "triflux",
|
|
3
|
+
"version": "10.0.0",
|
|
4
|
+
"description": "CLI-first multi-model orchestrator for Claude Code — route tasks to Codex, Gemini, and Claude",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "tellang"
|
|
7
|
+
},
|
|
8
|
+
"repository": "https://github.com/tellang/triflux",
|
|
9
|
+
"homepage": "https://github.com/tellang/triflux",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"claude-code",
|
|
13
|
+
"plugin",
|
|
14
|
+
"codex",
|
|
15
|
+
"gemini",
|
|
16
|
+
"cli-routing",
|
|
17
|
+
"orchestration",
|
|
18
|
+
"multi-model"
|
|
19
|
+
],
|
|
20
|
+
"skills": "./skills/",
|
|
21
|
+
"hooks": "./hooks/hooks.json"
|
|
22
|
+
}
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 tellang
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 tellang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/bin/triflux.mjs
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
import {
|
|
28
28
|
SYNC_MAP, SKILL_ALIASES, REQUIRED_CODEX_PROFILES, LEGACY_CODEX_MODELS,
|
|
29
29
|
syncAliasedSkillDir, hasProfileSection, replaceProfileSection,
|
|
30
|
-
ensureCodexProfiles, getVersion, cleanupStaleSkills,
|
|
30
|
+
ensureCodexProfiles, getVersion, cleanupStaleSkills,
|
|
31
31
|
extractManagedHookFilename, getManagedRegistryHooks, ensureHooksInSettings,
|
|
32
32
|
ensureCodexHubServerConfig,
|
|
33
33
|
} from "../scripts/setup.mjs";
|
|
@@ -65,14 +65,14 @@ const GREEN_BRIGHT = "\x1b[38;5;82m";
|
|
|
65
65
|
const RED_BRIGHT = "\x1b[38;5;196m";
|
|
66
66
|
|
|
67
67
|
// ── 브랜드 요소 ──
|
|
68
|
-
const
|
|
68
|
+
const _BRAND = `${AMBER}${BOLD}triflux${RESET}`;
|
|
69
69
|
const VER = `${DIM}v${PKG.version}${RESET}`;
|
|
70
70
|
const LINE = `${GRAY}${"─".repeat(48)}${RESET}`;
|
|
71
|
-
const
|
|
71
|
+
const _DOT = `${GRAY}·${RESET}`;
|
|
72
72
|
const STALE_TEAM_MAX_AGE_SEC = 3600;
|
|
73
73
|
const ANSI_PATTERN = /\x1B\[[0-?]*[ -/]*[@-~]/g;
|
|
74
74
|
|
|
75
|
-
const
|
|
75
|
+
const _EXIT_SUCCESS = 0;
|
|
76
76
|
const EXIT_ERROR = 1;
|
|
77
77
|
const EXIT_ARG_ERROR = 2;
|
|
78
78
|
const EXIT_CLI_MISSING = 3;
|
|
@@ -719,12 +719,11 @@ function previewMcpRegistrationActions(mcpUrl) {
|
|
|
719
719
|
function previewClaudeRoutingAction() {
|
|
720
720
|
const globalClaudePath = join(CLAUDE_DIR, "CLAUDE.md");
|
|
721
721
|
const projectClaudePath = join(PKG_ROOT, "CLAUDE.md");
|
|
722
|
-
const projectContent = existsSync(projectClaudePath)
|
|
723
|
-
? readFileSync(projectClaudePath, "utf8")
|
|
724
|
-
: "";
|
|
725
|
-
const projectSection = extractMarkdownSection(projectContent, TFX_SECTION_HEADING);
|
|
726
722
|
|
|
727
|
-
|
|
723
|
+
let _routingTable;
|
|
724
|
+
try {
|
|
725
|
+
_routingTable = getLatestRoutingTable();
|
|
726
|
+
} catch {
|
|
728
727
|
return {
|
|
729
728
|
type: "claude-guidance",
|
|
730
729
|
path: globalClaudePath,
|
|
@@ -734,18 +733,23 @@ function previewClaudeRoutingAction() {
|
|
|
734
733
|
};
|
|
735
734
|
}
|
|
736
735
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
736
|
+
if (!existsSync(globalClaudePath)) {
|
|
737
|
+
return {
|
|
738
|
+
type: "claude-guidance",
|
|
739
|
+
path: globalClaudePath,
|
|
740
|
+
source: projectClaudePath,
|
|
741
|
+
change: "create",
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
const globalContent = readFileSync(globalClaudePath, "utf8");
|
|
746
|
+
const hasRouting = globalContent.includes("<routing>") || globalContent.includes("## triflux CLI 라우팅");
|
|
741
747
|
|
|
742
748
|
return {
|
|
743
749
|
type: "claude-guidance",
|
|
744
750
|
path: globalClaudePath,
|
|
745
751
|
source: projectClaudePath,
|
|
746
|
-
change:
|
|
747
|
-
heading: TFX_SECTION_HEADING,
|
|
748
|
-
summary: TFX_GLOBAL_SUMMARY_SECTION,
|
|
752
|
+
change: hasRouting ? "noop" : "create",
|
|
749
753
|
};
|
|
750
754
|
}
|
|
751
755
|
|
|
@@ -2073,7 +2077,7 @@ async function cmdDoctor(options = {}) {
|
|
|
2073
2077
|
// 14. Stale Teams (Claude teams/ + tasks/ 자동 감지)
|
|
2074
2078
|
section("Stale Teams");
|
|
2075
2079
|
const teamsDir = join(CLAUDE_DIR, "teams");
|
|
2076
|
-
const
|
|
2080
|
+
const _tasksDir = join(CLAUDE_DIR, "tasks");
|
|
2077
2081
|
if (existsSync(teamsDir)) {
|
|
2078
2082
|
try {
|
|
2079
2083
|
const teamDirs = readdirSync(teamsDir).filter(d => {
|
|
@@ -2130,8 +2134,8 @@ async function cmdDoctor(options = {}) {
|
|
|
2130
2134
|
// 프로세스 명령줄에서 세션 ID 매칭 (tmux 없는 in-process 팀 지원)
|
|
2131
2135
|
if (!hasActiveMember && teamConfig.leadSessionId) {
|
|
2132
2136
|
try {
|
|
2133
|
-
const
|
|
2134
|
-
const safeToken = teamConfig.leadSessionId.slice(0, 8).replace(/[^a-zA-Z0-9
|
|
2137
|
+
const _sessionToken = teamConfig.leadSessionId.toLowerCase();
|
|
2138
|
+
const safeToken = teamConfig.leadSessionId.slice(0, 8).replace(/[^a-zA-Z0-9-]/g, '');
|
|
2135
2139
|
// Claude Code 프로세스에서 세션 ID 검색
|
|
2136
2140
|
if (process.platform === "win32") {
|
|
2137
2141
|
const psOut = execSync(
|
|
@@ -3723,7 +3727,7 @@ async function cmdHub(args = [], options = {}) {
|
|
|
3723
3727
|
process.kill(info.pid, "SIGTERM");
|
|
3724
3728
|
try { unlinkSync(HUB_PID_FILE); } catch {}
|
|
3725
3729
|
console.log(`\n ${GREEN_BRIGHT}✓${RESET} hub 종료됨 (PID ${info.pid})\n`);
|
|
3726
|
-
} catch (
|
|
3730
|
+
} catch (_e) {
|
|
3727
3731
|
try { unlinkSync(HUB_PID_FILE); } catch {}
|
|
3728
3732
|
console.log(`\n ${DIM}hub 프로세스 없음 — PID 파일 정리됨${RESET}\n`);
|
|
3729
3733
|
}
|
|
@@ -3884,6 +3888,12 @@ async function main() {
|
|
|
3884
3888
|
case "hub":
|
|
3885
3889
|
await cmdHub(cmdArgs, { json: JSON_OUTPUT && (cmdArgs[0] || "status") === "status" });
|
|
3886
3890
|
return;
|
|
3891
|
+
case "monitor": {
|
|
3892
|
+
const { createMonitor } = await import("../tui/monitor.mjs");
|
|
3893
|
+
const mon = createMonitor();
|
|
3894
|
+
await mon.start();
|
|
3895
|
+
break;
|
|
3896
|
+
}
|
|
3887
3897
|
case "tray": {
|
|
3888
3898
|
const trayUrl = new URL("../hub/tray.mjs", import.meta.url);
|
|
3889
3899
|
const trayPath = fileURLToPath(trayUrl);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "mcp-registry-schema",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"description": "MCP 서버 중앙 레지스트리 — 진실의 원천",
|
|
5
|
+
"defaults": {
|
|
6
|
+
"transport": "hub-url",
|
|
7
|
+
"hub_base": "http://127.0.0.1:27888"
|
|
8
|
+
},
|
|
9
|
+
"servers": {
|
|
10
|
+
"tfx-hub": {
|
|
11
|
+
"transport": "hub-url",
|
|
12
|
+
"url": "http://127.0.0.1:27888/mcp",
|
|
13
|
+
"safe": true,
|
|
14
|
+
"targets": ["claude", "gemini", "codex"],
|
|
15
|
+
"description": "triflux Hub MCP 서버"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"policies": {
|
|
19
|
+
"stdio_action": "replace-with-hub",
|
|
20
|
+
"unknown_server_action": "warn",
|
|
21
|
+
"watched_paths": [
|
|
22
|
+
"~/.gemini/settings.json",
|
|
23
|
+
"~/.codex/config.toml",
|
|
24
|
+
"~/.claude/settings.json",
|
|
25
|
+
"~/.claude/settings.local.json",
|
|
26
|
+
".mcp.json"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
}
|
package/hooks/error-context.mjs
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
// 도구 실패 시 에러 패턴을 분석하여 해결 힌트를 additionalContext로 주입한다.
|
|
5
5
|
// Claude가 동일 에러를 반복하지 않도록 구체적 가이드를 제공.
|
|
6
6
|
|
|
7
|
-
import { readFileSync } from "node:fs";
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
8
9
|
|
|
9
10
|
// ── 에러 패턴 → 해결 힌트 매핑 ─────────────────────────────
|
|
10
11
|
const ERROR_HINTS = [
|
|
@@ -128,16 +129,43 @@ function main() {
|
|
|
128
129
|
JSON.stringify(input.tool_result || ""),
|
|
129
130
|
].join("\n");
|
|
130
131
|
|
|
132
|
+
// ── reflexion 적응형 학습: safety-guard/headless-guard 차단을 패널티로 기록 ──
|
|
133
|
+
const isSafetyBlock = /\[(?:safety-guard|headless-guard)\].*(?:BLOCKED|차단)/i.test(errorText);
|
|
134
|
+
if (isSafetyBlock) {
|
|
135
|
+
try {
|
|
136
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
137
|
+
const penaltyDir = join(home, ".triflux", "reflexion");
|
|
138
|
+
mkdirSync(penaltyDir, { recursive: true });
|
|
139
|
+
const penaltyFile = join(penaltyDir, "pending-penalties.jsonl");
|
|
140
|
+
const command = input.tool_input?.command || "";
|
|
141
|
+
const entry = {
|
|
142
|
+
ts: new Date().toISOString(),
|
|
143
|
+
type: "guard_block",
|
|
144
|
+
tool: input.tool_name || "Bash",
|
|
145
|
+
error_pattern: errorText.match(/\[.*?\]\s*(.{0,120})/)?.[1] || errorText.slice(0, 120),
|
|
146
|
+
command_preview: command.slice(0, 200),
|
|
147
|
+
source: errorText.includes("safety-guard") ? "safety-guard" : "headless-guard",
|
|
148
|
+
};
|
|
149
|
+
writeFileSync(penaltyFile, JSON.stringify(entry) + "\n", { flag: "a" });
|
|
150
|
+
} catch { /* reflexion 기록 실패는 무시 — 힌트 출력에 영향 주지 않음 */ }
|
|
151
|
+
}
|
|
152
|
+
|
|
131
153
|
const hints = findHints(errorText);
|
|
132
|
-
|
|
154
|
+
// safety-guard 차단에는 guard가 이미 구체적 안내를 제공하므로 추가 힌트 불필요
|
|
155
|
+
if (hints.length === 0 && !isSafetyBlock) process.exit(0);
|
|
133
156
|
|
|
134
157
|
const toolName = input.tool_name || "Unknown";
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
158
|
+
const parts = [];
|
|
159
|
+
if (hints.length > 0) {
|
|
160
|
+
parts.push(`[error-context] ${toolName} 실패 — 해결 힌트:\n` + hints.map((h) => ` → ${h}`).join("\n"));
|
|
161
|
+
}
|
|
162
|
+
if (isSafetyBlock) {
|
|
163
|
+
parts.push("[reflexion] 이 패턴이 적응형 학습에 기록되었습니다. 다음 세션에서 동일 패턴 시 사전 차단됩니다.");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (parts.length === 0) process.exit(0);
|
|
140
167
|
|
|
168
|
+
const output = { systemMessage: parts.join("\n") };
|
|
141
169
|
process.stdout.write(JSON.stringify(output));
|
|
142
170
|
}
|
|
143
171
|
|
|
@@ -340,6 +340,20 @@ async function main() {
|
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
+
// ── PostToolUse:Skill 완료 시 라우팅 가중치 기록 ──
|
|
344
|
+
if (eventName === "PostToolUse" && toolName === "Skill" && !blocked) {
|
|
345
|
+
try {
|
|
346
|
+
const input = JSON.parse(stdinRaw);
|
|
347
|
+
const skillName = input.tool_input?.skill || "";
|
|
348
|
+
if (skillName && skillName.startsWith("tfx-")) {
|
|
349
|
+
const mode = skillName.replace(/^tfx-/, "");
|
|
350
|
+
const gitRoot = process.env.GIT_WORK_TREE || process.cwd();
|
|
351
|
+
const slug = gitRoot.split(/[\\/]/).pop() || "unknown";
|
|
352
|
+
recordRouteOutcome(slug, mode, "completion");
|
|
353
|
+
}
|
|
354
|
+
} catch { /* 가중치 기록 실패 무시 */ }
|
|
355
|
+
}
|
|
356
|
+
|
|
343
357
|
// 결과 출력
|
|
344
358
|
if (blocked) {
|
|
345
359
|
process.exit(2);
|
package/hooks/hook-registry.json
CHANGED
|
@@ -63,6 +63,16 @@
|
|
|
63
63
|
"timeout": 2,
|
|
64
64
|
"blocking": false,
|
|
65
65
|
"description": "tfx-multi 상태 추적 게이트"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": "tfx-write-edit-passthrough",
|
|
69
|
+
"source": "triflux",
|
|
70
|
+
"matcher": "Edit|Write",
|
|
71
|
+
"command": "exit 0",
|
|
72
|
+
"priority": 999,
|
|
73
|
+
"enabled": true,
|
|
74
|
+
"blocking": false,
|
|
75
|
+
"description": "Edit/Write passthrough"
|
|
66
76
|
}
|
|
67
77
|
],
|
|
68
78
|
"PostToolUse": [
|
package/hooks/safety-guard.mjs
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
// BLOCK (exit 2) — 복구 불가능한 파괴적 명령
|
|
9
9
|
// WARN (allow + context) — 주의가 필요한 명령
|
|
10
10
|
|
|
11
|
-
import { readFileSync } from "node:fs";
|
|
11
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
12
13
|
|
|
13
14
|
// ── 차단 규칙 ──────────────────────────────────────────────
|
|
14
15
|
const BLOCK_RULES = [
|
|
@@ -38,6 +39,21 @@ const WT_DIRECT_PATTERNS = [
|
|
|
38
39
|
const WT_DIRECT_BLOCK_MESSAGE =
|
|
39
40
|
"[safety-guard] wt.exe 직접 호출 차단됨. → hub/team/wt-manager.mjs의 createTab() / splitPane() / applySplitLayout()을 사용하세요.";
|
|
40
41
|
|
|
42
|
+
// ── SSH+PowerShell bash 문법 차단 ────────────────────────────
|
|
43
|
+
// 원격 기본 셸이 PowerShell인 호스트에 bash redirect/glob을 보내면 오동작
|
|
44
|
+
const BASH_SYNTAX_IN_SSH = [
|
|
45
|
+
/2>\/dev\/null/, // 2>/dev/null → PowerShell에서 Out-File C:\dev\null
|
|
46
|
+
/>\s*\/dev\/null/, // >/dev/null
|
|
47
|
+
/&>\s*\/dev\/null/, // &>/dev/null
|
|
48
|
+
/\$\(/, // $(cmd) → PowerShell에서 다른 의미
|
|
49
|
+
/\bsource\s+/, // source → PowerShell에 없음
|
|
50
|
+
/\bexport\s+\w+=/, // export VAR= → PowerShell에 없음
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const SSH_POWERSHELL_HINT =
|
|
54
|
+
"원격 셸이 PowerShell입니다. bash 문법 직접 전달 금지. scp + pwsh -File 패턴 사용. " +
|
|
55
|
+
"2>/dev/null → 2>$null, $() → $(), export → $env:, source → . (dot-source)";
|
|
56
|
+
|
|
41
57
|
// ── 경고 규칙 ──────────────────────────────────────────────
|
|
42
58
|
const WARN_RULES = [
|
|
43
59
|
{ pattern: /\bgit\s+push\b(?!.*--force)/i, warn: "git push 감지. 원격 저장소에 반영됩니다." },
|
|
@@ -50,6 +66,20 @@ const WARN_RULES = [
|
|
|
50
66
|
{ pattern: /\bcurl\s.*\|\s*(bash|sh)\b/i, warn: "curl | sh 감지. 원격 스크립트 실행 주의." },
|
|
51
67
|
];
|
|
52
68
|
|
|
69
|
+
// ── reflexion 적응형 패널티 로드 ──────────────────────────────
|
|
70
|
+
function loadReflexionPenalties() {
|
|
71
|
+
try {
|
|
72
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
73
|
+
const penaltyFile = join(home, ".triflux", "reflexion", "pending-penalties.jsonl");
|
|
74
|
+
if (!existsSync(penaltyFile)) return [];
|
|
75
|
+
return readFileSync(penaltyFile, "utf8")
|
|
76
|
+
.split("\n")
|
|
77
|
+
.filter(Boolean)
|
|
78
|
+
.map(line => { try { return JSON.parse(line); } catch { return null; } })
|
|
79
|
+
.filter(Boolean);
|
|
80
|
+
} catch { return []; }
|
|
81
|
+
}
|
|
82
|
+
|
|
53
83
|
function readStdin() {
|
|
54
84
|
try {
|
|
55
85
|
return readFileSync(0, "utf8");
|
|
@@ -127,6 +157,45 @@ function main() {
|
|
|
127
157
|
blockCommand(WT_DIRECT_BLOCK_MESSAGE, command);
|
|
128
158
|
}
|
|
129
159
|
|
|
160
|
+
// 0.1. reflexion 적응형 패널티 — 이전 세션에서 차단된 패턴 사전 경고
|
|
161
|
+
const penalties = loadReflexionPenalties();
|
|
162
|
+
if (penalties.length > 0) {
|
|
163
|
+
for (const penalty of penalties) {
|
|
164
|
+
if (penalty.error_pattern && new RegExp(penalty.error_pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").slice(0, 80), "i").test(command)) {
|
|
165
|
+
const output = {
|
|
166
|
+
hookSpecificOutput: {
|
|
167
|
+
hookEventName: "PreToolUse",
|
|
168
|
+
permissionDecision: "allow",
|
|
169
|
+
additionalContext:
|
|
170
|
+
`[reflexion] 이전 세션에서 차단된 패턴과 유사합니다 (${penalty.source}, ${penalty.ts?.slice(0, 10)}). ` +
|
|
171
|
+
`이전 차단 사유: ${penalty.error_pattern?.slice(0, 100)}`,
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
process.stdout.write(JSON.stringify(output));
|
|
175
|
+
process.exit(0);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 0.5. SSH → PowerShell 호스트에 bash 문법 전달 차단
|
|
181
|
+
// 세그먼트 시작 위치에서 ssh 명령인 경우만 (문자열/코드 안의 ssh는 무시)
|
|
182
|
+
if (hasSegmentInvocation(command, [/^\s*ssh\s+/i])) {
|
|
183
|
+
// 세그먼트 분리 후 ssh로 시작하는 세그먼트의 payload만 검사
|
|
184
|
+
const segments = command.split(/\s*(?:&&|;|\|\||\|)\s*/);
|
|
185
|
+
for (const seg of segments) {
|
|
186
|
+
const sshMatch = seg.trim().match(/^ssh\s+\S+\s+(.*)/s);
|
|
187
|
+
if (!sshMatch) continue;
|
|
188
|
+
const sshPayload = sshMatch[1];
|
|
189
|
+
const bashSyntax = BASH_SYNTAX_IN_SSH.find(p => p.test(sshPayload));
|
|
190
|
+
if (bashSyntax) {
|
|
191
|
+
blockCommand(
|
|
192
|
+
`[safety-guard] SSH 명령에 bash 전용 문법 감지: ${bashSyntax}. ${SSH_POWERSHELL_HINT}`,
|
|
193
|
+
command,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
130
199
|
// 1. BLOCK 체크 — exit 2로 차단
|
|
131
200
|
for (const rule of BLOCK_RULES) {
|
|
132
201
|
if (rule.skipIfGit && !isPsmuxInvocation(command)) continue;
|
package/hub/adaptive-inject.mjs
CHANGED