@triflux/core 10.51.0 → 10.53.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 (61) hide show
  1. package/hub/bridge.mjs +69 -1197
  2. package/hub/cli-adapter-base.mjs +4 -104
  3. package/hub/codex-adapter.mjs +7 -116
  4. package/hub/index.mjs +3 -20
  5. package/hub/lib/process-utils.mjs +1 -33
  6. package/hub/team/claude-daemon-control.mjs +1 -2
  7. package/hub/team/claude-session-projection.mjs +5 -73
  8. package/hub/team/claude-transcript.mjs +19 -0
  9. package/hub/team/nativeProxy.mjs +759 -0
  10. package/hub/team/session-context.mjs +1 -1
  11. package/hud/constants.mjs +9 -22
  12. package/hud/hud-qos-status.mjs +16 -19
  13. package/hud/providers/codex-probe.mjs +2 -31
  14. package/hud/providers/codex.mjs +16 -58
  15. package/hud/providers/gemini.mjs +20 -0
  16. package/hud/renderers.mjs +101 -77
  17. package/hud/utils.mjs +9 -13
  18. package/package.json +3 -6
  19. package/scripts/lib/agent-route-policy.mjs +0 -67
  20. package/scripts/lib/cli-claude.mjs +0 -12
  21. package/scripts/lib/env-probe.mjs +0 -70
  22. package/scripts/lib/legacy-mcp-cleanup.mjs +283 -0
  23. package/scripts/lib/mcp-guard-engine.mjs +42 -101
  24. package/scripts/lib/session-presence.mjs +1 -99
  25. package/hub/account-broker.mjs +0 -1221
  26. package/hub/adaptive-diagnostic.mjs +0 -350
  27. package/hub/adaptive-inject.mjs +0 -224
  28. package/hub/adaptive-memory.mjs +0 -277
  29. package/hub/adaptive.mjs +0 -172
  30. package/hub/assign-callbacks.mjs +0 -170
  31. package/hub/delegator/contracts.mjs +0 -38
  32. package/hub/delegator/index.mjs +0 -14
  33. package/hub/delegator/schema/delegator-tools.schema.json +0 -250
  34. package/hub/delegator/service.mjs +0 -336
  35. package/hub/delegator/tool-definitions.mjs +0 -35
  36. package/hub/hitl.mjs +0 -202
  37. package/hub/lib/known-errors.json +0 -72
  38. package/hub/lib/memory-store.mjs +0 -1001
  39. package/hub/lib/phase-manager.mjs +0 -493
  40. package/hub/lib/state-snapshot.mjs +0 -293
  41. package/hub/lib/trace-recorder.mjs +0 -153
  42. package/hub/lib/uuidv7.mjs +0 -45
  43. package/hub/memory-doctor.mjs +0 -640
  44. package/hub/middleware/quota-middleware.mjs +0 -70
  45. package/hub/middleware/request-logger.mjs +0 -191
  46. package/hub/paths.mjs +0 -24
  47. package/hub/pipeline/index.mjs +0 -163
  48. package/hub/pipeline/state.mjs +0 -191
  49. package/hub/pipeline/transitions.mjs +0 -131
  50. package/hub/reflexion.mjs +0 -290
  51. package/hub/role-contract.mjs +0 -312
  52. package/hub/router.mjs +0 -2026
  53. package/hub/session-fingerprint.mjs +0 -418
  54. package/hub/state.mjs +0 -300
  55. package/hub/team/synapse-http.mjs +0 -311
  56. package/hub/team-bridge.mjs +0 -27
  57. package/scripts/lib/claudemd-scanner.mjs +0 -26
  58. package/scripts/lib/context.mjs +0 -51
  59. package/scripts/lib/handoff.mjs +0 -187
  60. package/scripts/lib/logger.mjs +0 -122
  61. package/scripts/lib/stealth-fetch.mjs +0 -176
