triflux 7.1.4 → 7.2.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.
Files changed (73) hide show
  1. package/.claude-plugin/marketplace.json +31 -31
  2. package/.claude-plugin/plugin.json +22 -23
  3. package/bin/triflux.mjs +18 -5
  4. package/hooks/keyword-rules.json +393 -361
  5. package/hub/bridge.mjs +799 -786
  6. package/hub/delegator/contracts.mjs +37 -38
  7. package/hub/delegator/schema/delegator-tools.schema.json +250 -250
  8. package/hub/delegator/service.mjs +307 -302
  9. package/hub/intent.mjs +108 -11
  10. package/hub/lib/process-utils.mjs +20 -0
  11. package/hub/pipe.mjs +589 -589
  12. package/hub/pipeline/gates/confidence.mjs +1 -1
  13. package/hub/pipeline/gates/selfcheck.mjs +2 -4
  14. package/hub/pipeline/state.mjs +191 -187
  15. package/hub/pipeline/transitions.mjs +124 -120
  16. package/hub/public/dashboard.html +355 -349
  17. package/hub/quality/deslop.mjs +5 -3
  18. package/hub/reflexion.mjs +5 -1
  19. package/hub/research.mjs +6 -1
  20. package/hub/router.mjs +791 -782
  21. package/hub/server.mjs +893 -822
  22. package/hub/store.mjs +807 -778
  23. package/hub/team/agent-map.json +10 -0
  24. package/hub/team/ansi.mjs +3 -4
  25. package/hub/team/cli/commands/control.mjs +43 -43
  26. package/hub/team/cli/commands/interrupt.mjs +36 -36
  27. package/hub/team/cli/commands/kill.mjs +3 -3
  28. package/hub/team/cli/commands/send.mjs +37 -37
  29. package/hub/team/cli/commands/start/index.mjs +18 -8
  30. package/hub/team/cli/commands/start/parse-args.mjs +3 -1
  31. package/hub/team/cli/commands/start/start-headless.mjs +4 -1
  32. package/hub/team/cli/commands/status.mjs +87 -87
  33. package/hub/team/cli/commands/stop.mjs +1 -1
  34. package/hub/team/cli/commands/task.mjs +1 -1
  35. package/hub/team/cli/index.mjs +41 -39
  36. package/hub/team/cli/manifest.mjs +29 -28
  37. package/hub/team/cli/services/hub-client.mjs +37 -0
  38. package/hub/team/cli/services/state-store.mjs +26 -12
  39. package/hub/team/dashboard.mjs +11 -4
  40. package/hub/team/handoff.mjs +12 -0
  41. package/hub/team/headless.mjs +202 -200
  42. package/hub/team/native-supervisor.mjs +386 -346
  43. package/hub/team/nativeProxy.mjs +680 -692
  44. package/hub/team/staleState.mjs +361 -369
  45. package/hub/team/tui-viewer.mjs +27 -3
  46. package/hub/team/tui.mjs +1 -0
  47. package/hub/token-mode.mjs +114 -24
  48. package/hub/workers/delegator-mcp.mjs +1059 -1057
  49. package/hud/colors.mjs +88 -0
  50. package/hud/constants.mjs +78 -0
  51. package/hud/hud-qos-status.mjs +206 -1872
  52. package/hud/providers/claude.mjs +309 -0
  53. package/hud/providers/codex.mjs +151 -0
  54. package/hud/providers/gemini.mjs +320 -0
  55. package/hud/renderers.mjs +424 -0
  56. package/hud/terminal.mjs +140 -0
  57. package/hud/utils.mjs +271 -0
  58. package/package.json +1 -2
  59. package/scripts/__tests__/keyword-detector.test.mjs +234 -234
  60. package/scripts/headless-guard-fast.sh +21 -0
  61. package/scripts/headless-guard.mjs +26 -6
  62. package/scripts/lib/keyword-rules.mjs +166 -168
  63. package/scripts/setup.mjs +725 -690
  64. package/scripts/tfx-route-post.mjs +424 -424
  65. package/scripts/tfx-route.sh +1671 -1650
  66. package/scripts/tmp-cleanup.mjs +74 -0
  67. package/skills/tfx-auto/SKILL.md +279 -278
  68. package/skills/tfx-auto-codex/SKILL.md +98 -77
  69. package/skills/tfx-codex/SKILL.md +65 -65
  70. package/skills/tfx-gemini/SKILL.md +83 -82
  71. package/skills/tfx-hub/SKILL.md +205 -136
  72. package/skills/tfx-multi/SKILL.md +11 -5
  73. package/.mcp.json +0 -8
