triflux 10.50.2 → 10.52.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.
Files changed (263) hide show
  1. package/CLAUDE.md +57 -41
  2. package/README.ko.md +41 -45
  3. package/README.md +41 -45
  4. package/adapters/codex/skills/tfx-live/SKILL.md +25 -11
  5. package/bin/tfx-live.mjs +341 -104
  6. package/bin/triflux.mjs +147 -2624
  7. package/config/mcp-registry.json +3 -12
  8. package/cto/brief.mjs +0 -20
  9. package/cto/collect.mjs +1 -200
  10. package/cto/current.schema.json +2 -23
  11. package/cto/hygiene.mjs +2 -61
  12. package/cto/lake-root.mjs +0 -56
  13. package/cto/status.mjs +5 -187
  14. package/hooks/agy-session-hook.mjs +11 -56
  15. package/hooks/codex-session-hook.mjs +11 -101
  16. package/hub/bridge.mjs +65 -1250
  17. package/hub/cli-adapter-base.mjs +12 -90
  18. package/hub/codex-adapter.mjs +0 -1
  19. package/hub/codex-preflight.mjs +5 -28
  20. package/hub/lib/process-utils.mjs +1 -156
  21. package/hub/lib/spawn-trace.mjs +3 -2
  22. package/hub/lib/timeout-defaults.mjs +0 -1
  23. package/hub/team/agent-map.json +0 -1
  24. package/hub/team/agents-row-attach.py +120 -0
  25. package/hub/team/agents-row.mjs +200 -0
  26. package/hub/team/ansi.mjs +1 -35
  27. package/hub/team/backend.mjs +9 -145
  28. package/hub/team/claude-daemon-control.mjs +1 -2
  29. package/hub/team/claude-session-projection.mjs +5 -73
  30. package/hub/team/cli/commands/attach.mjs +1 -17
  31. package/hub/team/cli/commands/control.mjs +12 -38
  32. package/hub/team/cli/commands/debug.mjs +2 -39
  33. package/hub/team/cli/commands/focus.mjs +5 -31
  34. package/hub/team/cli/commands/interrupt.mjs +6 -25
  35. package/hub/team/cli/commands/kill.mjs +1 -30
  36. package/hub/team/cli/commands/list.mjs +0 -16
  37. package/hub/team/cli/commands/send.mjs +6 -26
  38. package/hub/team/cli/commands/start/index.mjs +42 -133
  39. package/hub/team/cli/commands/start/parse-args.mjs +15 -40
  40. package/hub/team/cli/commands/start/start-headless.mjs +138 -105
  41. package/hub/team/cli/commands/start/start-mux.mjs +2 -7
  42. package/hub/team/cli/commands/status.mjs +2 -57
  43. package/hub/team/cli/commands/stop.mjs +14 -19
  44. package/hub/team/cli/help.mjs +4 -5
  45. package/hub/team/cli/manifest.mjs +5 -1
  46. package/hub/team/cli/render.mjs +0 -12
  47. package/hub/team/cli/services/runtime-mode.mjs +27 -98
  48. package/hub/team/cli/services/state-store.mjs +5 -20
  49. package/hub/team/codex-queue.mjs +385 -0
  50. package/hub/team/handoff.mjs +3 -34
  51. package/hub/team/headless.mjs +108 -1296
  52. package/hub/team/orchestrator.mjs +4 -30
  53. package/hub/team/pane.mjs +6 -28
  54. package/hub/team/psmux.mjs +3 -34
  55. package/hub/team/remote-session.mjs +1 -2
  56. package/hub/team/session-context.mjs +1 -1
  57. package/hub/team/session.mjs +7 -91
  58. package/hub/team/tui-core.mjs +1 -1
  59. package/hub/team/tui-viewer.mjs +11 -58
  60. package/hub/team/tui.mjs +8 -306
  61. package/hub/team/uds-orchestrator.mjs +2 -580
  62. package/hub/team/wt-manager.mjs +2 -2
  63. package/hub/workers/factory.mjs +6 -84
  64. package/hub/workers/interface.mjs +1 -7
  65. package/hub/workers/lib/jsonrpc-core.mjs +11 -0
  66. package/hub/workers/lib/jsonrpc-ws-uds.mjs +5 -8
  67. package/hud/cli-policy.mjs +0 -22
  68. package/hud/constants.mjs +13 -26
  69. package/hud/hud-qos-status.mjs +42 -54
  70. package/hud/providers/gemini.mjs +125 -20
  71. package/hud/renderers.mjs +101 -122
  72. package/hud/utils.mjs +10 -6
  73. package/package.json +7 -12
  74. package/scripts/__tests__/mcp-guard-engine-http-headers.test.mjs +6 -6
  75. package/scripts/__tests__/mcp-guard-engine-policy-sync.test.mjs +1 -4
  76. package/scripts/__tests__/mcp-guard-engine-proactive-sync.test.mjs +16 -21
  77. package/scripts/__tests__/mcp-guard-engine-stdio-sync.test.mjs +1 -1
  78. package/scripts/__tests__/mcp-guard-engine-sync-http-headers.test.mjs +2 -2
  79. package/scripts/__tests__/mcp-guard-engine.test.mjs +56 -63
  80. package/scripts/__tests__/spawn-trace.test.mjs +16 -0
  81. package/scripts/check-codex-config-stable.mjs +4 -37
  82. package/scripts/claude-login-detect.mjs +0 -1
  83. package/scripts/claudemd-sync.mjs +1 -28
  84. package/scripts/lib/agent-route-policy.mjs +143 -62
  85. package/scripts/lib/cli-claude.mjs +0 -14
  86. package/scripts/lib/env-probe.mjs +2 -131
  87. package/scripts/lib/gemini-profiles.mjs +2 -69
  88. package/scripts/lib/legacy-mcp-cleanup.mjs +283 -0
  89. package/scripts/lib/machine-profile.mjs +3 -17
  90. package/scripts/lib/mcp-filter.mjs +109 -53
  91. package/scripts/lib/mcp-guard-engine.mjs +40 -98
  92. package/scripts/lib/mcp-health.mjs +2 -2
  93. package/scripts/lib/mcp-server-catalog.mjs +2 -2
  94. package/scripts/lib/psmux-info.mjs +11 -59
  95. package/scripts/lib/session-presence.mjs +2 -100
  96. package/scripts/lib/skill-template.mjs +0 -245
  97. package/scripts/pack.mjs +8 -83
  98. package/scripts/preflight-cache.mjs +5 -18
  99. package/scripts/release/check-packages-mirror.mjs +2 -8
  100. package/scripts/release/version-manifest.json +9 -1
  101. package/scripts/setup.mjs +100 -417
  102. package/scripts/test-lock.mjs +0 -1
  103. package/scripts/tfx-route-post.mjs +5 -69
  104. package/scripts/tfx-route-worker.mjs +4 -79
  105. package/scripts/tfx-route.sh +169 -1495
  106. package/scripts/wt-cli.mjs +1 -2
  107. package/skills/tfx-auto/SKILL.md +123 -741
  108. package/skills/tfx-auto/references/consensus-schema.md +161 -0
  109. package/skills/tfx-auto/references/tmux-observation.md +97 -0
  110. package/skills/tfx-doctor/SKILL.md +5 -6
  111. package/skills/tfx-lead/SKILL.md +195 -0
  112. package/skills/tfx-live/SKILL.md +25 -11
  113. package/skills/tfx-remote/SKILL.md +24 -87
  114. package/skills/tfx-research/SKILL.md +13 -20
  115. package/skills/tfx-review/SKILL.md +33 -35
  116. package/skills/tfx-setup/SKILL.md +1 -1
  117. package/skills/tfx-ship/SKILL.md +6 -27
  118. package/skills/tfx-wt/SKILL.md +34 -68
  119. package/bin/tfx-doctor-tui.mjs +0 -7
  120. package/bin/tfx-setup-tui.mjs +0 -7
  121. package/config/routing-policy.json +0 -124
  122. package/docs/assets/consensus-flow.svg +0 -125
  123. package/docs/assets/deep-vs-light.svg +0 -193
  124. package/docs/assets/demo-dark.gif +0 -0
  125. package/docs/assets/demo-light.gif +0 -0
  126. package/docs/assets/demo-psmux.gif +0 -0
  127. package/hub/adaptive-diagnostic.mjs +0 -350
  128. package/hub/adaptive-inject.mjs +0 -224
  129. package/hub/adaptive-memory.mjs +0 -277
  130. package/hub/adaptive.mjs +0 -172
  131. package/hub/assign-callbacks.mjs +0 -170
  132. package/hub/delegator/contracts.mjs +0 -38
  133. package/hub/delegator/index.mjs +0 -14
  134. package/hub/delegator/schema/delegator-tools.schema.json +0 -250
  135. package/hub/delegator/service.mjs +0 -336
  136. package/hub/delegator/tool-definitions.mjs +0 -35
  137. package/hub/dynamic-routing-engine.mjs +0 -511
  138. package/hub/hitl.mjs +0 -202
  139. package/hub/hub-lifecycle.mjs +0 -248
  140. package/hub/lib/known-errors.json +0 -72
  141. package/hub/lib/memory-store.mjs +0 -1001
  142. package/hub/lib/phase-manager.mjs +0 -493
  143. package/hub/lib/risk-tier.mjs +0 -53
  144. package/hub/lib/ssh-command.mjs +0 -231
  145. package/hub/lib/staged-file-detect.mjs +0 -43
  146. package/hub/lib/state-snapshot.mjs +0 -293
  147. package/hub/lib/tfx-route-args.mjs +0 -353
  148. package/hub/lib/trace-recorder.mjs +0 -153
  149. package/hub/lib/uuidv7.mjs +0 -45
  150. package/hub/memory-doctor.mjs +0 -640
  151. package/hub/middleware/quota-middleware.mjs +0 -70
  152. package/hub/middleware/request-logger.mjs +0 -191
  153. package/hub/paths.mjs +0 -24
  154. package/hub/pipe.mjs +0 -825
  155. package/hub/pipeline/index.mjs +0 -163
  156. package/hub/pipeline/state.mjs +0 -191
  157. package/hub/pipeline/transitions.mjs +0 -131
  158. package/hub/promote-penalties.mjs +0 -138
  159. package/hub/public/dashboard.html +0 -416
  160. package/hub/reflexion.mjs +0 -290
  161. package/hub/role-contract.mjs +0 -314
  162. package/hub/router.mjs +0 -2026
  163. package/hub/routing-snapshot.mjs +0 -261
  164. package/hub/schema.sql +0 -209
  165. package/hub/server.mjs +0 -3048
  166. package/hub/session-fingerprint.mjs +0 -418
  167. package/hub/state.mjs +0 -300
  168. package/hub/store-adapter.mjs +0 -182
  169. package/hub/store.mjs +0 -1736
  170. package/hub/team/build-worker-prompt.mjs +0 -92
  171. package/hub/team/check-mcp-hub.mjs +0 -49
  172. package/hub/team/claude-native-bridge.mjs +0 -987
  173. package/hub/team/cli/commands/start/start-in-process.mjs +0 -50
  174. package/hub/team/cli/commands/start/start-wt.mjs +0 -86
  175. package/hub/team/cli/services/hub-client.mjs +0 -264
  176. package/hub/team/cli/services/native-control.mjs +0 -145
  177. package/hub/team/codex-review.mjs +0 -520
  178. package/hub/team/conductor-mesh-bridge.mjs +0 -122
  179. package/hub/team/conductor-registry.mjs +0 -121
  180. package/hub/team/conductor.mjs +0 -1529
  181. package/hub/team/consensus-meta.mjs +0 -176
  182. package/hub/team/cto-auto-collect.mjs +0 -115
  183. package/hub/team/cto-pull.mjs +0 -31
  184. package/hub/team/daemon-pty-tmux-bridge.mjs +0 -146
  185. package/hub/team/dashboard.mjs +0 -322
  186. package/hub/team/event-log.mjs +0 -84
  187. package/hub/team/execution-mode.mjs +0 -324
  188. package/hub/team/extract-completion-payload.mjs +0 -110
  189. package/hub/team/headless-bridge-session.mjs +0 -17
  190. package/hub/team/health-probe.mjs +0 -435
  191. package/hub/team/interactive-native-launcher.mjs +0 -119
  192. package/hub/team/interactive-native-worker.mjs +0 -80
  193. package/hub/team/interactive-tui-transport.mjs +0 -479
  194. package/hub/team/launcher-template.mjs +0 -144
  195. package/hub/team/lead-control.mjs +0 -191
  196. package/hub/team/mcp-selector.mjs +0 -145
  197. package/hub/team/native-supervisor.mjs +0 -460
  198. package/hub/team/native.mjs +0 -727
  199. package/hub/team/recovery-store.mjs +0 -149
  200. package/hub/team/remote-probe.mjs +0 -292
  201. package/hub/team/remote-watcher.mjs +0 -506
  202. package/hub/team/runtime-strategy.mjs +0 -200
  203. package/hub/team/schemas/worker-completion.json +0 -39
  204. package/hub/team/sentinel-capture.mjs +0 -127
  205. package/hub/team/session-sync.mjs +0 -316
  206. package/hub/team/swarm-cli.mjs +0 -390
  207. package/hub/team/swarm-hypervisor.mjs +0 -2206
  208. package/hub/team/swarm-intent.mjs +0 -216
  209. package/hub/team/swarm-locks.mjs +0 -335
  210. package/hub/team/swarm-planner.mjs +0 -371
  211. package/hub/team/swarm-preflight.mjs +0 -366
  212. package/hub/team/swarm-reconciler.mjs +0 -242
  213. package/hub/team/synapse-cli.mjs +0 -458
  214. package/hub/team/synapse-http.mjs +0 -311
  215. package/hub/team/synapse-registry.mjs +0 -618
  216. package/hub/team/tui-remote-adapter.mjs +0 -377
  217. package/hub/team/tui-synapse.mjs +0 -223
  218. package/hub/team/worker-completion-validator.mjs +0 -79
  219. package/hub/team/worker-sandbox.mjs +0 -125
  220. package/hub/team/worktree-lifecycle.mjs +0 -639
  221. package/hub/team/wt-templates.json +0 -43
  222. package/hub/team-bridge.mjs +0 -27
  223. package/hub/tools.mjs +0 -900
  224. package/hub/workers/antigravity-route-worker.mjs +0 -179
  225. package/hub/workers/codex-app-server-worker.mjs +0 -1067
  226. package/hub/workers/delegator-mcp.mjs +0 -1098
  227. package/hub/workers/lib/jsonrpc-stdio.mjs +0 -204
  228. package/mesh/index.mjs +0 -69
  229. package/mesh/mesh-budget.mjs +0 -137
  230. package/mesh/mesh-heartbeat.mjs +0 -100
  231. package/mesh/mesh-protocol.mjs +0 -96
  232. package/mesh/mesh-queue.mjs +0 -163
  233. package/mesh/mesh-registry.mjs +0 -78
  234. package/mesh/mesh-router.mjs +0 -77
  235. package/scripts/__tests__/skill-surface.test.mjs +0 -93
  236. package/scripts/cache-doctor.mjs +0 -156
  237. package/scripts/cache-warmup.mjs +0 -630
  238. package/scripts/completions/tfx.bash +0 -74
  239. package/scripts/completions/tfx.fish +0 -57
  240. package/scripts/completions/tfx.zsh +0 -98
  241. package/scripts/demo.mjs +0 -197
  242. package/scripts/doctor-dynamic-routing.mjs +0 -87
  243. package/scripts/hub-ensure.mjs +0 -842
  244. package/scripts/hub-watchdog.mjs +0 -90
  245. package/scripts/lib/claudemd-scanner.mjs +0 -223
  246. package/scripts/lib/context.mjs +0 -67
  247. package/scripts/lib/dynamic-route-cli.mjs +0 -107
  248. package/scripts/lib/handoff.mjs +0 -187
  249. package/scripts/lib/logger.mjs +0 -122
  250. package/scripts/lib/stealth-fetch.mjs +0 -176
  251. package/scripts/notion-read.mjs +0 -686
  252. package/scripts/snapshot-codex-state.mjs +0 -37
  253. package/scripts/snapshot-gemini-state.mjs +0 -37
  254. package/scripts/sync-codex-auth.mjs +0 -71
  255. package/scripts/sync-hub-mcp-settings.mjs +0 -697
  256. package/skills/_templates/base.md +0 -4
  257. package/skills/_templates/deep.md +0 -6
  258. package/skills/shared/telemetry-segment.md +0 -6
  259. package/tui/core.mjs +0 -266
  260. package/tui/doctor.mjs +0 -375
  261. package/tui/monitor-data.mjs +0 -152
  262. package/tui/monitor.mjs +0 -318
  263. package/tui/setup.mjs +0 -506
