triflux 3.2.0-dev.3 → 3.2.0-dev.5
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/README.ko.md +19 -13
- package/README.md +19 -13
- package/bin/triflux.mjs +6 -5
- package/hooks/hooks.json +2 -2
- package/hooks/keyword-rules.json +338 -0
- package/hub/team/cli.mjs +406 -359
- package/hub/team/dashboard.mjs +164 -55
- package/hub/team/native.mjs +38 -0
- package/hud/hud-qos-status.mjs +56 -1
- package/package.json +3 -2
- package/scripts/__tests__/keyword-detector.test.mjs +234 -0
- package/scripts/keyword-detector.mjs +257 -0
- package/scripts/keyword-rules-expander.mjs +521 -0
- package/scripts/lib/keyword-rules.mjs +165 -0
- package/scripts/run.cjs +62 -0
- package/scripts/setup.mjs +5 -4
- package/scripts/test-tfx-route-no-claude-native.mjs +49 -0
- package/scripts/tfx-route.sh +482 -418
- package/skills/tfx-auto-codex/SKILL.md +79 -0
- package/skills/tfx-team/SKILL.md +90 -63
- package/scripts/team-keyword.mjs +0 -35
package/scripts/run.cjs
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { execFileSync } = require("child_process");
|
|
5
|
+
const { existsSync, readFileSync } = require("fs");
|
|
6
|
+
const { dirname, isAbsolute, join, resolve } = require("path");
|
|
7
|
+
|
|
8
|
+
function resolvePluginRoot() {
|
|
9
|
+
if (process.env.CLAUDE_PLUGIN_ROOT) return process.env.CLAUDE_PLUGIN_ROOT;
|
|
10
|
+
return dirname(__dirname);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function resolveTargetPath(rawTarget) {
|
|
14
|
+
if (!rawTarget || typeof rawTarget !== "string") return null;
|
|
15
|
+
|
|
16
|
+
const pluginRoot = resolvePluginRoot();
|
|
17
|
+
const trimmed = rawTarget.trim();
|
|
18
|
+
|
|
19
|
+
if (trimmed.startsWith("${CLAUDE_PLUGIN_ROOT}/")) {
|
|
20
|
+
return join(pluginRoot, trimmed.replace("${CLAUDE_PLUGIN_ROOT}/", ""));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (trimmed.startsWith("/scripts/")) {
|
|
24
|
+
return join(pluginRoot, trimmed.replace(/^\/+/, ""));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isAbsolute(trimmed)) return trimmed;
|
|
28
|
+
return resolve(process.cwd(), trimmed);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const targetArg = process.argv[2];
|
|
32
|
+
if (!targetArg) {
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const targetPath = resolveTargetPath(targetArg);
|
|
37
|
+
if (!targetPath || !existsSync(targetPath)) {
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const stdinBuffer = (() => {
|
|
42
|
+
try {
|
|
43
|
+
return readFileSync(0);
|
|
44
|
+
} catch {
|
|
45
|
+
return Buffer.alloc(0);
|
|
46
|
+
}
|
|
47
|
+
})();
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
execFileSync(process.execPath, [targetPath, ...process.argv.slice(3)], {
|
|
51
|
+
env: process.env,
|
|
52
|
+
stdio: ["pipe", "inherit", "inherit"],
|
|
53
|
+
input: stdinBuffer,
|
|
54
|
+
windowsHide: true
|
|
55
|
+
});
|
|
56
|
+
process.exit(0);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (typeof error?.status === "number") {
|
|
59
|
+
process.exit(error.status);
|
|
60
|
+
}
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
package/scripts/setup.mjs
CHANGED
|
@@ -341,10 +341,11 @@ ${B}Shortcuts:${R}
|
|
|
341
341
|
${C}tfx-setup${R} triflux setup
|
|
342
342
|
${C}tfx-doctor${R} triflux doctor
|
|
343
343
|
|
|
344
|
-
${B}Skills (Claude Code):${R}
|
|
345
|
-
${C}/tfx-auto${R} "작업" 자동 분류 + 병렬 실행
|
|
346
|
-
${C}/tfx-codex${R}
|
|
347
|
-
${C}/tfx-
|
|
344
|
+
${B}Skills (Claude Code):${R}
|
|
345
|
+
${C}/tfx-auto${R} "작업" 자동 분류 + 병렬 실행
|
|
346
|
+
${C}/tfx-auto-codex${R} "작업" Codex 리드 + Gemini 유지
|
|
347
|
+
${C}/tfx-codex${R} "작업" Codex 전용 모드
|
|
348
|
+
${C}/tfx-gemini${R} "작업" Gemini 전용 모드
|
|
348
349
|
${C}/tfx-setup${R} HUD 설정 + 진단
|
|
349
350
|
|
|
350
351
|
${Y}!${R} 세션 재시작 후 스킬이 활성화됩니다
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import assert from "node:assert/strict";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { dirname, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const PROJECT_ROOT = resolve(SCRIPT_DIR, "..");
|
|
10
|
+
|
|
11
|
+
function runBash(command) {
|
|
12
|
+
return spawnSync("bash", ["-lc", command], {
|
|
13
|
+
cwd: PROJECT_ROOT,
|
|
14
|
+
encoding: "utf8"
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function out(result) {
|
|
19
|
+
return `${result.stdout || ""}\n${result.stderr || ""}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
test("gemini 모드에서는 no-claude-native 강제 치환이 적용되지 않는다", () => {
|
|
23
|
+
const result = runBash(
|
|
24
|
+
"TFX_CLI_MODE=gemini TFX_NO_CLAUDE_NATIVE=1 bash scripts/tfx-route.sh explore 'test-case'"
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
assert.equal(result.status, 0, out(result));
|
|
28
|
+
assert.match(out(result), /ROUTE_TYPE=claude-native/, out(result));
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("auto 모드 + no-claude-native=1이면 explore가 codex로 치환된다", () => {
|
|
32
|
+
const result = runBash(
|
|
33
|
+
"TFX_CLI_MODE=auto TFX_NO_CLAUDE_NATIVE=1 CODEX_BIN=true bash scripts/tfx-route.sh explore 'test-case' minimal 5"
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
assert.equal(result.status, 0, out(result));
|
|
37
|
+
assert.match(out(result), /TFX_NO_CLAUDE_NATIVE=1: explore -> codex/, out(result));
|
|
38
|
+
assert.match(out(result), /type=codex|cli:\\s*codex/i, out(result));
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("TFX_NO_CLAUDE_NATIVE는 0/1 값만 허용한다", () => {
|
|
42
|
+
const result = runBash(
|
|
43
|
+
"TFX_NO_CLAUDE_NATIVE=2 bash scripts/tfx-route.sh explore 'test-case'"
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
assert.notEqual(result.status, 0, out(result));
|
|
47
|
+
assert.match(out(result), /0 또는 1/, out(result));
|
|
48
|
+
});
|
|
49
|
+
|