@triflux/remote 10.41.1 → 10.43.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.
- package/cto/hygiene-actions.mjs +355 -0
- package/cto/hygiene.mjs +79 -9
- package/cto/steward.mjs +362 -0
- package/hub/log-retention.mjs +726 -0
- package/hub/pipe.mjs +5 -1
- package/hub/public/tray.html +50 -53
- package/hub/schema.sql +149 -0
- package/hub/server.mjs +44 -22
- package/hub/store.mjs +37 -19
- package/hub/team/claude-daemon-control.mjs +33 -12
- package/hub/team/cli/commands/start/parse-args.mjs +2 -2
- package/hub/team/headless.mjs +275 -24
- package/hub/team/intervention.mjs +530 -0
- package/hub/team/retry-state-machine.mjs +6 -2
- package/hub/team/swarm-hypervisor.mjs +19 -2
- package/hub/team/swarm-locks.mjs +17 -1
- package/hub/team/uds-orchestrator.mjs +62 -9
- package/hub/tools.mjs +5 -7
- package/hub/workers/codex-app-server-worker.mjs +54 -5
- package/hub/workers/codex-mcp.mjs +1 -1
- package/hub/workers/delegator-mcp.mjs +18 -18
- package/package.json +1 -1
- package/scripts/lib/cli-agy.mjs +1 -0
- package/scripts/lib/cli-claude.mjs +1 -0
- package/scripts/lib/cli-codex.mjs +22 -21
- package/scripts/lib/codex-profile-config.mjs +2 -2
package/hub/store.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { mkdirSync, readFileSync } from "node:fs";
|
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { clampDurationMs, DEFAULT_ASSIGN_TIMEOUT_MS, DEFAULT_ASSIGN_TTL_MS } from "@triflux/core/hub/lib/timeout-defaults.mjs";
|
|
8
9
|
import { uuidv7 } from "@triflux/core/hub/lib/uuidv7.mjs";
|
|
9
10
|
import { recalcConfidence } from "@triflux/core/hub/reflexion.mjs";
|
|
10
11
|
|
|
@@ -111,7 +112,7 @@ export function createStore(dbPath, options = {}) {
|
|
|
111
112
|
db.exec(
|
|
112
113
|
"CREATE TABLE IF NOT EXISTS _meta (key TEXT PRIMARY KEY, value TEXT)",
|
|
113
114
|
);
|
|
114
|
-
const SCHEMA_VERSION = "
|
|
115
|
+
const SCHEMA_VERSION = "5";
|
|
115
116
|
const curVer = (() => {
|
|
116
117
|
try {
|
|
117
118
|
return db
|
|
@@ -143,6 +144,7 @@ export function createStore(dbPath, options = {}) {
|
|
|
143
144
|
"type",
|
|
144
145
|
"TEXT NOT NULL DEFAULT 'reflexion'",
|
|
145
146
|
);
|
|
147
|
+
ensureColumn(db, "assign_jobs", "dispatched_at_ms", "INTEGER");
|
|
146
148
|
ensureColumn(
|
|
147
149
|
db,
|
|
148
150
|
"reflexion_entries",
|
|
@@ -233,12 +235,12 @@ export function createStore(dbPath, options = {}) {
|
|
|
233
235
|
job_id, supervisor_agent, worker_agent, topic, task, payload_json,
|
|
234
236
|
status, attempt, retry_count, max_retries, priority, ttl_ms, timeout_ms, deadline_ms,
|
|
235
237
|
trace_id, correlation_id, last_message_id, result_json, error_json,
|
|
236
|
-
created_at_ms, updated_at_ms, started_at_ms, completed_at_ms, last_retry_at_ms
|
|
238
|
+
created_at_ms, updated_at_ms, started_at_ms, dispatched_at_ms, completed_at_ms, last_retry_at_ms
|
|
237
239
|
) VALUES (
|
|
238
240
|
@job_id, @supervisor_agent, @worker_agent, @topic, @task, @payload_json,
|
|
239
241
|
@status, @attempt, @retry_count, @max_retries, @priority, @ttl_ms, @timeout_ms, @deadline_ms,
|
|
240
242
|
@trace_id, @correlation_id, @last_message_id, @result_json, @error_json,
|
|
241
|
-
@created_at_ms, @updated_at_ms, @started_at_ms, @completed_at_ms, @last_retry_at_ms
|
|
243
|
+
@created_at_ms, @updated_at_ms, @started_at_ms, @dispatched_at_ms, @completed_at_ms, @last_retry_at_ms
|
|
242
244
|
)`),
|
|
243
245
|
getAssign: db.prepare("SELECT * FROM assign_jobs WHERE job_id = ?"),
|
|
244
246
|
updateAssign: db.prepare(`
|
|
@@ -263,6 +265,7 @@ export function createStore(dbPath, options = {}) {
|
|
|
263
265
|
error_json=@error_json,
|
|
264
266
|
updated_at_ms=@updated_at_ms,
|
|
265
267
|
started_at_ms=@started_at_ms,
|
|
268
|
+
dispatched_at_ms=@dispatched_at_ms,
|
|
266
269
|
completed_at_ms=@completed_at_ms,
|
|
267
270
|
last_retry_at_ms=@last_retry_at_ms
|
|
268
271
|
WHERE job_id=@job_id`),
|
|
@@ -356,12 +359,6 @@ export function createStore(dbPath, options = {}) {
|
|
|
356
359
|
return Math.max(1, Math.min(Math.trunc(num), 9));
|
|
357
360
|
}
|
|
358
361
|
|
|
359
|
-
function clampDuration(value, fallback = 600000, min = 1000, max = 86400000) {
|
|
360
|
-
const num = Number(value);
|
|
361
|
-
if (!Number.isFinite(num)) return fallback;
|
|
362
|
-
return Math.max(min, Math.min(Math.trunc(num), max));
|
|
363
|
-
}
|
|
364
|
-
|
|
365
362
|
const store = {
|
|
366
363
|
db,
|
|
367
364
|
uuidv7,
|
|
@@ -381,7 +378,8 @@ export function createStore(dbPath, options = {}) {
|
|
|
381
378
|
}) {
|
|
382
379
|
const now = Date.now();
|
|
383
380
|
const leaseExpires = now + heartbeat_ttl_ms;
|
|
384
|
-
|
|
381
|
+
const leaseId = uuidv7();
|
|
382
|
+
const write = S.upsertAgent.run({
|
|
385
383
|
agent_id,
|
|
386
384
|
cli,
|
|
387
385
|
pid: pid ?? null,
|
|
@@ -392,11 +390,23 @@ export function createStore(dbPath, options = {}) {
|
|
|
392
390
|
status: "online",
|
|
393
391
|
metadata_json: JSON.stringify(metadata),
|
|
394
392
|
});
|
|
393
|
+
const persisted = parseAgentRow(S.getAgent.get(agent_id));
|
|
395
394
|
return {
|
|
396
395
|
agent_id,
|
|
397
|
-
lease_id:
|
|
396
|
+
lease_id: leaseId,
|
|
398
397
|
lease_expires_ms: leaseExpires,
|
|
399
398
|
server_time_ms: now,
|
|
399
|
+
effective: {
|
|
400
|
+
updated: write.changes > 0,
|
|
401
|
+
online:
|
|
402
|
+
persisted?.status === "online" &&
|
|
403
|
+
Number(persisted.lease_expires_ms) === leaseExpires,
|
|
404
|
+
status: persisted?.status ?? null,
|
|
405
|
+
last_seen_ms: persisted?.last_seen_ms ?? null,
|
|
406
|
+
lease_expires_ms: persisted?.lease_expires_ms ?? null,
|
|
407
|
+
store_type: "sqlite",
|
|
408
|
+
db_path: dbPath ?? null,
|
|
409
|
+
},
|
|
400
410
|
};
|
|
401
411
|
},
|
|
402
412
|
|
|
@@ -406,11 +416,12 @@ export function createStore(dbPath, options = {}) {
|
|
|
406
416
|
|
|
407
417
|
refreshLease(agentId, ttlMs = 30000) {
|
|
408
418
|
const now = Date.now();
|
|
409
|
-
S.heartbeat.run(now, now + ttlMs, agentId);
|
|
419
|
+
const write = S.heartbeat.run(now, now + ttlMs, agentId);
|
|
410
420
|
return {
|
|
411
421
|
agent_id: agentId,
|
|
412
422
|
lease_expires_ms: now + ttlMs,
|
|
413
423
|
server_time_ms: now,
|
|
424
|
+
effective: { updated: write.changes > 0, store_type: "sqlite", db_path: dbPath ?? null },
|
|
414
425
|
};
|
|
415
426
|
},
|
|
416
427
|
|
|
@@ -616,9 +627,10 @@ export function createStore(dbPath, options = {}) {
|
|
|
616
627
|
retry_count = 0,
|
|
617
628
|
max_retries = 0,
|
|
618
629
|
priority = 5,
|
|
619
|
-
ttl_ms =
|
|
620
|
-
timeout_ms =
|
|
630
|
+
ttl_ms = DEFAULT_ASSIGN_TTL_MS,
|
|
631
|
+
timeout_ms = DEFAULT_ASSIGN_TIMEOUT_MS,
|
|
621
632
|
deadline_ms,
|
|
633
|
+
dispatched_at_ms = null,
|
|
622
634
|
trace_id,
|
|
623
635
|
correlation_id,
|
|
624
636
|
last_message_id = null,
|
|
@@ -626,7 +638,7 @@ export function createStore(dbPath, options = {}) {
|
|
|
626
638
|
error = null,
|
|
627
639
|
}) {
|
|
628
640
|
const now = Date.now();
|
|
629
|
-
const normalizedTimeout =
|
|
641
|
+
const normalizedTimeout = clampDurationMs(timeout_ms, DEFAULT_ASSIGN_TIMEOUT_MS);
|
|
630
642
|
const row = {
|
|
631
643
|
job_id: job_id || uuidv7(),
|
|
632
644
|
supervisor_agent,
|
|
@@ -639,7 +651,7 @@ export function createStore(dbPath, options = {}) {
|
|
|
639
651
|
retry_count: Math.max(0, Number(retry_count) || 0),
|
|
640
652
|
max_retries: Math.max(0, Number(max_retries) || 0),
|
|
641
653
|
priority: clampPriority(priority, 5),
|
|
642
|
-
ttl_ms:
|
|
654
|
+
ttl_ms: clampDurationMs(ttl_ms, normalizedTimeout),
|
|
643
655
|
timeout_ms: normalizedTimeout,
|
|
644
656
|
deadline_ms: Number.isFinite(Number(deadline_ms))
|
|
645
657
|
? Math.trunc(Number(deadline_ms))
|
|
@@ -652,6 +664,10 @@ export function createStore(dbPath, options = {}) {
|
|
|
652
664
|
created_at_ms: now,
|
|
653
665
|
updated_at_ms: now,
|
|
654
666
|
started_at_ms: status === "running" ? now : null,
|
|
667
|
+
dispatched_at_ms:
|
|
668
|
+
dispatched_at_ms == null || !Number.isFinite(Number(dispatched_at_ms))
|
|
669
|
+
? null
|
|
670
|
+
: Math.trunc(Number(dispatched_at_ms)),
|
|
655
671
|
completed_at_ms: ["succeeded", "failed", "timed_out"].includes(status)
|
|
656
672
|
? now
|
|
657
673
|
: null,
|
|
@@ -676,7 +692,7 @@ export function createStore(dbPath, options = {}) {
|
|
|
676
692
|
const isTerminal = ["succeeded", "failed", "timed_out"].includes(
|
|
677
693
|
nextStatus,
|
|
678
694
|
);
|
|
679
|
-
const nextTimeout =
|
|
695
|
+
const nextTimeout = clampDurationMs(
|
|
680
696
|
patch.timeout_ms ?? current.timeout_ms,
|
|
681
697
|
current.timeout_ms,
|
|
682
698
|
);
|
|
@@ -704,7 +720,7 @@ export function createStore(dbPath, options = {}) {
|
|
|
704
720
|
patch.priority ?? current.priority,
|
|
705
721
|
current.priority || 5,
|
|
706
722
|
),
|
|
707
|
-
ttl_ms:
|
|
723
|
+
ttl_ms: clampDurationMs(
|
|
708
724
|
patch.ttl_ms ?? current.ttl_ms,
|
|
709
725
|
current.ttl_ms || nextTimeout,
|
|
710
726
|
),
|
|
@@ -745,6 +761,7 @@ export function createStore(dbPath, options = {}) {
|
|
|
745
761
|
: nextStatus === "running"
|
|
746
762
|
? current.started_at_ms || now
|
|
747
763
|
: current.started_at_ms,
|
|
764
|
+
dispatched_at_ms: Object.hasOwn(patch, "dispatched_at_ms") ? patch.dispatched_at_ms : current.dispatched_at_ms,
|
|
748
765
|
completed_at_ms: Object.hasOwn(patch, "completed_at_ms")
|
|
749
766
|
? patch.completed_at_ms
|
|
750
767
|
: isTerminal
|
|
@@ -836,7 +853,7 @@ export function createStore(dbPath, options = {}) {
|
|
|
836
853
|
current.attempt + 1,
|
|
837
854
|
Number(patch.attempt ?? current.attempt + 1) || 1,
|
|
838
855
|
);
|
|
839
|
-
const nextTimeout =
|
|
856
|
+
const nextTimeout = clampDurationMs(
|
|
840
857
|
patch.timeout_ms ?? current.timeout_ms,
|
|
841
858
|
current.timeout_ms,
|
|
842
859
|
);
|
|
@@ -848,6 +865,7 @@ export function createStore(dbPath, options = {}) {
|
|
|
848
865
|
deadline_ms: Date.now() + nextTimeout,
|
|
849
866
|
completed_at_ms: null,
|
|
850
867
|
started_at_ms: null,
|
|
868
|
+
dispatched_at_ms: null,
|
|
851
869
|
last_retry_at_ms: Date.now(),
|
|
852
870
|
result: patch.result ?? null,
|
|
853
871
|
error: Object.hasOwn(patch, "error") ? patch.error : current.error,
|
|
@@ -464,25 +464,46 @@ export function sendClaudeControlRequest(
|
|
|
464
464
|
|
|
465
465
|
// claude daemon 은 control.sock 의 mutating op(dispatch 등)에 control-key
|
|
466
466
|
// 인증을 강제한다 (미제시 시 EAUTH "didn't present the daemon control key").
|
|
467
|
-
//
|
|
468
|
-
//
|
|
467
|
+
// OMC runtime config 는 .omc-launch-profile.json 의 sourceConfigDir 에서 key 를
|
|
468
|
+
// 발급한다. control.sock 은 runtime config hash 를 쓰더라도 auth 는 발급 config
|
|
469
|
+
// 에서 읽어야 한다. 일반 daemon 은 <configDir>/daemon/control.key 를 사용한다.
|
|
470
|
+
// 어느 경로에도 파일이 없으면 인증 미강제 daemon 으로 보고 auth 를 생략한다
|
|
471
|
+
// (fail-open — 구버전 호환).
|
|
469
472
|
export async function readDaemonControlKey(
|
|
470
473
|
configDir = resolveClaudeConfigDir(),
|
|
474
|
+
{ diagnostics } = {},
|
|
471
475
|
) {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
476
|
+
if (!configDir) return undefined;
|
|
477
|
+
|
|
478
|
+
const runtimeConfigDir = path.resolve(configDir);
|
|
479
|
+
const omcProfile = await readOmcLaunchProfile(runtimeConfigDir);
|
|
480
|
+
const keyConfigDirs = [omcProfile?.sourceConfigDir, runtimeConfigDir].filter(
|
|
481
|
+
(candidate, index, entries) =>
|
|
482
|
+
candidate && entries.indexOf(candidate) === index,
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
for (const keyConfigDir of keyConfigDirs) {
|
|
486
|
+
const keyPath = path.join(keyConfigDir, "daemon", "control.key");
|
|
487
|
+
try {
|
|
488
|
+
const key = await fs.readFile(keyPath, "utf8");
|
|
489
|
+
if (key.trim()) return key.trim();
|
|
490
|
+
} catch (error) {
|
|
491
|
+
if (error?.code === "ENOENT") continue;
|
|
492
|
+
if (Array.isArray(diagnostics)) {
|
|
493
|
+
diagnostics.push({
|
|
494
|
+
code: error?.code || "UNKNOWN",
|
|
495
|
+
path: keyPath,
|
|
496
|
+
message: error?.message || String(error),
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
480
500
|
}
|
|
501
|
+
return undefined;
|
|
481
502
|
}
|
|
482
503
|
|
|
483
|
-
export async function buildDaemonControlAuth(configDir) {
|
|
504
|
+
export async function buildDaemonControlAuth(configDir, opts = {}) {
|
|
484
505
|
if (!configDir) return {};
|
|
485
|
-
const auth = await readDaemonControlKey(configDir);
|
|
506
|
+
const auth = await readDaemonControlKey(configDir, opts);
|
|
486
507
|
return auth ? { auth } : {};
|
|
487
508
|
}
|
|
488
509
|
|
|
@@ -74,7 +74,7 @@ export function parseTeamArgs(args = []) {
|
|
|
74
74
|
const assigns = []; // --assign "codex:프롬프트:역할" 형식
|
|
75
75
|
let autoAttach = true;
|
|
76
76
|
let progressive = true;
|
|
77
|
-
let timeoutSec =
|
|
77
|
+
let timeoutSec = 0;
|
|
78
78
|
let verbose = false;
|
|
79
79
|
let dashboard = true;
|
|
80
80
|
let dashboardLayout = "lite";
|
|
@@ -130,7 +130,7 @@ export function parseTeamArgs(args = []) {
|
|
|
130
130
|
} else if (current === "--no-progressive") {
|
|
131
131
|
progressive = false;
|
|
132
132
|
} else if (current === "--timeout" && args[index + 1]) {
|
|
133
|
-
timeoutSec = Number(args[++index]) ||
|
|
133
|
+
timeoutSec = Number(args[++index]) || 0;
|
|
134
134
|
} else if (current === "--mcp-profile" && args[index + 1]) {
|
|
135
135
|
mcpProfile = args[++index].trim();
|
|
136
136
|
} else if ((current === "--model" || current === "-m") && args[index + 1]) {
|