@triflux/remote 10.50.1 → 10.51.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/brief.mjs +0 -12
- package/cto/collect.mjs +16 -247
- package/cto/current.schema.json +4 -20
- package/cto/events.mjs +13 -294
- package/cto/hygiene.mjs +26 -346
- package/cto/lake-root.mjs +114 -16
- package/cto/status.mjs +33 -128
- package/hub/index.mjs +0 -8
- package/hub/store-adapter.mjs +1 -1
- package/hub/team/agent-map.json +0 -1
- package/hub/team/ansi.mjs +1 -35
- package/hub/team/backend.mjs +9 -145
- package/hub/team/cli/commands/attach.mjs +1 -17
- package/hub/team/cli/commands/control.mjs +12 -38
- package/hub/team/cli/commands/debug.mjs +1 -37
- package/hub/team/cli/commands/focus.mjs +5 -31
- package/hub/team/cli/commands/interrupt.mjs +6 -25
- package/hub/team/cli/commands/kill.mjs +1 -30
- package/hub/team/cli/commands/list.mjs +0 -16
- package/hub/team/cli/commands/send.mjs +6 -26
- package/hub/team/cli/commands/start/index.mjs +41 -133
- package/hub/team/cli/commands/start/parse-args.mjs +15 -40
- package/hub/team/cli/commands/start/start-headless.mjs +138 -105
- package/hub/team/cli/commands/start/start-mux.mjs +0 -3
- package/hub/team/cli/commands/status.mjs +2 -57
- package/hub/team/cli/commands/stop.mjs +14 -19
- package/hub/team/cli/help.mjs +4 -5
- package/hub/team/cli/manifest.mjs +5 -1
- package/hub/team/cli/render.mjs +0 -12
- package/hub/team/cli/services/hub-client.mjs +2 -88
- package/hub/team/cli/services/runtime-mode.mjs +27 -98
- package/hub/team/handoff.mjs +3 -34
- package/hub/team/headless.mjs +14 -755
- package/hub/team/orchestrator.mjs +4 -30
- package/hub/team/pane.mjs +6 -28
- package/hub/team/psmux.mjs +16 -403
- package/hub/team/remote-session.mjs +1 -2
- package/hub/team/session.mjs +8 -119
- package/hub/team/swarm-intent.mjs +0 -198
- package/hub/team/terminal-opener.mjs +11 -35
- package/hub/team/tui-core.mjs +1 -1
- package/hub/team/tui-viewer.mjs +2 -2
- package/hub/team/tui.mjs +8 -269
- package/hub/team/wt-manager.mjs +2 -2
- package/hub/workers/factory.mjs +4 -37
- package/hub/workers/lib/jsonrpc-ws-uds.mjs +0 -2
- package/package.json +1 -1
- package/scripts/lib/agent-route-policy.mjs +162 -14
- package/scripts/lib/claudemd-scanner.mjs +2 -199
- package/scripts/lib/cli-claude.mjs +0 -2
- package/scripts/lib/context.mjs +3 -19
- package/scripts/lib/env-probe.mjs +5 -64
- package/scripts/lib/gemini-profiles.mjs +2 -69
- package/scripts/lib/legacy-mcp-cleanup.mjs +14 -3
- package/scripts/lib/machine-profile.mjs +3 -17
- package/scripts/lib/mcp-filter.mjs +109 -53
- package/scripts/lib/mcp-health.mjs +2 -2
- package/scripts/lib/mcp-server-catalog.mjs +2 -2
- package/scripts/lib/psmux-info.mjs +25 -104
- package/scripts/lib/skill-template.mjs +0 -271
- package/cto/hygiene-actions.mjs +0 -355
- package/cto/hygiene-notify.mjs +0 -170
- package/hub/team/build-worker-prompt.mjs +0 -92
- package/hub/team/check-mcp-hub.mjs +0 -49
- package/hub/team/claude-native-bridge.mjs +0 -987
- package/hub/team/cli/commands/start/start-in-process.mjs +0 -50
- package/hub/team/cli/commands/start/start-wt.mjs +0 -86
- package/hub/team/cli/services/native-control.mjs +0 -145
- package/hub/team/codex-review.mjs +0 -520
- package/hub/team/conductor-mesh-bridge.mjs +0 -122
- package/hub/team/conductor.mjs +0 -1529
- package/hub/team/consensus-meta.mjs +0 -176
- package/hub/team/cto-pull.mjs +0 -31
- package/hub/team/daemon-pty-tmux-bridge.mjs +0 -146
- package/hub/team/dashboard.mjs +0 -322
- package/hub/team/event-log.mjs +0 -84
- package/hub/team/execution-mode.mjs +0 -324
- package/hub/team/extract-completion-payload.mjs +0 -110
- package/hub/team/headless-bridge-session.mjs +0 -17
- package/hub/team/health-probe.mjs +0 -435
- package/hub/team/interactive-native-launcher.mjs +0 -119
- package/hub/team/interactive-native-worker.mjs +0 -80
- package/hub/team/interactive-tui-transport.mjs +0 -479
- package/hub/team/launcher-template.mjs +0 -144
- package/hub/team/mcp-selector.mjs +0 -145
- package/hub/team/native-supervisor.mjs +0 -460
- package/hub/team/native.mjs +0 -727
- package/hub/team/recovery-store.mjs +0 -149
- package/hub/team/remote-probe.mjs +0 -292
- package/hub/team/remote-watcher.mjs +0 -506
- package/hub/team/runtime-strategy.mjs +0 -200
- package/hub/team/schemas/worker-completion.json +0 -39
- package/hub/team/sentinel-capture.mjs +0 -127
- package/hub/team/swarm-cli.mjs +0 -390
- package/hub/team/swarm-hypervisor.mjs +0 -2206
- package/hub/team/swarm-locks.mjs +0 -335
- package/hub/team/swarm-planner.mjs +0 -371
- package/hub/team/swarm-preflight.mjs +0 -366
- package/hub/team/swarm-reconciler.mjs +0 -242
- package/hub/team/tui-remote-adapter.mjs +0 -377
- package/hub/team/worker-completion-validator.mjs +0 -79
- package/hub/team/worktree-lifecycle.mjs +0 -639
- package/hub/team/wt-templates.json +0 -43
- package/hub/workers/antigravity-route-worker.mjs +0 -179
- package/hub/workers/gemini-worker.mjs +0 -217
- package/scripts/lib/agent-json.mjs +0 -27
- package/scripts/lib/async.mjs +0 -174
- package/scripts/lib/cli-agy.mjs +0 -85
- package/scripts/lib/cli-codex.mjs +0 -62
- package/scripts/lib/cli-gemini.mjs +0 -37
- package/scripts/lib/dynamic-route-cli.mjs +0 -107
- package/scripts/lib/env.mjs +0 -14
- package/scripts/lib/hub.mjs +0 -48
- package/scripts/lib/pid.mjs +0 -63
- package/scripts/lib/quota.mjs +0 -47
- package/scripts/lib/skill-state.mjs +0 -220
- package/scripts/lib/team.mjs +0 -75
- package/scripts/lib/timeout.mjs +0 -66
- package/scripts/lib/tmp.mjs +0 -26
- package/scripts/lib/toml.mjs +0 -132
package/cto/brief.mjs
CHANGED
|
@@ -27,13 +27,6 @@ function formatGoal(goal) {
|
|
|
27
27
|
return `- ${id} ${status}: ${title}`;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
function formatShard(shard) {
|
|
31
|
-
const id = oneLine(shard?.id || shard?.name || shard?.sessionId, "shard");
|
|
32
|
-
const status = oneLine(shard?.status || shard?.state, "unknown");
|
|
33
|
-
const detail = oneLine(shard?.summary || shard?.objective || shard?.task, "");
|
|
34
|
-
return detail ? `- ${id} ${status}: ${detail}` : `- ${id} ${status}`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
30
|
function formatEvent(event) {
|
|
38
31
|
const ts = oneLine(event?.ts, "unknown_ts");
|
|
39
32
|
const name = oneLine(event?.event, "event");
|
|
@@ -61,9 +54,6 @@ export function renderBrief(current) {
|
|
|
61
54
|
const activeGoals = Array.isArray(summary.active_goals)
|
|
62
55
|
? summary.active_goals.slice(0, 3)
|
|
63
56
|
: [];
|
|
64
|
-
const swarmShards = Array.isArray(summary.swarm_shards)
|
|
65
|
-
? summary.swarm_shards.slice(0, 2)
|
|
66
|
-
: [];
|
|
67
57
|
const recentEvents = Array.isArray(current?.ledger_tail)
|
|
68
58
|
? current.ledger_tail.slice(-2)
|
|
69
59
|
: [];
|
|
@@ -75,8 +65,6 @@ export function renderBrief(current) {
|
|
|
75
65
|
`summary: ${oneLine(summary.repo_state, "no repo summary")}`,
|
|
76
66
|
"active_goals",
|
|
77
67
|
...(activeGoals.length > 0 ? activeGoals.map(formatGoal) : ["- none"]),
|
|
78
|
-
"swarm_shards",
|
|
79
|
-
...(swarmShards.length > 0 ? swarmShards.map(formatShard) : ["- none"]),
|
|
80
68
|
"hub_status",
|
|
81
69
|
`status: ${oneLine(hub.status, "unknown")} available: ${hub.available === true} detail: ${compactDetail(hub.detail)}`,
|
|
82
70
|
"recent_events",
|
package/cto/collect.mjs
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import {
|
|
3
|
-
appendFileSync,
|
|
4
|
-
closeSync,
|
|
5
3
|
existsSync,
|
|
6
4
|
mkdirSync,
|
|
7
|
-
openSync,
|
|
8
5
|
readdirSync,
|
|
9
6
|
readFileSync,
|
|
10
|
-
renameSync,
|
|
11
7
|
statSync,
|
|
12
|
-
unlinkSync,
|
|
13
|
-
writeFileSync,
|
|
14
8
|
} from "node:fs";
|
|
15
9
|
import { homedir } from "node:os";
|
|
16
|
-
import {
|
|
10
|
+
import { join, relative } from "node:path";
|
|
17
11
|
import { fileURLToPath } from "node:url";
|
|
18
12
|
|
|
19
13
|
import { renderBrief } from "./brief.mjs";
|
|
20
|
-
import {
|
|
14
|
+
import { appendCtoEvent } from "./events.mjs";
|
|
15
|
+
import {
|
|
16
|
+
firstExisting,
|
|
17
|
+
readJsonLines,
|
|
18
|
+
resolveLakeRootDir,
|
|
19
|
+
writeAtomic,
|
|
20
|
+
} from "./lake-root.mjs";
|
|
21
21
|
|
|
22
22
|
const SCHEMA_VERSION = "cto-lake.v1";
|
|
23
23
|
const SOURCE_REGISTRY = [
|
|
@@ -33,12 +33,6 @@ const SOURCE_REGISTRY = [
|
|
|
33
33
|
probe: ".triflux/hub/status.json or host tfx-hub cache",
|
|
34
34
|
enabled: true,
|
|
35
35
|
},
|
|
36
|
-
{
|
|
37
|
-
id: "tfx_swarm",
|
|
38
|
-
kind: "triflux-runtime-artifact",
|
|
39
|
-
probe: ".triflux/swarm-locks.json or .triflux/swarm/*.json",
|
|
40
|
-
enabled: true,
|
|
41
|
-
},
|
|
42
36
|
{
|
|
43
37
|
id: "tfx_team",
|
|
44
38
|
kind: "triflux-runtime-artifact",
|
|
@@ -69,24 +63,6 @@ const SOURCE_REGISTRY = [
|
|
|
69
63
|
probe: ".omx/handoffs/*",
|
|
70
64
|
enabled: true,
|
|
71
65
|
},
|
|
72
|
-
{
|
|
73
|
-
id: "session_vault",
|
|
74
|
-
kind: "optional-durable-ref",
|
|
75
|
-
probe: ".triflux/session-vault.json, sessions_v2.db, or .session-vault",
|
|
76
|
-
enabled: true,
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
id: "agy",
|
|
80
|
-
kind: "optional-durable-ref",
|
|
81
|
-
probe: ".agy/state.json or .agy/refs.json",
|
|
82
|
-
enabled: true,
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
id: "gbrain",
|
|
86
|
-
kind: "optional-durable-ref",
|
|
87
|
-
probe: ".gbrain/refs.json or .gbrain/config.json",
|
|
88
|
-
enabled: true,
|
|
89
|
-
},
|
|
90
66
|
];
|
|
91
67
|
const SOURCE_IDS = SOURCE_REGISTRY.map((source) => source.id);
|
|
92
68
|
|
|
@@ -104,10 +80,6 @@ function isoNow(opts) {
|
|
|
104
80
|
return value.toISOString();
|
|
105
81
|
}
|
|
106
82
|
|
|
107
|
-
function sleep(ms) {
|
|
108
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
109
|
-
}
|
|
110
|
-
|
|
111
83
|
function sourceState(available, status, detail, collectedAt) {
|
|
112
84
|
return {
|
|
113
85
|
available,
|
|
@@ -130,25 +102,6 @@ function readJson(filePath) {
|
|
|
130
102
|
return JSON.parse(readFileSync(filePath, "utf8"));
|
|
131
103
|
}
|
|
132
104
|
|
|
133
|
-
function readJsonLines(filePath, limit = 20) {
|
|
134
|
-
if (!existsSync(filePath)) return [];
|
|
135
|
-
const lines = readFileSync(filePath, "utf8")
|
|
136
|
-
.split(/\r?\n/u)
|
|
137
|
-
.map((line) => line.trim())
|
|
138
|
-
.filter(Boolean);
|
|
139
|
-
return lines.slice(-limit).flatMap((line) => {
|
|
140
|
-
try {
|
|
141
|
-
return [JSON.parse(line)];
|
|
142
|
-
} catch {
|
|
143
|
-
return [];
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function findFirstExisting(candidates) {
|
|
149
|
-
return candidates.find((candidate) => existsSync(candidate)) || null;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
105
|
function listDirFiles(dirPath, rootDir, limit = 10) {
|
|
153
106
|
if (!existsSync(dirPath)) return [];
|
|
154
107
|
try {
|
|
@@ -237,7 +190,7 @@ function collectJsonArtifact(
|
|
|
237
190
|
collectedAt,
|
|
238
191
|
summarize = safeSummary,
|
|
239
192
|
) {
|
|
240
|
-
const filePath =
|
|
193
|
+
const filePath = firstExisting(candidates);
|
|
241
194
|
if (!filePath) {
|
|
242
195
|
return missingSource(
|
|
243
196
|
"no_shell_readable_artifact",
|
|
@@ -347,70 +300,6 @@ function collectUltragoal(dirPath, rootDir, collectedAt) {
|
|
|
347
300
|
}
|
|
348
301
|
}
|
|
349
302
|
|
|
350
|
-
export function collectSwarm(rootDir, collectedAt) {
|
|
351
|
-
const locksPath = join(rootDir, ".triflux", "swarm-locks.json");
|
|
352
|
-
const logsDir = join(rootDir, ".triflux", "swarm-logs");
|
|
353
|
-
if (!existsSync(locksPath) && !existsSync(logsDir)) {
|
|
354
|
-
return missingSource(
|
|
355
|
-
"no_shell_readable_artifact",
|
|
356
|
-
"no swarm locks or logs found",
|
|
357
|
-
collectedAt,
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
try {
|
|
361
|
-
const detail = { locks_path: null, locks: null, shards: [], log_runs: [] };
|
|
362
|
-
if (existsSync(locksPath)) {
|
|
363
|
-
const locks = readJson(locksPath);
|
|
364
|
-
detail.locks_path = relPath(rootDir, locksPath);
|
|
365
|
-
detail.locks = safeSummary(locks);
|
|
366
|
-
if (Array.isArray(locks?.shards)) detail.shards = locks.shards;
|
|
367
|
-
else if (Array.isArray(locks)) detail.shards = locks;
|
|
368
|
-
else if (locks && typeof locks === "object") {
|
|
369
|
-
// 실제 producer(hub/team/swarm-locks.mjs persist)는
|
|
370
|
-
// { "<file>": { workerId, leaseType, sessionMeta } } 형태의 lock map 을 쓴다.
|
|
371
|
-
// workerId 가 곧 shard.name 이다 — swarm-hypervisor 가
|
|
372
|
-
// acquire(shard.name, shard.files) 로 잠그기 때문(swarm-hypervisor.mjs:753).
|
|
373
|
-
// workerId 별로 묶어 active shard row 로 환원한다. (expired lock 정밀 필터는
|
|
374
|
-
// hub snapshot() 의 책임이라, 여기서는 persist 된 보유 lock 전부를 active 로 본다.)
|
|
375
|
-
const byWorker = new Map();
|
|
376
|
-
for (const entry of Object.values(locks)) {
|
|
377
|
-
const workerId =
|
|
378
|
-
entry && typeof entry.workerId === "string" ? entry.workerId : null;
|
|
379
|
-
if (!workerId) continue;
|
|
380
|
-
let row = byWorker.get(workerId);
|
|
381
|
-
if (!row) {
|
|
382
|
-
row = { shard_name: workerId, phase: "active", members: [] };
|
|
383
|
-
byWorker.set(workerId, row);
|
|
384
|
-
}
|
|
385
|
-
const host = entry?.sessionMeta?.host;
|
|
386
|
-
if (typeof host === "string" && host && !row.members.includes(host)) {
|
|
387
|
-
row.members.push(host);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
detail.shards = [...byWorker.values()];
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
if (existsSync(logsDir)) {
|
|
394
|
-
detail.log_runs = readdirSync(logsDir, { withFileTypes: true })
|
|
395
|
-
.filter((entry) => entry.isDirectory() && entry.name.startsWith("run-"))
|
|
396
|
-
.map((entry) => {
|
|
397
|
-
const path = join(logsDir, entry.name);
|
|
398
|
-
return { id: entry.name, mtime: statSync(path).mtime.toISOString() };
|
|
399
|
-
})
|
|
400
|
-
.sort((a, b) => b.mtime.localeCompare(a.mtime))
|
|
401
|
-
.slice(0, 5);
|
|
402
|
-
}
|
|
403
|
-
return sourceState(true, "ok", detail, collectedAt);
|
|
404
|
-
} catch (error) {
|
|
405
|
-
return sourceState(
|
|
406
|
-
true,
|
|
407
|
-
"read_error",
|
|
408
|
-
error?.message || "swarm read failed",
|
|
409
|
-
collectedAt,
|
|
410
|
-
);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
303
|
function collectHandoffs(rootDir, collectedAt) {
|
|
415
304
|
const dirPath = join(rootDir, ".omx", "handoffs");
|
|
416
305
|
const files = listDirFiles(dirPath, rootDir, 10);
|
|
@@ -429,64 +318,10 @@ function collectHandoffs(rootDir, collectedAt) {
|
|
|
429
318
|
);
|
|
430
319
|
}
|
|
431
320
|
|
|
432
|
-
function collectDurableRefs(
|
|
433
|
-
id,
|
|
434
|
-
candidates,
|
|
435
|
-
rootDir,
|
|
436
|
-
collectedAt,
|
|
437
|
-
unavailableStatus = "no_shell_readable_artifact",
|
|
438
|
-
) {
|
|
439
|
-
const filePath = findFirstExisting(candidates);
|
|
440
|
-
if (!filePath) {
|
|
441
|
-
return missingSource(
|
|
442
|
-
unavailableStatus,
|
|
443
|
-
`${id} exposes no shell-readable durable artifact`,
|
|
444
|
-
collectedAt,
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
try {
|
|
448
|
-
const stat = statSync(filePath);
|
|
449
|
-
if (stat.isDirectory()) {
|
|
450
|
-
return sourceState(
|
|
451
|
-
true,
|
|
452
|
-
"ok",
|
|
453
|
-
{
|
|
454
|
-
path: relPath(rootDir, filePath),
|
|
455
|
-
files: listDirFiles(filePath, rootDir, 10),
|
|
456
|
-
},
|
|
457
|
-
collectedAt,
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
const parsed = basename(filePath).endsWith(".json")
|
|
461
|
-
? readJson(filePath)
|
|
462
|
-
: readFileSync(filePath, "utf8");
|
|
463
|
-
return sourceState(
|
|
464
|
-
true,
|
|
465
|
-
"ok",
|
|
466
|
-
{
|
|
467
|
-
path: relPath(rootDir, filePath),
|
|
468
|
-
summary: safeSummary(parsed),
|
|
469
|
-
},
|
|
470
|
-
collectedAt,
|
|
471
|
-
);
|
|
472
|
-
} catch (error) {
|
|
473
|
-
return sourceState(
|
|
474
|
-
true,
|
|
475
|
-
"read_error",
|
|
476
|
-
{
|
|
477
|
-
path: relPath(rootDir, filePath),
|
|
478
|
-
error: error?.message || `${id} read failed`,
|
|
479
|
-
},
|
|
480
|
-
collectedAt,
|
|
481
|
-
);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
321
|
function buildSummary(current) {
|
|
486
322
|
const repo = current.repo;
|
|
487
323
|
const omxGoals = current.sources.ultragoal_omx.detail?.active_goals || [];
|
|
488
324
|
const omcGoals = current.sources.ultragoal_omc.detail?.active_goals || [];
|
|
489
|
-
const swarmShards = current.sources.tfx_swarm.detail?.shards || [];
|
|
490
325
|
const availableSources = Object.values(current.sources).filter(
|
|
491
326
|
(source) => source.available,
|
|
492
327
|
).length;
|
|
@@ -494,7 +329,6 @@ function buildSummary(current) {
|
|
|
494
329
|
return {
|
|
495
330
|
repo_state: `branch ${repo.branch || "unknown"} at ${repo.head || "unknown"} is ${repo.dirty ? "dirty" : "clean"}`,
|
|
496
331
|
active_goals: [...omxGoals, ...omcGoals].slice(0, 5),
|
|
497
|
-
swarm_shards: Array.isArray(swarmShards) ? swarmShards.slice(0, 5) : [],
|
|
498
332
|
hub_status: current.sources.tfx_hub.status,
|
|
499
333
|
available_sources: availableSources,
|
|
500
334
|
missing_sources: SOURCE_IDS.length - availableSources,
|
|
@@ -633,48 +467,6 @@ function validateCurrent(current) {
|
|
|
633
467
|
}
|
|
634
468
|
}
|
|
635
469
|
|
|
636
|
-
function writeAtomic(filePath, body) {
|
|
637
|
-
mkdirSync(dirname(filePath), { recursive: true });
|
|
638
|
-
const tmpPath = join(
|
|
639
|
-
dirname(filePath),
|
|
640
|
-
`.${basename(filePath)}.${process.pid}.${Date.now()}.tmp`,
|
|
641
|
-
);
|
|
642
|
-
writeFileSync(tmpPath, body, "utf8");
|
|
643
|
-
renameSync(tmpPath, filePath);
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
async function appendLedgerEvent(lakeRoot, event, stderr) {
|
|
647
|
-
mkdirSync(lakeRoot, { recursive: true });
|
|
648
|
-
const ledgerPath = join(lakeRoot, "ledger.jsonl");
|
|
649
|
-
const lockPath = join(lakeRoot, "ledger.jsonl.lock");
|
|
650
|
-
let fd = null;
|
|
651
|
-
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
652
|
-
try {
|
|
653
|
-
fd = openSync(lockPath, "wx", 0o600);
|
|
654
|
-
break;
|
|
655
|
-
} catch (error) {
|
|
656
|
-
if (error?.code !== "EEXIST") throw error;
|
|
657
|
-
if (attempt < 2) await sleep(100);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
if (fd === null) {
|
|
661
|
-
stderr.write(
|
|
662
|
-
"[tfx cto collect] warning: ledger lock timeout; skipped ledger append\n",
|
|
663
|
-
);
|
|
664
|
-
return false;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
try {
|
|
668
|
-
appendFileSync(ledgerPath, `${JSON.stringify(event)}\n`, "utf8");
|
|
669
|
-
return true;
|
|
670
|
-
} finally {
|
|
671
|
-
closeSync(fd);
|
|
672
|
-
try {
|
|
673
|
-
unlinkSync(lockPath);
|
|
674
|
-
} catch {}
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
|
|
678
470
|
function collectSources(rootDir, collectedAt, execFileSyncFn, opts = {}) {
|
|
679
471
|
const home = homedir();
|
|
680
472
|
const hostArtifactCandidates =
|
|
@@ -717,7 +509,6 @@ function collectSources(rootDir, collectedAt, execFileSyncFn, opts = {}) {
|
|
|
717
509
|
rootDir,
|
|
718
510
|
collectedAt,
|
|
719
511
|
),
|
|
720
|
-
tfx_swarm: collectSwarm(rootDir, collectedAt),
|
|
721
512
|
tfx_team: collectJsonArtifact(
|
|
722
513
|
"tfx_team",
|
|
723
514
|
[
|
|
@@ -748,34 +539,6 @@ function collectSources(rootDir, collectedAt, execFileSyncFn, opts = {}) {
|
|
|
748
539
|
collectedAt,
|
|
749
540
|
),
|
|
750
541
|
handoffs: collectHandoffs(rootDir, collectedAt),
|
|
751
|
-
session_vault: collectDurableRefs(
|
|
752
|
-
"session_vault",
|
|
753
|
-
[
|
|
754
|
-
join(rootDir, ".triflux", "session-vault.json"),
|
|
755
|
-
join(rootDir, "sessions_v2.db"),
|
|
756
|
-
join(rootDir, ".session-vault"),
|
|
757
|
-
],
|
|
758
|
-
rootDir,
|
|
759
|
-
collectedAt,
|
|
760
|
-
"not_shell_collectable",
|
|
761
|
-
),
|
|
762
|
-
agy: collectDurableRefs(
|
|
763
|
-
"agy",
|
|
764
|
-
[join(rootDir, ".agy", "state.json"), join(rootDir, ".agy", "refs.json")],
|
|
765
|
-
rootDir,
|
|
766
|
-
collectedAt,
|
|
767
|
-
"not_shell_collectable",
|
|
768
|
-
),
|
|
769
|
-
gbrain: collectDurableRefs(
|
|
770
|
-
"gbrain",
|
|
771
|
-
[
|
|
772
|
-
join(rootDir, ".gbrain", "refs.json"),
|
|
773
|
-
join(rootDir, ".gbrain", "config.json"),
|
|
774
|
-
],
|
|
775
|
-
rootDir,
|
|
776
|
-
collectedAt,
|
|
777
|
-
"not_shell_collectable",
|
|
778
|
-
),
|
|
779
542
|
};
|
|
780
543
|
|
|
781
544
|
return { repo: git.repo, sources };
|
|
@@ -786,6 +549,12 @@ function hasFlag(args, flag) {
|
|
|
786
549
|
}
|
|
787
550
|
|
|
788
551
|
export async function runCollect(args = [], opts = {}) {
|
|
552
|
+
if (hasFlag(args, "--help")) {
|
|
553
|
+
(opts.stdout || process.stdout).write(
|
|
554
|
+
"Usage: tfx cto collect [--json]\nRefresh the CTO lake from durable authority sources.\n",
|
|
555
|
+
);
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
789
558
|
const rootDir = opts.rootDir || resolveLakeRootDir(process.cwd());
|
|
790
559
|
const lakeRoot = opts.lakeRoot || join(rootDir, ".triflux", "lake");
|
|
791
560
|
const stdout = opts.stdout || process.stdout;
|
|
@@ -822,7 +591,7 @@ export async function runCollect(args = [], opts = {}) {
|
|
|
822
591
|
sources_json: "sources.json",
|
|
823
592
|
},
|
|
824
593
|
};
|
|
825
|
-
const appended = await
|
|
594
|
+
const { appended } = await appendCtoEvent(lakeRoot, event, { stderr });
|
|
826
595
|
if (appended) current.ledger_tail = readLedgerTail(lakeRoot);
|
|
827
596
|
|
|
828
597
|
validateCurrent(current);
|
package/cto/current.schema.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://triflux.local/schemas/cto/current.schema.json",
|
|
4
4
|
"title": "Triflux CTO Lake Current Authority State",
|
|
5
|
-
"description": "Contract for .triflux/lake/current.json. .triflux/lake is a triflux-owned, namespace-neutral cross-agent rollup for durable artifacts across Claude, Codex/OMX, OMC,
|
|
5
|
+
"description": "Contract for .triflux/lake/current.json. .triflux/lake is a triflux-owned, namespace-neutral cross-agent rollup for durable artifacts across Claude, Codex/OMX, OMC, and Triflux state. It reads and aggregates .omx/ultragoal and .omc/ultragoal execution ledgers without replacing or duplicating their authority. ledger.jsonl and sources.json companion contracts are documented in $defs.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": false,
|
|
8
8
|
"required": [
|
|
@@ -44,20 +44,16 @@
|
|
|
44
44
|
},
|
|
45
45
|
"sources": {
|
|
46
46
|
"type": "object",
|
|
47
|
-
"description": "Durable artifact source states only.
|
|
47
|
+
"description": "Durable artifact source states only. A source reports available:false when no shell-readable durable artifact exists.",
|
|
48
48
|
"additionalProperties": false,
|
|
49
49
|
"required": [
|
|
50
50
|
"git",
|
|
51
51
|
"tfx_hub",
|
|
52
|
-
"tfx_swarm",
|
|
53
52
|
"tfx_team",
|
|
54
53
|
"tfx_synapse",
|
|
55
54
|
"ultragoal_omx",
|
|
56
55
|
"ultragoal_omc",
|
|
57
|
-
"handoffs"
|
|
58
|
-
"session_vault",
|
|
59
|
-
"agy",
|
|
60
|
-
"gbrain"
|
|
56
|
+
"handoffs"
|
|
61
57
|
],
|
|
62
58
|
"properties": {
|
|
63
59
|
"git": {
|
|
@@ -66,9 +62,6 @@
|
|
|
66
62
|
"tfx_hub": {
|
|
67
63
|
"$ref": "#/$defs/sourceState"
|
|
68
64
|
},
|
|
69
|
-
"tfx_swarm": {
|
|
70
|
-
"$ref": "#/$defs/sourceState"
|
|
71
|
-
},
|
|
72
65
|
"tfx_team": {
|
|
73
66
|
"$ref": "#/$defs/sourceState"
|
|
74
67
|
},
|
|
@@ -83,21 +76,12 @@
|
|
|
83
76
|
},
|
|
84
77
|
"handoffs": {
|
|
85
78
|
"$ref": "#/$defs/sourceState"
|
|
86
|
-
},
|
|
87
|
-
"session_vault": {
|
|
88
|
-
"$ref": "#/$defs/sourceState"
|
|
89
|
-
},
|
|
90
|
-
"agy": {
|
|
91
|
-
"$ref": "#/$defs/sourceState"
|
|
92
|
-
},
|
|
93
|
-
"gbrain": {
|
|
94
|
-
"$ref": "#/$defs/sourceState"
|
|
95
79
|
}
|
|
96
80
|
}
|
|
97
81
|
},
|
|
98
82
|
"summary": {
|
|
99
83
|
"type": "object",
|
|
100
|
-
"description": "Human-
|
|
84
|
+
"description": "Human-oriented synthesized authority summary derived from durable artifacts and live Triflux synapse session status. Phase 1 may add source-derived fields here without changing the top-level contract.",
|
|
101
85
|
"additionalProperties": true
|
|
102
86
|
},
|
|
103
87
|
"ledger_tail": {
|