@@ -1,168 +1,166 @@
1
- import { readFileSync } from "node:fs";
2
-
3
- const VALID_MCP_ROUTES = new Set(["codex", "gemini", "claude"]);
4
-
5
- function logRuleError(message, error) {
6
- if (error) {
7
- console.error(`[triflux-keyword-rules] ${message}: ${error.message}`);
8
- return;
9
- }
10
- console.error(`[triflux-keyword-rules] ${message}`);
11
- }
12
-
13
- function normalizePattern(pattern) {
14
- if (!pattern || typeof pattern.source !== "string") return null;
15
- if (typeof pattern.flags !== "string") return null;
16
- return { source: pattern.source, flags: pattern.flags };
17
- }
18
-
19
- function normalizeState(state) {
20
- if (state == null) return null;
21
- if (typeof state !== "object") return null;
22
- if (typeof state.activate !== "boolean") return null;
23
- if (typeof state.name !== "string" || !state.name.trim()) return null;
24
- return { activate: state.activate, name: state.name.trim() };
25
- }
26
-
27
- function normalizeRule(rule) {
28
- if (!rule || typeof rule !== "object") return null;
29
- if (typeof rule.id !== "string" || !rule.id.trim()) return null;
30
- if (!Array.isArray(rule.patterns) || rule.patterns.length === 0) return null;
31
- if (typeof rule.priority !== "number" || !Number.isFinite(rule.priority)) return null;
32
-
33
- const patterns = rule.patterns.map(normalizePattern).filter(Boolean);
34
- if (patterns.length === 0) return null;
35
-
36
- const skill = typeof rule.skill === "string" && rule.skill.trim() ? rule.skill.trim() : null;
37
- const action = typeof rule.action === "string" && rule.action.trim() ? rule.action.trim() : null;
38
- const mcpRoute = typeof rule.mcp_route === "string" && VALID_MCP_ROUTES.has(rule.mcp_route)
39
- ? rule.mcp_route
40
- : null;
41
-
42
- if (!skill && !mcpRoute && !action) return null;
43
-
44
- const supersedes = Array.isArray(rule.supersedes)
45
- ? rule.supersedes.filter((id) => typeof id === "string" && id.trim()).map((id) => id.trim())
46
- : [];
47
-
48
- const state = normalizeState(rule.state);
49
- if (rule.state != null && state == null) return null;
50
-
51
- return {
52
- id: rule.id.trim(),
53
- patterns,
54
- skill,
55
- action: rule.action || null,
56
- priority: rule.priority,
57
- supersedes,
58
- exclusive: rule.exclusive === true,
59
- state,
60
- mcp_route: mcpRoute
61
- };
62
- }
63
-
64
- // 외부 JSON 규칙 로드 + 스키마 검증
65
- export function loadRules(rulesPath) {
66
- try {
67
- const raw = readFileSync(rulesPath, "utf8");
68
- const parsed = JSON.parse(raw);
69
- if (!parsed || !Array.isArray(parsed.rules)) {
70
- logRuleError(`규칙 형식이 올바르지 않습니다: ${rulesPath}`);
71
- return [];
72
- }
73
-
74
- const normalized = parsed.rules.map(normalizeRule).filter(Boolean);
75
- return normalized;
76
- } catch (error) {
77
- logRuleError(`규칙 파일을 읽을 수 없습니다: ${rulesPath}`, error);
78
- return [];
79
- }
80
- }
81
-
82
- // pattern.source / flags를 RegExp로 컴파일
83
- export function compileRules(rules) {
84
- try {
85
- return rules.map((rule) => ({
86
- ...rule,
87
- compiledPatterns: rule.patterns.map((pattern) => new RegExp(pattern.source, pattern.flags))
88
- }));
89
- } catch (error) {
90
- // fail-open: 정규식 오류 시 전체 비활성
91
- logRuleError("정규식 컴파일 실패", error);
92
- return [];
93
- }
94
- }
95
-
96
- // 입력 텍스트에서 매칭된 규칙 목록 반환
97
- export function matchRules(compiledRules, cleanText) {
98
- if (!Array.isArray(compiledRules) || typeof cleanText !== "string" || !cleanText) {
99
- return [];
100
- }
101
-
102
- const matches = [];
103
-
104
- for (const rule of compiledRules) {
105
- if (!Array.isArray(rule.compiledPatterns) || rule.compiledPatterns.length === 0) {
106
- continue;
107
- }
108
-
109
- const matched = rule.compiledPatterns.some((pattern) => {
110
- pattern.lastIndex = 0;
111
- return pattern.test(cleanText);
112
- });
113
-
114
- if (!matched) continue;
115
-
116
- matches.push({
117
- id: rule.id,
118
- skill: rule.skill,
119
- action: rule.action || null,
120
- priority: rule.priority,
121
- supersedes: rule.supersedes || [],
122
- exclusive: rule.exclusive === true,
123
- state: rule.state || null,
124
- mcp_route: rule.mcp_route || null
125
- });
126
- }
127
-
128
- return matches;
129
- }
130
-
131
- // priority 정렬 + supersedes + exclusive 처리
132
- export function resolveConflicts(matches) {
133
- try {
134
- if (!Array.isArray(matches) || matches.length === 0) return [];
135
-
136
- const sorted = [...matches].sort((a, b) => {
137
- if (a.priority !== b.priority) return a.priority - b.priority;
138
- return String(a.id).localeCompare(String(b.id));
139
- });
140
-
141
- const deduped = [];
142
- const seen = new Set();
143
- for (const match of sorted) {
144
- if (seen.has(match.id)) continue;
145
- deduped.push(match);
146
- seen.add(match.id);
147
- }
148
-
149
- const superseded = new Set();
150
- const resolved = [];
151
-
152
- for (const match of deduped) {
153
- if (superseded.has(match.id)) continue;
154
- resolved.push(match);
155
- for (const targetId of match.supersedes || []) {
156
- superseded.add(targetId);
157
- }
158
- }
159
-
160
- const exclusiveMatch = resolved.find((match) => match.exclusive === true);
161
- if (exclusiveMatch) return [exclusiveMatch];
162
-
163
- return resolved;
164
- } catch (error) {
165
- logRuleError("규칙 충돌 해결 실패", error);
166
- return [];
167
- }
168
- }
1
+ import { readFileSync } from "node:fs";
2
+
3
+ const VALID_MCP_ROUTES = new Set(["codex", "gemini", "claude"]);
4
+
5
+ function logRuleError(message, error) {
6
+ if (error) {
7
+ console.error(`[triflux-keyword-rules] ${message}: ${error.message}`);
8
+ return;
9
+ }
10
+ console.error(`[triflux-keyword-rules] ${message}`);
11
+ }
12
+
13
+ function normalizePattern(pattern) {
14
+ if (!pattern || typeof pattern.source !== "string") return null;
15
+ if (typeof pattern.flags !== "string") return null;
16
+ return { source: pattern.source, flags: pattern.flags };
17
+ }
18
+
19
+ function normalizeState(state) {
20
+ if (state == null) return null;
21
+ if (typeof state !== "object") return null;
22
+ if (typeof state.activate !== "boolean") return null;
23
+ if (typeof state.name !== "string" || !state.name.trim()) return null;
24
+ return { activate: state.activate, name: state.name.trim() };
25
+ }
26
+
27
+ function normalizeRule(rule) {
28
+ if (!rule || typeof rule !== "object") return null;
29
+ if (typeof rule.id !== "string" || !rule.id.trim()) return null;
30
+ if (!Array.isArray(rule.patterns) || rule.patterns.length === 0) return null;
31
+ if (typeof rule.priority !== "number" || !Number.isFinite(rule.priority)) return null;
32
+
33
+ const patterns = rule.patterns.map(normalizePattern).filter(Boolean);
34
+ if (patterns.length === 0) return null;
35
+
36
+ const skill = typeof rule.skill === "string" && rule.skill.trim() ? rule.skill.trim() : null;
37
+ const action = typeof rule.action === "string" && rule.action.trim() ? rule.action.trim() : null;
38
+ const mcpRoute = typeof rule.mcp_route === "string" && VALID_MCP_ROUTES.has(rule.mcp_route)
39
+ ? rule.mcp_route
40
+ : null;
41
+
42
+ if (!skill && !mcpRoute && !action) return null;
43
+
44
+ const supersedes = Array.isArray(rule.supersedes)
45
+ ? rule.supersedes.filter((id) => typeof id === "string" && id.trim()).map((id) => id.trim())
46
+ : [];
47
+
48
+ const state = normalizeState(rule.state);
49
+ if (rule.state != null && state == null) return null;
50
+
51
+ return {
52
+ id: rule.id.trim(),
53
+ patterns,
54
+ skill,
55
+ action,
56
+ priority: rule.priority,
57
+ supersedes,
58
+ exclusive: rule.exclusive === true,
59
+ state,
60
+ mcp_route: mcpRoute
61
+ };
62
+ }
63
+
64
+ // 외부 JSON 규칙 로드 + 스키마 검증
65
+ export function loadRules(rulesPath) {
66
+ try {
67
+ const raw = readFileSync(rulesPath, "utf8");
68
+ const parsed = JSON.parse(raw);
69
+ if (!parsed || !Array.isArray(parsed.rules)) {
70
+ logRuleError(`규칙 형식이 올바르지 않습니다: ${rulesPath}`);
71
+ return [];
72
+ }
73
+
74
+ const normalized = parsed.rules.map(normalizeRule).filter(Boolean);
75
+ return normalized;
76
+ } catch (error) {
77
+ logRuleError(`규칙 파일을 읽을 수 없습니다: ${rulesPath}`, error);
78
+ return [];
79
+ }
80
+ }
81
+
82
+ // pattern.source / flags를 RegExp로 컴파일
83
+ export function compileRules(rules) {
84
+ return rules.map((rule) => {
85
+ try {
86
+ return { ...rule, compiledPatterns: rule.patterns.map((p) => new RegExp(p.source, p.flags)) };
87
+ } catch (error) {
88
+ logRuleError(`정규식 컴파일 실패: ${rule.id}`, error);
89
+ return null;
90
+ }
91
+ }).filter(Boolean);
92
+ }
93
+
94
+ // 입력 텍스트에서 매칭된 규칙 목록 반환
95
+ export function matchRules(compiledRules, cleanText) {
96
+ if (!Array.isArray(compiledRules) || typeof cleanText !== "string" || !cleanText) {
97
+ return [];
98
+ }
99
+
100
+ const matches = [];
101
+
102
+ for (const rule of compiledRules) {
103
+ if (!Array.isArray(rule.compiledPatterns) || rule.compiledPatterns.length === 0) {
104
+ continue;
105
+ }
106
+
107
+ const matched = rule.compiledPatterns.some((pattern) => {
108
+ pattern.lastIndex = 0;
109
+ return pattern.test(cleanText);
110
+ });
111
+
112
+ if (!matched) continue;
113
+
114
+ matches.push({
115
+ id: rule.id,
116
+ skill: rule.skill,
117
+ action: rule.action,
118
+ priority: rule.priority,
119
+ supersedes: rule.supersedes || [],
120
+ exclusive: rule.exclusive === true,
121
+ state: rule.state || null,
122
+ mcp_route: rule.mcp_route || null
123
+ });
124
+ }
125
+
126
+ return matches;
127
+ }
128
+
129
+ // priority 정렬 + supersedes + exclusive 처리
130
+ export function resolveConflicts(matches) {
131
+ try {
132
+ if (!Array.isArray(matches) || matches.length === 0) return [];
133
+
134
+ const sorted = [...matches].sort((a, b) => {
135
+ if (a.priority !== b.priority) return a.priority - b.priority;
136
+ return String(a.id).localeCompare(String(b.id));
137
+ });
138
+
139
+ const deduped = [];
140
+ const seen = new Set();
141
+ for (const match of sorted) {
142
+ if (seen.has(match.id)) continue;
143
+ deduped.push(match);
144
+ seen.add(match.id);
145
+ }
146
+
147
+ const superseded = new Set();
148
+ const resolved = [];
149
+
150
+ for (const match of deduped) {
151
+ if (superseded.has(match.id)) continue;
152
+ resolved.push(match);
153
+ for (const targetId of match.supersedes || []) {
154
+ superseded.add(targetId);
155
+ }
156
+ }
157
+
158
+ const exclusiveMatch = resolved.find((match) => match.exclusive === true);
159
+ if (exclusiveMatch) return [exclusiveMatch];
160
+
161
+ return resolved;
162
+ } catch (error) {
163
+ logRuleError("규칙 충돌 해결 실패", error);
164
+ return [];
165
+ }
166
+ }