@@ -1,224 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
- import { join, resolve } from "node:path";
3
-
4
- const SECTION_HEADING = "## Adaptive Rules (triflux auto-generated)";
5
- const DEFAULT_MAX_RULES = 10;
6
- const SECTION_RE = /^## Adaptive Rules \(triflux auto-generated\)$/mu;
7
- const BLOCK_RE =
8
- /<!-- tfx-adaptive:start rule_id="([^"]+)" confidence=([0-9.]+) occurrences=(\d+) first_seen=([0-9-]+) last_seen=([0-9-]+) -->\r?\n([^\r\n]*)\r?\n<!-- tfx-adaptive:end -->/gu;
9
-
10
- function cloneRule(rule) {
11
- return Object.freeze({ ...rule });
12
- }
13
-
14
- function clampConfidence(value) {
15
- const numeric = Number(value);
16
- if (!Number.isFinite(numeric)) return 0;
17
- return Math.min(1, Math.max(0, numeric));
18
- }
19
-
20
- function normalizeOccurrences(value) {
21
- const numeric = Number(value);
22
- if (!Number.isFinite(numeric)) return 1;
23
- return Math.max(1, Math.trunc(numeric));
24
- }
25
-
26
- function formatConfidence(value) {
27
- return Number(clampConfidence(value).toFixed(6)).toString();
28
- }
29
-
30
- function normalizeDate(value, fallback) {
31
- const text = String(value ?? fallback ?? "").trim();
32
- return text || fallback;
33
- }
34
-
35
- function normalizeRuleInput(rule, fallback = {}) {
36
- if (!rule || typeof rule !== "object") return null;
37
-
38
- const id = String(rule.id ?? rule.rule_id ?? fallback.id ?? "").trim();
39
- const text = String(rule.rule ?? rule.text ?? fallback.rule ?? "").trim();
40
- const firstSeen = normalizeDate(
41
- rule.firstSeen ?? rule.first_seen,
42
- fallback.firstSeen ?? fallback.lastSeen ?? "1970-01-01",
43
- );
44
- const lastSeen = normalizeDate(
45
- rule.lastSeen ?? rule.last_seen,
46
- fallback.lastSeen ?? firstSeen,
47
- );
48
- if (!id || !text || /["\r\n]/u.test(id) || /[\r\n]/u.test(text)) {
49
- return null;
50
- }
51
-
52
- return cloneRule({
53
- id,
54
- rule: text,
55
- confidence: clampConfidence(rule.confidence ?? fallback.confidence),
56
- occurrences: normalizeOccurrences(rule.occurrences ?? fallback.occurrences),
57
- firstSeen,
58
- lastSeen,
59
- });
60
- }
61
-
62
- function trimLeadingBlankLines(text) {
63
- return String(text ?? "").replace(/^(?:[ \t]*\r?\n)+/u, "");
64
- }
65
-
66
- function trimTrailingBlankLines(text) {
67
- return String(text ?? "").replace(/(?:\r?\n[ \t]*)+$/u, "");
68
- }
69
-
70
- function parseInjectedRules(sectionBody = "") {
71
- const matches = Array.from(String(sectionBody).matchAll(BLOCK_RE));
72
- return matches.map(
73
- ([, id, confidence, occurrences, firstSeen, lastSeen, text]) =>
74
- cloneRule({
75
- id,
76
- rule: text,
77
- confidence: clampConfidence(confidence),
78
- occurrences: normalizeOccurrences(occurrences),
79
- firstSeen,
80
- lastSeen,
81
- }),
82
- );
83
- }
84
-
85
- function readDocument(claudeMdPath) {
86
- const raw = existsSync(claudeMdPath)
87
- ? readFileSync(claudeMdPath, "utf8")
88
- : "";
89
- const sectionStart = raw.search(SECTION_RE);
90
- if (sectionStart === -1) {
91
- return { before: raw, after: "", rules: [] };
92
- }
93
-
94
- const headingEnd = raw.indexOf("\n", sectionStart);
95
- const bodyStart = headingEnd === -1 ? raw.length : headingEnd + 1;
96
- const rest = raw.slice(bodyStart);
97
- const nextHeadingOffset = rest.search(/^#{1,6}\s/mu);
98
- const sectionEnd =
99
- nextHeadingOffset === -1 ? raw.length : bodyStart + nextHeadingOffset;
100
- const body = raw.slice(bodyStart, sectionEnd);
101
-
102
- return {
103
- before: raw.slice(0, sectionStart),
104
- after: raw.slice(sectionEnd),
105
- rules: parseInjectedRules(body),
106
- };
107
- }
108
-
109
- function serializeRule(rule) {
110
- return [
111
- `<!-- tfx-adaptive:start rule_id="${rule.id}" confidence=${formatConfidence(rule.confidence)} occurrences=${rule.occurrences} first_seen=${rule.firstSeen} last_seen=${rule.lastSeen} -->`,
112
- rule.rule,
113
- "<!-- tfx-adaptive:end -->",
114
- ].join("\n");
115
- }
116
-
117
- function serializeDocument(before, rules, after) {
118
- const section =
119
- rules.length > 0
120
- ? `${SECTION_HEADING}\n\n${rules.map(serializeRule).join("\n\n")}`
121
- : "";
122
- const parts = [
123
- trimTrailingBlankLines(before),
124
- section,
125
- trimLeadingBlankLines(after),
126
- ].filter(Boolean);
127
- return parts.length > 0 ? `${parts.join("\n\n")}\n` : "";
128
- }
129
-
130
- function enforceMaxRules(rules, maxRules) {
131
- if (rules.length <= maxRules) return rules.map(cloneRule);
132
- const ranked = rules
133
- .map((rule, index) => ({ ...rule, index }))
134
- .sort(
135
- (left, right) =>
136
- left.confidence - right.confidence ||
137
- left.occurrences - right.occurrences ||
138
- left.lastSeen.localeCompare(right.lastSeen) ||
139
- left.index - right.index ||
140
- left.id.localeCompare(right.id),
141
- );
142
- const removedIds = new Set(
143
- ranked.slice(0, rules.length - maxRules).map((rule) => rule.id),
144
- );
145
- return rules.filter((rule) => !removedIds.has(rule.id)).map(cloneRule);
146
- }
147
-
148
- export function createAdaptiveInjector(opts = {}) {
149
- const claudeMdPath = resolve(
150
- opts.claudeMdPath ?? join(process.cwd(), "CLAUDE.md"),
151
- );
152
- const maxRules =
153
- Number.isInteger(opts.maxRules) && opts.maxRules > 0
154
- ? opts.maxRules
155
- : DEFAULT_MAX_RULES;
156
-
157
- function listInjected() {
158
- return readDocument(claudeMdPath).rules.map(cloneRule);
159
- }
160
-
161
- function inject(rule) {
162
- const document = readDocument(claudeMdPath);
163
- const targetId = String(rule?.id ?? rule?.rule_id ?? "").trim();
164
- const existing = document.rules.find((item) => item.id === targetId);
165
- const normalized = normalizeRuleInput(rule, existing ?? {});
166
- if (!normalized) return false;
167
-
168
- const nextRules = existing
169
- ? document.rules.map((item) =>
170
- item.id === normalized.id
171
- ? cloneRule({
172
- ...item,
173
- confidence: normalized.confidence,
174
- occurrences: normalized.occurrences,
175
- lastSeen: normalized.lastSeen,
176
- })
177
- : cloneRule(item),
178
- )
179
- : [...document.rules.map(cloneRule), normalized];
180
- const limitedRules = enforceMaxRules(nextRules, maxRules);
181
- writeFileSync(
182
- claudeMdPath,
183
- serializeDocument(document.before, limitedRules, document.after),
184
- "utf8",
185
- );
186
- return limitedRules.some((item) => item.id === normalized.id);
187
- }
188
-
189
- function remove(ruleId) {
190
- const targetId = String(ruleId ?? "").trim();
191
- if (!targetId || !existsSync(claudeMdPath)) return false;
192
- const document = readDocument(claudeMdPath);
193
- if (!document.rules.some((rule) => rule.id === targetId)) return false;
194
- const nextRules = document.rules
195
- .filter((rule) => rule.id !== targetId)
196
- .map(cloneRule);
197
- writeFileSync(
198
- claudeMdPath,
199
- serializeDocument(document.before, nextRules, document.after),
200
- "utf8",
201
- );
202
- return true;
203
- }
204
-
205
- function cleanup(activeRuleIds = []) {
206
- const activeIds = new Set(
207
- Array.isArray(activeRuleIds) ? activeRuleIds : Array.from(activeRuleIds),
208
- );
209
- return listInjected().reduce(
210
- (count, rule) =>
211
- count + (activeIds.has(rule.id) ? 0 : Number(remove(rule.id))),
212
- 0,
213
- );
214
- }
215
-
216
- return Object.freeze({
217
- inject,
218
- remove,
219
- listInjected,
220
- cleanup,
221
- });
222
- }
223
-
224
- export default createAdaptiveInjector;
@@ -1,277 +0,0 @@
1
- import {
2
- existsSync,
3
- mkdirSync,
4
- readFileSync,
5
- rmSync,
6
- writeFileSync,
7
- } from "node:fs";
8
- import { homedir } from "node:os";
9
- import { join } from "node:path";
10
-
11
- const SESSION_FILE = "adaptive-session.json";
12
- const DEFAULT_CONFIDENCE = 0.5;
13
- const TIER2_DECAY_STEP = 0.2;
14
- const TIER2_DECAY_INTERVAL = 5;
15
- const TIER2_REMOVE_THRESHOLD = 0.3;
16
- const TIER3_WARN_THRESHOLD = 10;
17
- const TIER3_REMOVE_THRESHOLD = 20;
18
-
19
- const clone = (v) => (v == null ? v : JSON.parse(JSON.stringify(v)));
20
- const clamp01 = (v) => {
21
- const n = Number(v);
22
- return Number.isFinite(n)
23
- ? Number(Math.max(0, Math.min(1, n)).toFixed(4))
24
- : DEFAULT_CONFIDENCE;
25
- };
26
- const toDate = (v = Date.now()) => {
27
- const d = new Date(v);
28
- return Number.isNaN(d.getTime())
29
- ? new Date().toISOString().slice(0, 10)
30
- : d.toISOString().slice(0, 10);
31
- };
32
- const uniq = (arr) => [
33
- ...new Set(arr.filter((s) => typeof s === "string" && s.trim())),
34
- ];
35
- const slugify = (v) =>
36
- String(v || "")
37
- .trim()
38
- .toLowerCase()
39
- .replace(/[^a-z0-9]+/g, "-")
40
- .replace(/^-+|-+$/g, "")
41
- .slice(0, 80);
42
- const buildId = (r) => {
43
- const e = slugify(r.id);
44
- if (e) return e;
45
- const p = slugify(r.pattern);
46
- return p || `adaptive-${Date.now()}`;
47
- };
48
- const readJson = (f, fb) => {
49
- if (!existsSync(f)) return clone(fb);
50
- try {
51
- return { ...clone(fb), ...JSON.parse(readFileSync(f, "utf8")) };
52
- } catch {
53
- return clone(fb);
54
- }
55
- };
56
- const writeJson = (f, v) =>
57
- writeFileSync(f, `${JSON.stringify(v, null, 2)}\n`, "utf8");
58
- const strip = (r) => {
59
- if (!r) return null;
60
- const { sessionIds, ...pub } = r;
61
- return clone(pub);
62
- };
63
- const sortRules = (list) =>
64
- [...list].sort(
65
- (a, b) =>
66
- a.tier - b.tier ||
67
- b.confidence - a.confidence ||
68
- a.id.localeCompare(b.id),
69
- );
70
- const upsert = (list, r) => [...list.filter((x) => x.id !== r.id), r];
71
- const without = (list, id) => list.filter((x) => x.id !== id);
72
-
73
- function toRule(rule, tier, sessionId, existing = null) {
74
- return {
75
- id: existing?.id || buildId(rule),
76
- pattern: String(rule.pattern || existing?.pattern || ""),
77
- rootCause: String(
78
- rule.rootCause || rule.root_cause || existing?.rootCause || "",
79
- ),
80
- rule: String(rule.rule || existing?.rule || ""),
81
- confidence: clamp01(rule.confidence ?? existing?.confidence),
82
- occurrences: Math.max(1, Number(existing?.occurrences || 0) + 1),
83
- firstSeen: existing?.firstSeen || toDate(rule.timestamp),
84
- lastSeen: toDate(rule.timestamp),
85
- sessionsWithout: 0,
86
- tier,
87
- dnaFactor: rule.dnaFactor ?? rule.dna_factor ?? existing?.dnaFactor ?? null,
88
- sessionIds: uniq([...(existing?.sessionIds || []), sessionId]),
89
- };
90
- }
91
-
92
- export function createAdaptiveMemory(opts = {}) {
93
- const projectSlug = slugify(opts.projectSlug);
94
- if (!projectSlug) throw new Error("projectSlug is required");
95
-
96
- const sessionDir = opts.sessionDir || join(process.cwd(), ".omc", "state");
97
- const globalDir = opts.globalDir || join(homedir(), ".triflux", "adaptive");
98
- const sessionFile = join(sessionDir, SESSION_FILE);
99
- const projectFile = join(globalDir, `${projectSlug}.json`);
100
-
101
- mkdirSync(sessionDir, { recursive: true });
102
- mkdirSync(globalDir, { recursive: true });
103
-
104
- let ss = readJson(sessionFile, { projectSlug, sessionId: null, rules: [] });
105
- let ps = readJson(projectFile, {
106
- projectSlug,
107
- history: {},
108
- tier2: [],
109
- tier3: [],
110
- });
111
-
112
- function saveSession() {
113
- if (ss.rules.length === 0) {
114
- rmSync(sessionFile, { force: true });
115
- return;
116
- }
117
- writeJson(sessionFile, ss);
118
- }
119
-
120
- function saveProject() {
121
- const has =
122
- Object.keys(ps.history).length > 0 ||
123
- ps.tier2.length > 0 ||
124
- ps.tier3.length > 0;
125
- if (!has) {
126
- rmSync(projectFile, { force: true });
127
- return;
128
- }
129
- writeJson(projectFile, ps);
130
- }
131
-
132
- const saveAll = () => {
133
- saveSession();
134
- saveProject();
135
- };
136
-
137
- function getSessionId(id) {
138
- const next = String(id || ss.sessionId || "session-current");
139
- ss = { ...ss, sessionId: next };
140
- return next;
141
- }
142
-
143
- const getDurable = (id) =>
144
- ps.tier3.find((r) => r.id === id) ||
145
- ps.tier2.find((r) => r.id === id) ||
146
- null;
147
-
148
- function promote(ruleId) {
149
- const t2 = ps.tier2.find((r) => r.id === ruleId);
150
- if (t2 && t2.occurrences >= 3 && t2.confidence >= 0.8) {
151
- const next = { ...t2, tier: 3, sessionsWithout: 0 };
152
- ps = {
153
- ...ps,
154
- tier2: without(ps.tier2, ruleId),
155
- tier3: upsert(ps.tier3, next),
156
- };
157
- saveProject();
158
- return { rule: strip(next), promoted: true, fromTier: 2, toTier: 3 };
159
- }
160
- const cand = ps.history[ruleId];
161
- if (cand && cand.occurrences >= 2 && cand.sessionIds.length >= 2) {
162
- const next = { ...cand, tier: 2, sessionsWithout: 0 };
163
- const { [ruleId]: _, ...history } = ps.history;
164
- ps = { ...ps, history, tier2: upsert(ps.tier2, next) };
165
- ss = { ...ss, rules: without(ss.rules, ruleId) };
166
- saveAll();
167
- return { rule: strip(next), promoted: true, fromTier: 1, toTier: 2 };
168
- }
169
- const cur = getDurable(ruleId) || ps.history[ruleId] || null;
170
- return {
171
- rule: strip(cur),
172
- promoted: false,
173
- fromTier: cur?.tier ?? null,
174
- toTier: cur?.tier ?? null,
175
- };
176
- }
177
-
178
- function record(rule = {}) {
179
- if (!rule.pattern)
180
- return { rule: null, promoted: false, fromTier: null, toTier: null };
181
- const sessionId = getSessionId(rule.sessionId);
182
- const ruleId = buildId(rule);
183
- const durable = getDurable(ruleId);
184
- if (durable) {
185
- const next = toRule(rule, durable.tier, sessionId, durable);
186
- ps =
187
- durable.tier === 3
188
- ? { ...ps, tier3: upsert(ps.tier3, next) }
189
- : { ...ps, tier2: upsert(ps.tier2, next) };
190
- saveProject();
191
- const res = promote(ruleId);
192
- return res.promoted
193
- ? res
194
- : {
195
- rule: strip(next),
196
- promoted: false,
197
- fromTier: durable.tier,
198
- toTier: durable.tier,
199
- };
200
- }
201
- const cand = toRule(rule, 1, sessionId, ps.history[ruleId]);
202
- ps = { ...ps, history: { ...ps.history, [ruleId]: cand } };
203
- ss = { ...ss, rules: upsert(ss.rules, { ...cand, tier: 1 }) };
204
- saveAll();
205
- const res = promote(ruleId);
206
- return res.promoted
207
- ? res
208
- : { rule: strip(cand), promoted: false, fromTier: 1, toTier: 1 };
209
- }
210
-
211
- function decay(sessionId) {
212
- const nextId = String(sessionId || `session-${Date.now()}`);
213
- if (ss.sessionId === nextId)
214
- return {
215
- sessionId: nextId,
216
- tier1Cleared: 0,
217
- updated: [],
218
- warned: [],
219
- removed: [],
220
- };
221
- const warned = [],
222
- removed = [],
223
- updated = [];
224
- const tier1Cleared = ss.rules.length;
225
- const tier2 = ps.tier2.flatMap((r) => {
226
- const sw = Number(r.sessionsWithout || 0) + 1;
227
- const conf =
228
- sw % TIER2_DECAY_INTERVAL === 0
229
- ? clamp01(r.confidence - TIER2_DECAY_STEP)
230
- : r.confidence;
231
- if (conf < TIER2_REMOVE_THRESHOLD) {
232
- removed.push(r.id);
233
- return [];
234
- }
235
- updated.push(r.id);
236
- return [{ ...r, sessionsWithout: sw, confidence: conf }];
237
- });
238
- const tier3 = ps.tier3.flatMap((r) => {
239
- const sw = Number(r.sessionsWithout || 0) + 1;
240
- if (sw >= TIER3_REMOVE_THRESHOLD) {
241
- removed.push(r.id);
242
- return [];
243
- }
244
- if (sw === TIER3_WARN_THRESHOLD) warned.push(r.id);
245
- updated.push(r.id);
246
- return [{ ...r, sessionsWithout: sw }];
247
- });
248
- ss = { ...ss, sessionId: nextId, rules: [] };
249
- ps = { ...ps, tier2, tier3 };
250
- saveAll();
251
- return { sessionId: nextId, tier1Cleared, updated, warned, removed };
252
- }
253
-
254
- function getRule(id) {
255
- return strip(ss.rules.find((r) => r.id === id) || getDurable(id));
256
- }
257
- function getTier(tier) {
258
- if (tier === 1) return sortRules(ss.rules).map(strip);
259
- if (tier === 2) return sortRules(ps.tier2).map(strip);
260
- if (tier === 3) return sortRules(ps.tier3).map(strip);
261
- return [];
262
- }
263
- function getAllRules() {
264
- return sortRules([...ss.rules, ...ps.tier2, ...ps.tier3]).map(strip);
265
- }
266
- function reset(target = "all") {
267
- const rs = target === "all" || target === 1 || target === "session";
268
- const rp =
269
- target === "all" || target === 2 || target === 3 || target === "project";
270
- if (rs) ss = { ...ss, rules: [] };
271
- if (rp) ps = { ...ps, history: {}, tier2: [], tier3: [] };
272
- saveAll();
273
- return { sessionCleared: rs, projectCleared: rp };
274
- }
275
-
276
- return { record, promote, decay, getRule, getAllRules, getTier, reset };
277
- }
package/hub/adaptive.mjs DELETED
@@ -1,172 +0,0 @@
1
- import { randomUUID } from "node:crypto";
2
- import { join } from "node:path";
3
- import { createDiagnosticPipeline } from "./adaptive-diagnostic.mjs";
4
- import { createAdaptiveInjector } from "./adaptive-inject.mjs";
5
- import { createAdaptiveMemory } from "./adaptive-memory.mjs";
6
- import { createAdaptiveFingerprintService } from "./session-fingerprint.mjs";
7
-
8
- let singletonEngine = null;
9
-
10
- function clone(value) {
11
- return value == null ? value : JSON.parse(JSON.stringify(value));
12
- }
13
-
14
- function toRuleList(value) {
15
- return Array.isArray(value) ? value : [];
16
- }
17
-
18
- function resolveTierCount(memory, tier) {
19
- if (typeof memory.getTier === "function") {
20
- const rules = memory.getTier(tier);
21
- return Array.isArray(rules) ? rules.length : 0;
22
- }
23
- return toRuleList(memory.getAllRules?.()).filter(
24
- (rule) => Number(rule?.tier) === tier,
25
- ).length;
26
- }
27
-
28
- function resolveActiveRuleIds(memory, decayResult) {
29
- if (Array.isArray(decayResult?.activeRuleIds))
30
- return [...decayResult.activeRuleIds];
31
- return toRuleList(memory.getAllRules?.())
32
- .map((rule) => rule.id)
33
- .filter(Boolean);
34
- }
35
-
36
- function resolveRecordedRule(recordResult) {
37
- if (recordResult?.rule)
38
- return {
39
- rule: recordResult.rule,
40
- promoted: Boolean(recordResult.promoted),
41
- };
42
- return { rule: recordResult || null, promoted: false };
43
- }
44
-
45
- function createEngineInstance(opts = {}) {
46
- const repoRoot = opts.repoRoot || process.cwd();
47
- const claudeMdPath = opts.claudeMdPath || join(repoRoot, "CLAUDE.md");
48
- const projectSlug = String(opts.projectSlug || "default").trim() || "default";
49
- const now = opts.now || (() => Date.now());
50
- const sessionIdFactory = opts.sessionIdFactory || (() => randomUUID());
51
-
52
- const memory =
53
- opts.memory ||
54
- opts.memoryFactory?.(opts) ||
55
- createAdaptiveMemory({ projectSlug, ...opts.memoryOptions });
56
- const diagnostic =
57
- opts.diagnostic ||
58
- opts.diagnosticFactory?.(opts) ||
59
- createDiagnosticPipeline(opts.diagnosticOptions);
60
- const injector =
61
- opts.injector ||
62
- opts.injectorFactory?.(opts) ||
63
- createAdaptiveInjector({ claudeMdPath, ...opts.injectorOptions });
64
- const fingerprintService =
65
- opts.fingerprintService ||
66
- opts.fingerprintFactory?.(opts) ||
67
- createAdaptiveFingerprintService(opts.fingerprintOptions);
68
-
69
- let started = false;
70
- let currentSessionId = null;
71
- let lastFingerprintId = null;
72
- const counters = {
73
- totalErrors: 0,
74
- diagnosedErrors: 0,
75
- };
76
-
77
- function refreshFingerprint() {
78
- if (typeof fingerprintService.computeFingerprint !== "function") return;
79
- const fingerprint = fingerprintService.computeFingerprint({
80
- scope: projectSlug,
81
- cwd: repoRoot,
82
- filePath: claudeMdPath,
83
- workType: "adaptive",
84
- timestamp: now(),
85
- });
86
- lastFingerprintId = fingerprint?.fingerprint_id || lastFingerprintId;
87
- }
88
-
89
- function startSession() {
90
- if (started) return;
91
- currentSessionId = sessionIdFactory();
92
- const decayResult =
93
- typeof memory.decay === "function"
94
- ? memory.decay(currentSessionId)
95
- : null;
96
- injector.cleanup?.(resolveActiveRuleIds(memory, decayResult));
97
- refreshFingerprint();
98
- started = true;
99
- }
100
-
101
- function handleError(errorContext = {}) {
102
- if (!started) startSession();
103
- counters.totalErrors += 1;
104
-
105
- const diagnosis = diagnostic.diagnose({
106
- ...errorContext,
107
- projectSlug,
108
- sessionId: currentSessionId,
109
- });
110
- if (!diagnosis?.matched || !diagnosis.rule) {
111
- return Object.freeze({ diagnosed: false, rule: null, promoted: false });
112
- }
113
-
114
- counters.diagnosedErrors += 1;
115
- const { rule: recordedRule, promoted } = resolveRecordedRule(
116
- memory.record({
117
- ...diagnosis.rule,
118
- confidence: diagnosis.confidence,
119
- dnaFactor: diagnosis.dnaFactor,
120
- sessionId: currentSessionId,
121
- lastSeen: new Date(now()).toISOString().slice(0, 10),
122
- }),
123
- );
124
-
125
- const nextRule = clone(recordedRule || diagnosis.rule);
126
- if (nextRule?.tier >= 3 && promoted) {
127
- injector.inject?.(nextRule);
128
- }
129
-
130
- return Object.freeze({
131
- diagnosed: true,
132
- rule: nextRule,
133
- promoted: Boolean(promoted),
134
- });
135
- }
136
-
137
- function endSession() {
138
- if (!started) return;
139
- memory.reset?.({ tier: 1, sessionId: currentSessionId });
140
- started = false;
141
- currentSessionId = null;
142
- }
143
-
144
- function getStats() {
145
- return Object.freeze({
146
- tier1Count: resolveTierCount(memory, 1),
147
- tier2Count: resolveTierCount(memory, 2),
148
- tier3Count: resolveTierCount(memory, 3),
149
- totalErrors: counters.totalErrors,
150
- });
151
- }
152
-
153
- return Object.freeze({
154
- handleError,
155
- startSession,
156
- endSession,
157
- getStats,
158
- __lastFingerprintId: () => lastFingerprintId,
159
- });
160
- }
161
-
162
- export function createAdaptiveEngine(opts = {}) {
163
- if (singletonEngine) return singletonEngine;
164
- singletonEngine = createEngineInstance(opts);
165
- return singletonEngine;
166
- }
167
-
168
- export function __resetAdaptiveEngineForTests() {
169
- singletonEngine = null;
170
- }
171
-
172
- export default createAdaptiveEngine;