@@ -1,293 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import {
3
- copyFile,
4
- mkdir,
5
- readdir,
6
- rename,
7
- rm,
8
- stat,
9
- writeFile,
10
- } from "node:fs/promises";
11
- import { tmpdir } from "node:os";
12
- import { dirname, isAbsolute, join, relative, resolve } from "node:path";
13
- import { promisify } from "node:util";
14
-
15
- const execFileAsync = promisify(execFile);
16
- const DEFAULT_MAX_SNAPSHOTS = 10;
17
- const DAY_MS = 24 * 60 * 60 * 1000;
18
-
19
- export const CODEX_STATE_INCLUDES = Object.freeze([
20
- "config.toml",
21
- "AGENTS.md",
22
- "skills",
23
- "agents",
24
- "prompts",
25
- "plugins",
26
- ]);
27
-
28
- export const CODEX_STATE_EXCLUDES = Object.freeze([
29
- "*.sqlite*",
30
- ".sandbox*",
31
- ".tmp",
32
- "_archived_skills",
33
- "memories",
34
- "cache",
35
- "log",
36
- "logs",
37
- "sessions",
38
- "auth.json",
39
- ".credentials.json",
40
- "*.bak*",
41
- "*.tmp-*",
42
- "cap_sid",
43
- "installation_id",
44
- "history.jsonl",
45
- "models_cache.json",
46
- ]);
47
-
48
- export const GEMINI_STATE_INCLUDES = Object.freeze([
49
- "settings.json",
50
- "settings.local.json",
51
- "GEMINI.md",
52
- "commands",
53
- "extensions",
54
- "plugins",
55
- "skills",
56
- "agents",
57
- ]);
58
-
59
- export const GEMINI_STATE_EXCLUDES = Object.freeze([
60
- "*.sqlite*",
61
- "cache",
62
- "log",
63
- "logs",
64
- "sessions",
65
- "auth.json",
66
- ".credentials.json",
67
- "*.bak*",
68
- ]);
69
-
70
- export const STATE_SNAPSHOT_THRESHOLD_MS = DAY_MS;
71
- export const STATE_SNAPSHOT_MAX_SNAPSHOTS = DEFAULT_MAX_SNAPSHOTS;
72
-
73
- function normalizePath(path) {
74
- return String(path || "")
75
- .replace(/\\/gu, "/")
76
- .replace(/^\/+/u, "");
77
- }
78
-
79
- function globToRegExp(pattern) {
80
- const escaped = String(pattern).replace(/[.+^${}()|[\]\\]/gu, "\\$&");
81
- return new RegExp(`^${escaped.replace(/\*/gu, ".*")}$`, "u");
82
- }
83
-
84
- function compileExclude(pattern) {
85
- const text = normalizePath(pattern).replace(/\/+$/u, "");
86
- if (text.includes("*")) {
87
- const regex = globToRegExp(text);
88
- return (relativePath) => {
89
- const normalized = normalizePath(relativePath);
90
- return normalized.split("/").some((part) => regex.test(part));
91
- };
92
- }
93
-
94
- return (relativePath) => {
95
- const normalized = normalizePath(relativePath);
96
- return normalized.split("/").includes(text);
97
- };
98
- }
99
-
100
- function isSubpath(parent, child) {
101
- const rel = relative(parent, child);
102
- return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
103
- }
104
-
105
- async function pathStats(path) {
106
- try {
107
- return await stat(path);
108
- } catch (error) {
109
- if (error?.code === "ENOENT") return null;
110
- throw error;
111
- }
112
- }
113
-
114
- async function collectFiles({ sourceDir, includes, excludeMatchers }) {
115
- const sourceRoot = resolve(sourceDir);
116
- const files = [];
117
-
118
- async function visit(absPath, relativePath) {
119
- if (excludeMatchers.some((matcher) => matcher(relativePath))) return;
120
-
121
- const info = await pathStats(absPath);
122
- if (!info) return;
123
- if (info.isDirectory()) {
124
- const children = await readdir(absPath, { withFileTypes: true });
125
- for (const child of children) {
126
- await visit(join(absPath, child.name), join(relativePath, child.name));
127
- }
128
- return;
129
- }
130
- if (info.isFile()) {
131
- files.push({
132
- absPath,
133
- relativePath: normalizePath(relativePath),
134
- size: info.size,
135
- });
136
- }
137
- }
138
-
139
- for (const include of includes || []) {
140
- const relativeInclude = normalizePath(include);
141
- if (!relativeInclude || relativeInclude.startsWith("../")) continue;
142
- const absPath = resolve(sourceRoot, relativeInclude);
143
- if (!isSubpath(sourceRoot, absPath)) continue;
144
- await visit(absPath, relativeInclude);
145
- }
146
-
147
- files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
148
- return files;
149
- }
150
-
151
- async function listSnapshots(destDir) {
152
- const names = await readdir(destDir).catch((error) => {
153
- if (error?.code === "ENOENT") return [];
154
- throw error;
155
- });
156
- const snapshots = [];
157
- for (const name of names) {
158
- if (!name.endsWith(".tar.gz")) continue;
159
- const path = join(destDir, name);
160
- const info = await pathStats(path);
161
- if (info?.isFile()) snapshots.push({ name, path, mtimeMs: info.mtimeMs });
162
- }
163
- snapshots.sort(
164
- (a, b) => b.mtimeMs - a.mtimeMs || b.name.localeCompare(a.name),
165
- );
166
- return snapshots;
167
- }
168
-
169
- async function copyToStaging(files, stagingDir) {
170
- for (const file of files) {
171
- const targetPath = join(stagingDir, ...file.relativePath.split("/"));
172
- await mkdir(dirname(targetPath), { recursive: true });
173
- await copyFile(file.absPath, targetPath);
174
- }
175
- }
176
-
177
- async function createArchive({ stagingDir, archivePath, files }) {
178
- const listPath = join(stagingDir, ".snapshot-files");
179
- const archiveName = normalizePath(relative(stagingDir, archivePath));
180
- await writeFile(
181
- listPath,
182
- `${files.map((file) => file.relativePath).join("\n")}\n`,
183
- "utf8",
184
- );
185
- await execFileAsync(
186
- "tar",
187
- ["-czf", archiveName, "-C", ".", "-T", ".snapshot-files"],
188
- {
189
- cwd: stagingDir,
190
- windowsHide: true,
191
- },
192
- );
193
- await rm(listPath, { force: true });
194
- }
195
-
196
- async function pruneSnapshots(destDir, maxSnapshots) {
197
- const snapshots = await listSnapshots(destDir);
198
- const keep = Math.max(1, Number(maxSnapshots) || DEFAULT_MAX_SNAPSHOTS);
199
- for (const snapshot of snapshots.slice(keep)) {
200
- await rm(snapshot.path, { force: true });
201
- }
202
- }
203
-
204
- function formatStamp(date) {
205
- return date
206
- .toISOString()
207
- .replace(/[-:]/gu, "")
208
- .replace(/\.\d{3}Z$/u, "Z");
209
- }
210
-
211
- function uniqueSuffix() {
212
- return `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
213
- }
214
-
215
- /**
216
- * Snapshot selected user state into a rolling tar.gz archive.
217
- *
218
- * @param {object} options
219
- * @param {string} options.sourceDir
220
- * @param {string} options.destDir
221
- * @param {string[]} options.includes
222
- * @param {string[]} options.excludes
223
- * @param {number} options.thresholdMs
224
- * @param {number} [options.maxSnapshots=10]
225
- * @returns {Promise<{skipped: boolean, reason?: string, path?: string, sizeBytes?: number, fileCount?: number}>}
226
- */
227
- export async function snapshotState({
228
- sourceDir,
229
- destDir,
230
- includes,
231
- excludes = [],
232
- thresholdMs = 0,
233
- maxSnapshots = DEFAULT_MAX_SNAPSHOTS,
234
- }) {
235
- const sourceRoot = resolve(sourceDir || "");
236
- const destRoot = resolve(destDir || "");
237
- const sourceInfo = await pathStats(sourceRoot);
238
- if (!sourceInfo?.isDirectory()) {
239
- return { skipped: true, reason: "source-missing" };
240
- }
241
-
242
- await mkdir(destRoot, { recursive: true });
243
- const snapshots = await listSnapshots(destRoot);
244
- const newest = snapshots[0];
245
- if (
246
- newest &&
247
- Number(thresholdMs) > 0 &&
248
- Date.now() - newest.mtimeMs < Number(thresholdMs)
249
- ) {
250
- return { skipped: true, reason: "threshold", path: newest.path };
251
- }
252
-
253
- const excludeMatchers = excludes.map((pattern) => compileExclude(pattern));
254
- const files = await collectFiles({
255
- sourceDir: sourceRoot,
256
- includes,
257
- excludeMatchers,
258
- });
259
- if (files.length === 0) {
260
- return { skipped: true, reason: "empty" };
261
- }
262
-
263
- const suffix = uniqueSuffix();
264
- const stagingDir = join(tmpdir(), `tfx-state-snapshot-${suffix}`);
265
- const tempArchivePath = join(stagingDir, `.state-${suffix}.tar.gz.tmp`);
266
- const finalArchivePath = join(
267
- destRoot,
268
- `state-${formatStamp(new Date())}-${suffix}.tar.gz`,
269
- );
270
-
271
- try {
272
- await mkdir(stagingDir, { recursive: true });
273
- await copyToStaging(files, stagingDir);
274
- await createArchive({
275
- stagingDir,
276
- archivePath: tempArchivePath,
277
- files,
278
- });
279
- await rename(tempArchivePath, finalArchivePath);
280
- await pruneSnapshots(destRoot, maxSnapshots);
281
- const archiveInfo = await stat(finalArchivePath);
282
- const sizeBytes = files.reduce((sum, file) => sum + file.size, 0);
283
- return {
284
- skipped: false,
285
- path: finalArchivePath,
286
- sizeBytes: archiveInfo.size || sizeBytes,
287
- fileCount: files.length,
288
- };
289
- } finally {
290
- await rm(stagingDir, { recursive: true, force: true });
291
- await rm(tempArchivePath, { force: true });
292
- }
293
- }
@@ -1,153 +0,0 @@
1
- const VALID_CLIENTS = new Set(["codex", "claude", "gemini", "unknown"]);
2
- const VALID_PHASES = new Set(["ingress", "handler", "store", "event-loop"]);
3
- const SAMPLE_LIMIT = 1000;
4
-
5
- const categories = new Map();
6
- const workerDurations = [];
7
- const workerCounts = {
8
- spawned: 0,
9
- exited: 0,
10
- };
11
-
12
- function debugInvalid(kind, details) {
13
- if (process.env.TFX_TRACE_DEBUG !== "1") return;
14
- console.debug(`[trace-recorder] ignored invalid ${kind}`, details);
15
- }
16
-
17
- function normalizeClient(client) {
18
- const value = String(client || "unknown").toLowerCase();
19
- return VALID_CLIENTS.has(value) ? value : "unknown";
20
- }
21
-
22
- function normalizePhase(phase) {
23
- const value = String(phase || "handler");
24
- return VALID_PHASES.has(value) ? value : "handler";
25
- }
26
-
27
- function validDuration(durMs) {
28
- return Number.isFinite(durMs) && durMs >= 0;
29
- }
30
-
31
- function emptyStats() {
32
- return {
33
- count: 0,
34
- total: 0,
35
- min: null,
36
- max: null,
37
- samples: [],
38
- phases: {},
39
- };
40
- }
41
-
42
- function addDuration(stats, durMs, phase) {
43
- stats.count += 1;
44
- stats.total += durMs;
45
- stats.min = stats.min == null ? durMs : Math.min(stats.min, durMs);
46
- stats.max = stats.max == null ? durMs : Math.max(stats.max, durMs);
47
- stats.samples.push(durMs);
48
- if (stats.samples.length > SAMPLE_LIMIT) {
49
- stats.samples.splice(0, stats.samples.length - SAMPLE_LIMIT);
50
- }
51
-
52
- const phaseStats = stats.phases[phase] || emptyPhaseStats();
53
- phaseStats.count += 1;
54
- phaseStats.total += durMs;
55
- phaseStats.min =
56
- phaseStats.min == null ? durMs : Math.min(phaseStats.min, durMs);
57
- phaseStats.max =
58
- phaseStats.max == null ? durMs : Math.max(phaseStats.max, durMs);
59
- stats.phases[phase] = phaseStats;
60
- }
61
-
62
- function emptyPhaseStats() {
63
- return { count: 0, total: 0, min: null, max: null };
64
- }
65
-
66
- function percentile(samples, percentileValue) {
67
- if (!samples.length) return null;
68
- const sorted = [...samples].sort((a, b) => a - b);
69
- const index = Math.ceil((percentileValue / 100) * sorted.length) - 1;
70
- return sorted[Math.max(0, Math.min(sorted.length - 1, index))];
71
- }
72
-
73
- function publicStats(stats) {
74
- return {
75
- count: stats.count,
76
- total: stats.total,
77
- min: stats.min,
78
- max: stats.max,
79
- p50: percentile(stats.samples, 50),
80
- p95: percentile(stats.samples, 95),
81
- p99: percentile(stats.samples, 99),
82
- phases: stats.phases,
83
- };
84
- }
85
-
86
- export function recordRequest(
87
- category,
88
- durMs,
89
- client = "unknown",
90
- phase = "handler",
91
- ) {
92
- if (!category || typeof category !== "string") return;
93
- if (!validDuration(durMs)) {
94
- debugInvalid("request duration", { category, durMs, client, phase });
95
- return;
96
- }
97
-
98
- const clientKey = normalizeClient(client);
99
- const phaseKey = normalizePhase(phase);
100
- const bucket = categories.get(category) || new Map();
101
- const stats = bucket.get(clientKey) || emptyStats();
102
- addDuration(stats, durMs, phaseKey);
103
- bucket.set(clientKey, stats);
104
- categories.set(category, bucket);
105
- }
106
-
107
- export function recordWorker(workerId, kind, command, durMs) {
108
- if (!workerId || typeof workerId !== "string") return;
109
- if (kind === "spawned") {
110
- workerCounts.spawned += 1;
111
- return;
112
- }
113
- if (kind !== "exited") return;
114
-
115
- workerCounts.exited += 1;
116
- if (durMs == null) return;
117
- if (!validDuration(durMs)) {
118
- debugInvalid("worker duration", { workerId, kind, command, durMs });
119
- return;
120
- }
121
- workerDurations.push(durMs);
122
- if (workerDurations.length > SAMPLE_LIMIT) {
123
- workerDurations.splice(0, workerDurations.length - SAMPLE_LIMIT);
124
- }
125
- }
126
-
127
- export function snapshot() {
128
- const categorySnapshot = {};
129
- for (const [category, bucket] of categories.entries()) {
130
- categorySnapshot[category] = {};
131
- for (const [client, stats] of bucket.entries()) {
132
- categorySnapshot[category][client] = publicStats(stats);
133
- }
134
- }
135
-
136
- return {
137
- categories: categorySnapshot,
138
- workers: {
139
- spawned: workerCounts.spawned,
140
- exited: workerCounts.exited,
141
- p50: percentile(workerDurations, 50),
142
- p95: percentile(workerDurations, 95),
143
- p99: percentile(workerDurations, 99),
144
- },
145
- };
146
- }
147
-
148
- export function reset() {
149
- categories.clear();
150
- workerDurations.length = 0;
151
- workerCounts.spawned = 0;
152
- workerCounts.exited = 0;
153
- }
@@ -1,45 +0,0 @@
1
- // hub/lib/uuidv7.mjs — UUIDv7 generator (RFC 9562, monotonic)
2
- import { randomBytes } from "node:crypto";
3
-
4
- let _rndPool = Buffer.alloc(0),
5
- _rndOff = 0;
6
-
7
- function pooledRandom(n) {
8
- if (_rndOff + n > _rndPool.length) {
9
- _rndPool = randomBytes(256);
10
- _rndOff = 0;
11
- }
12
- const out = Buffer.from(_rndPool.subarray(_rndOff, _rndOff + n));
13
- _rndOff += n;
14
- return out;
15
- }
16
-
17
- let _lastMs = 0n;
18
- let _seq = 0;
19
-
20
- /** UUIDv7 생성 (RFC 9562, 단조 증가 보장) */
21
- export function uuidv7() {
22
- let now = BigInt(Date.now());
23
- if (now <= _lastMs) {
24
- _seq++;
25
- if (_seq > 0xfff) {
26
- now = _lastMs + 1n;
27
- _seq = 0;
28
- }
29
- } else {
30
- _seq = 0;
31
- }
32
- _lastMs = now;
33
- const buf = pooledRandom(16);
34
- buf[0] = Number((now >> 40n) & 0xffn);
35
- buf[1] = Number((now >> 32n) & 0xffn);
36
- buf[2] = Number((now >> 24n) & 0xffn);
37
- buf[3] = Number((now >> 16n) & 0xffn);
38
- buf[4] = Number((now >> 8n) & 0xffn);
39
- buf[5] = Number(now & 0xffn);
40
- buf[6] = ((_seq >> 8) & 0x0f) | 0x70;
41
- buf[7] = _seq & 0xff;
42
- buf[8] = (buf[8] & 0x3f) | 0x80;
43
- const h = buf.toString("hex");
44
- return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
45
- }