@sentropic/h2a-runtime 0.81.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/dist/account-pool.d.ts +168 -0
- package/dist/account-pool.d.ts.map +1 -0
- package/dist/account-pool.js +385 -0
- package/dist/account-pool.js.map +1 -0
- package/dist/agents-projection.d.ts +56 -0
- package/dist/agents-projection.d.ts.map +1 -0
- package/dist/agents-projection.js +82 -0
- package/dist/agents-projection.js.map +1 -0
- package/dist/attach.d.ts +75 -0
- package/dist/attach.d.ts.map +1 -0
- package/dist/attach.js +432 -0
- package/dist/attach.js.map +1 -0
- package/dist/auth-bundle.d.ts +21 -0
- package/dist/auth-bundle.d.ts.map +1 -0
- package/dist/auth-bundle.js +112 -0
- package/dist/auth-bundle.js.map +1 -0
- package/dist/auth-diagnostics.d.ts +18 -0
- package/dist/auth-diagnostics.d.ts.map +1 -0
- package/dist/auth-diagnostics.js +23 -0
- package/dist/auth-diagnostics.js.map +1 -0
- package/dist/auth-login.d.ts +9 -0
- package/dist/auth-login.d.ts.map +1 -0
- package/dist/auth-login.js +21 -0
- package/dist/auth-login.js.map +1 -0
- package/dist/auth-refresh.d.ts +32 -0
- package/dist/auth-refresh.d.ts.map +1 -0
- package/dist/auth-refresh.js +83 -0
- package/dist/auth-refresh.js.map +1 -0
- package/dist/auth-tools.d.ts +55 -0
- package/dist/auth-tools.d.ts.map +1 -0
- package/dist/auth-tools.js +163 -0
- package/dist/auth-tools.js.map +1 -0
- package/dist/browser-bridge-local.d.ts +27 -0
- package/dist/browser-bridge-local.d.ts.map +1 -0
- package/dist/browser-bridge-local.js +51 -0
- package/dist/browser-bridge-local.js.map +1 -0
- package/dist/browser.d.ts +53 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +61 -0
- package/dist/browser.js.map +1 -0
- package/dist/conductor-launch.d.ts +179 -0
- package/dist/conductor-launch.d.ts.map +1 -0
- package/dist/conductor-launch.js +414 -0
- package/dist/conductor-launch.js.map +1 -0
- package/dist/config.d.ts +182 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +334 -0
- package/dist/config.js.map +1 -0
- package/dist/conv-guard.d.ts +76 -0
- package/dist/conv-guard.d.ts.map +1 -0
- package/dist/conv-guard.js +131 -0
- package/dist/conv-guard.js.map +1 -0
- package/dist/convsync.d.ts +24 -0
- package/dist/convsync.d.ts.map +1 -0
- package/dist/convsync.js +108 -0
- package/dist/convsync.js.map +1 -0
- package/dist/cred-health.d.ts +96 -0
- package/dist/cred-health.d.ts.map +1 -0
- package/dist/cred-health.js +170 -0
- package/dist/cred-health.js.map +1 -0
- package/dist/delegate.d.ts +406 -0
- package/dist/delegate.d.ts.map +1 -0
- package/dist/delegate.js +739 -0
- package/dist/delegate.js.map +1 -0
- package/dist/enroll.d.ts +91 -0
- package/dist/enroll.d.ts.map +1 -0
- package/dist/enroll.js +248 -0
- package/dist/enroll.js.map +1 -0
- package/dist/fanout.d.ts +63 -0
- package/dist/fanout.d.ts.map +1 -0
- package/dist/fanout.js +115 -0
- package/dist/fanout.js.map +1 -0
- package/dist/forward.d.ts +66 -0
- package/dist/forward.d.ts.map +1 -0
- package/dist/forward.js +141 -0
- package/dist/forward.js.map +1 -0
- package/dist/gitdiff.d.ts +31 -0
- package/dist/gitdiff.d.ts.map +1 -0
- package/dist/gitdiff.js +133 -0
- package/dist/gitdiff.js.map +1 -0
- package/dist/h2a-bridge.d.ts +102 -0
- package/dist/h2a-bridge.d.ts.map +1 -0
- package/dist/h2a-bridge.js +333 -0
- package/dist/h2a-bridge.js.map +1 -0
- package/dist/h2a-jobs.d.ts +235 -0
- package/dist/h2a-jobs.d.ts.map +1 -0
- package/dist/h2a-jobs.js +388 -0
- package/dist/h2a-jobs.js.map +1 -0
- package/dist/h2a-ping.d.ts +38 -0
- package/dist/h2a-ping.d.ts.map +1 -0
- package/dist/h2a-ping.js +58 -0
- package/dist/h2a-ping.js.map +1 -0
- package/dist/index.d.ts +98 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5887 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive-throttle.d.ts +164 -0
- package/dist/interactive-throttle.d.ts.map +1 -0
- package/dist/interactive-throttle.js +194 -0
- package/dist/interactive-throttle.js.map +1 -0
- package/dist/lineage-client.d.ts +77 -0
- package/dist/lineage-client.d.ts.map +1 -0
- package/dist/lineage-client.js +117 -0
- package/dist/lineage-client.js.map +1 -0
- package/dist/lineage-lease.d.ts +152 -0
- package/dist/lineage-lease.d.ts.map +1 -0
- package/dist/lineage-lease.js +303 -0
- package/dist/lineage-lease.js.map +1 -0
- package/dist/llm-gateway-runtime/accounts.d.ts +48 -0
- package/dist/llm-gateway-runtime/accounts.d.ts.map +1 -0
- package/dist/llm-gateway-runtime/accounts.js +226 -0
- package/dist/llm-gateway-runtime/accounts.js.map +1 -0
- package/dist/llm-gateway-runtime/index.d.ts +4 -0
- package/dist/llm-gateway-runtime/index.d.ts.map +1 -0
- package/dist/llm-gateway-runtime/index.js +58 -0
- package/dist/llm-gateway-runtime/index.js.map +1 -0
- package/dist/llm-gateway-runtime/model-catalog.d.ts +36 -0
- package/dist/llm-gateway-runtime/model-catalog.d.ts.map +1 -0
- package/dist/llm-gateway-runtime/model-catalog.js +146 -0
- package/dist/llm-gateway-runtime/model-catalog.js.map +1 -0
- package/dist/llm-gateway-runtime/proxy-anthropic.d.ts +3 -0
- package/dist/llm-gateway-runtime/proxy-anthropic.d.ts.map +1 -0
- package/dist/llm-gateway-runtime/proxy-anthropic.js +139 -0
- package/dist/llm-gateway-runtime/proxy-anthropic.js.map +1 -0
- package/dist/llm-gateway-runtime/proxy-openai.d.ts +117 -0
- package/dist/llm-gateway-runtime/proxy-openai.d.ts.map +1 -0
- package/dist/llm-gateway-runtime/proxy-openai.js +1132 -0
- package/dist/llm-gateway-runtime/proxy-openai.js.map +1 -0
- package/dist/llm-gateway-runtime/session-ledger.d.ts +32 -0
- package/dist/llm-gateway-runtime/session-ledger.d.ts.map +1 -0
- package/dist/llm-gateway-runtime/session-ledger.js +62 -0
- package/dist/llm-gateway-runtime/session-ledger.js.map +1 -0
- package/dist/llm-gateway-runtime/sticky.d.ts +40 -0
- package/dist/llm-gateway-runtime/sticky.d.ts.map +1 -0
- package/dist/llm-gateway-runtime/sticky.js +254 -0
- package/dist/llm-gateway-runtime/sticky.js.map +1 -0
- package/dist/llm-mesh.d.ts +102 -0
- package/dist/llm-mesh.d.ts.map +1 -0
- package/dist/llm-mesh.js +433 -0
- package/dist/llm-mesh.js.map +1 -0
- package/dist/migrate-candidates.d.ts +35 -0
- package/dist/migrate-candidates.d.ts.map +1 -0
- package/dist/migrate-candidates.js +128 -0
- package/dist/migrate-candidates.js.map +1 -0
- package/dist/migrate.d.ts +125 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +561 -0
- package/dist/migrate.js.map +1 -0
- package/dist/plugin-manifest.d.ts +143 -0
- package/dist/plugin-manifest.d.ts.map +1 -0
- package/dist/plugin-manifest.js +233 -0
- package/dist/plugin-manifest.js.map +1 -0
- package/dist/plugin.d.ts +274 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +919 -0
- package/dist/plugin.js.map +1 -0
- package/dist/pod-liveness.d.ts +51 -0
- package/dist/pod-liveness.d.ts.map +1 -0
- package/dist/pod-liveness.js +80 -0
- package/dist/pod-liveness.js.map +1 -0
- package/dist/profile-menu.d.ts +7 -0
- package/dist/profile-menu.d.ts.map +1 -0
- package/dist/profile-menu.js +52 -0
- package/dist/profile-menu.js.map +1 -0
- package/dist/profiles.d.ts +23 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +66 -0
- package/dist/profiles.js.map +1 -0
- package/dist/protocol-local.d.ts +27 -0
- package/dist/protocol-local.d.ts.map +1 -0
- package/dist/protocol-local.js +12 -0
- package/dist/protocol-local.js.map +1 -0
- package/dist/pty.d.ts +26 -0
- package/dist/pty.d.ts.map +1 -0
- package/dist/pty.js +45 -0
- package/dist/pty.js.map +1 -0
- package/dist/readiness.d.ts +38 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +169 -0
- package/dist/readiness.js.map +1 -0
- package/dist/registry.d.ts +258 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +570 -0
- package/dist/registry.js.map +1 -0
- package/dist/relaunch.d.ts +52 -0
- package/dist/relaunch.d.ts.map +1 -0
- package/dist/relaunch.js +76 -0
- package/dist/relaunch.js.map +1 -0
- package/dist/restore.d.ts +165 -0
- package/dist/restore.d.ts.map +1 -0
- package/dist/restore.js +530 -0
- package/dist/restore.js.map +1 -0
- package/dist/run.d.ts +29 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +206 -0
- package/dist/run.js.map +1 -0
- package/dist/secrets.d.ts +25 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +98 -0
- package/dist/secrets.js.map +1 -0
- package/dist/session-restore.d.ts +26 -0
- package/dist/session-restore.d.ts.map +1 -0
- package/dist/session-restore.js +122 -0
- package/dist/session-restore.js.map +1 -0
- package/dist/skills-sync.d.ts +126 -0
- package/dist/skills-sync.d.ts.map +1 -0
- package/dist/skills-sync.js +255 -0
- package/dist/skills-sync.js.map +1 -0
- package/dist/smoke.d.ts +23 -0
- package/dist/smoke.d.ts.map +1 -0
- package/dist/smoke.js +138 -0
- package/dist/smoke.js.map +1 -0
- package/dist/soft-refresh.d.ts +107 -0
- package/dist/soft-refresh.d.ts.map +1 -0
- package/dist/soft-refresh.js +426 -0
- package/dist/soft-refresh.js.map +1 -0
- package/dist/sync-status.d.ts +22 -0
- package/dist/sync-status.d.ts.map +1 -0
- package/dist/sync-status.js +41 -0
- package/dist/sync-status.js.map +1 -0
- package/dist/sync.d.ts +77 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +302 -0
- package/dist/sync.js.map +1 -0
- package/dist/throttle-signatures.d.ts +43 -0
- package/dist/throttle-signatures.d.ts.map +1 -0
- package/dist/throttle-signatures.js +116 -0
- package/dist/throttle-signatures.js.map +1 -0
- package/dist/tmux.d.ts +286 -0
- package/dist/tmux.d.ts.map +1 -0
- package/dist/tmux.js +970 -0
- package/dist/tmux.js.map +1 -0
- package/dist/tunnel.d.ts +25 -0
- package/dist/tunnel.d.ts.map +1 -0
- package/dist/tunnel.js +127 -0
- package/dist/tunnel.js.map +1 -0
- package/dist/workspace-merge.d.ts +17 -0
- package/dist/workspace-merge.d.ts.map +1 -0
- package/dist/workspace-merge.js +153 -0
- package/dist/workspace-merge.js.map +1 -0
- package/dist/workspace-sync-incremental.d.ts +64 -0
- package/dist/workspace-sync-incremental.d.ts.map +1 -0
- package/dist/workspace-sync-incremental.js +199 -0
- package/dist/workspace-sync-incremental.js.map +1 -0
- package/dist/workspace-sync.d.ts +3 -0
- package/dist/workspace-sync.d.ts.map +1 -0
- package/dist/workspace-sync.js +187 -0
- package/dist/workspace-sync.js.map +1 -0
- package/dist/workspace.d.ts +70 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +173 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +44 -0
package/dist/registry.js
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live-session registry — the source of truth for `remote ls` / `remote
|
|
3
|
+
* restore`, so they stop GUESSING sessions from filesystem mtimes.
|
|
4
|
+
*
|
|
5
|
+
* Entries land here from:
|
|
6
|
+
* - `remote run` (source "run" — local tmux sessions),
|
|
7
|
+
* - Claude Code hooks (source "hook" — `remote enroll --hook claude-*`),
|
|
8
|
+
* - the restore scanner (source "scan" — legacy fallback),
|
|
9
|
+
* - the control-plane (source "remote" — reconciled by the caller).
|
|
10
|
+
*
|
|
11
|
+
* The file is `<configDir>/registry.json`, written atomically (tmp + rename).
|
|
12
|
+
* Every function takes an optional explicit path so tests never touch the real
|
|
13
|
+
* config dir (default path honors REMOTE_CLI_CONFIG_HOME like config.ts).
|
|
14
|
+
*/
|
|
15
|
+
import { spawnSync } from "node:child_process";
|
|
16
|
+
import { closeSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
17
|
+
import { uptime } from "node:os";
|
|
18
|
+
import { dirname, join } from "node:path";
|
|
19
|
+
import { getLayoutConfig, resolveConfigPath } from "./config.js";
|
|
20
|
+
import { listLocalSessions } from "./tmux.js";
|
|
21
|
+
/** System boot time in ms epoch (now minus uptime). */
|
|
22
|
+
function defaultBootTimeMs() {
|
|
23
|
+
return Date.now() - uptime() * 1000;
|
|
24
|
+
}
|
|
25
|
+
export function resolveRegistryPath() {
|
|
26
|
+
return join(dirname(resolveConfigPath()), "registry.json");
|
|
27
|
+
}
|
|
28
|
+
export function loadRegistry(path = resolveRegistryPath()) {
|
|
29
|
+
try {
|
|
30
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
31
|
+
const entries = parsed?.entries;
|
|
32
|
+
if (!Array.isArray(entries))
|
|
33
|
+
return [];
|
|
34
|
+
return entries.filter(isRegistryEntry);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// missing or corrupt file -> empty registry (it is rebuilt by enrolment)
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function isRegistryEntry(raw) {
|
|
42
|
+
if (!raw || typeof raw !== "object")
|
|
43
|
+
return false;
|
|
44
|
+
const e = raw;
|
|
45
|
+
return (typeof e.id === "string" &&
|
|
46
|
+
(e.tool === "claude" || e.tool === "codex" || e.tool === "agy") &&
|
|
47
|
+
(e.kind === "local-tmux" || e.kind === "local" || e.kind === "remote") &&
|
|
48
|
+
typeof e.cwd === "string" &&
|
|
49
|
+
typeof e.enrolledAt === "string" &&
|
|
50
|
+
typeof e.lastSeenAt === "string" &&
|
|
51
|
+
(e.source === "run" ||
|
|
52
|
+
e.source === "hook" ||
|
|
53
|
+
e.source === "scan" ||
|
|
54
|
+
e.source === "remote"));
|
|
55
|
+
}
|
|
56
|
+
/** Atomic write: tmp file in the same dir, then rename. */
|
|
57
|
+
function saveRegistry(entries, path) {
|
|
58
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
59
|
+
const tmp = `${path}.tmp.${process.pid}`;
|
|
60
|
+
writeFileSync(tmp, JSON.stringify({ version: 1, entries }, null, 2), "utf8");
|
|
61
|
+
renameSync(tmp, path);
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Cross-process lock for load-modify-save mutations (S2/S3 fix).
|
|
65
|
+
//
|
|
66
|
+
// The registry is read-modified-written by CONCURRENT processes — `delegate`,
|
|
67
|
+
// the conductor, and the claude SessionEnd hook can all mutate it at once.
|
|
68
|
+
// Without a lock, two writers each load the same snapshot, modify a disjoint
|
|
69
|
+
// entry, and the last `saveRegistry` wins → the other's enroll/advance is LOST.
|
|
70
|
+
// The same race makes the concurrency cap leaky: `delegate` checks
|
|
71
|
+
// `hasFreeSlot` then enrolls-as-running in two steps, so N delegations racing
|
|
72
|
+
// can all see a free slot and overshoot the cap.
|
|
73
|
+
//
|
|
74
|
+
// The registry is LOCAL ONLY (the CLI writes it; pods never touch it — they have
|
|
75
|
+
// no access to ~/.config/.../registry.json), so a LOCAL file lock is sufficient
|
|
76
|
+
// — there is no cross-host writer to coordinate with. We use an exclusive
|
|
77
|
+
// lockfile (`<path>.lock`, O_CREAT|O_EXCL) with a bounded spin and stale-lock
|
|
78
|
+
// takeover, NOT a real OS flock(2): exclusive-create on the SAME local fs is the
|
|
79
|
+
// portable primitive here (Node has no flock), and a crashed holder is recovered
|
|
80
|
+
// by the staleness break below.
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
/** Spin parameters for the lockfile (bounded — a deadlock must never hang a hook). */
|
|
83
|
+
const LOCK_STALE_MS = 10_000; // a lockfile older than this is assumed orphaned
|
|
84
|
+
const LOCK_SPIN_MS = 5; // busy-wait granularity between acquire attempts
|
|
85
|
+
const LOCK_MAX_WAIT_MS = 4_000; // give up waiting after this (then proceed best-effort)
|
|
86
|
+
function lockPath(path) {
|
|
87
|
+
return `${path}.lock`;
|
|
88
|
+
}
|
|
89
|
+
/** Busy-wait `ms` without a timer (we are holding a process-wide critical section). */
|
|
90
|
+
function spinSleep(ms) {
|
|
91
|
+
const end = Date.now() + ms;
|
|
92
|
+
while (Date.now() < end) {
|
|
93
|
+
// tight spin — ms is tiny (LOCK_SPIN_MS); a registry mutation is sub-ms.
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Acquire the registry lockfile (exclusive create). Returns the fd on success,
|
|
98
|
+
* or undefined if it could not be acquired within LOCK_MAX_WAIT_MS (the caller
|
|
99
|
+
* then proceeds best-effort — a slow lock must NEVER take down a claude hook).
|
|
100
|
+
* Breaks a STALE lock (holder crashed) by age.
|
|
101
|
+
*/
|
|
102
|
+
function acquireLock(path) {
|
|
103
|
+
const lp = lockPath(path);
|
|
104
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
105
|
+
const deadline = Date.now() + LOCK_MAX_WAIT_MS;
|
|
106
|
+
for (;;) {
|
|
107
|
+
try {
|
|
108
|
+
const fd = openSync(lp, "wx"); // O_CREAT|O_EXCL|O_WRONLY
|
|
109
|
+
return fd;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Held — break it if it is stale (a crashed holder left it behind).
|
|
113
|
+
try {
|
|
114
|
+
const age = Date.now() - statSync(lp).mtimeMs;
|
|
115
|
+
if (age > LOCK_STALE_MS) {
|
|
116
|
+
rmSync(lp, { force: true });
|
|
117
|
+
continue; // retry the exclusive create immediately
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
// raced with the holder releasing it → just retry the create
|
|
122
|
+
}
|
|
123
|
+
if (Date.now() >= deadline)
|
|
124
|
+
return undefined; // give up, proceed best-effort
|
|
125
|
+
spinSleep(LOCK_SPIN_MS);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function releaseLock(fd, path) {
|
|
130
|
+
try {
|
|
131
|
+
closeSync(fd);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// already closed
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
rmSync(lockPath(path), { force: true });
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// already gone
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Run `fn` under the registry lock: load the current entries, let `fn` mutate
|
|
145
|
+
* them (and compute a return value), then persist atomically — all inside ONE
|
|
146
|
+
* critical section, so concurrent processes serialize and no enroll/advance is
|
|
147
|
+
* lost. `fn` returns `{ entries, result, save? }`: `entries` is what to save
|
|
148
|
+
* (return the same array you mutated), `result` is passed back to the caller, and
|
|
149
|
+
* `save:false` skips the write entirely (a read-only no-op must not rewrite — nor
|
|
150
|
+
* create — the file). If the lock can't be taken (a crashed holder, contention
|
|
151
|
+
* storm), we proceed WITHOUT it rather than block a hook — best-effort,
|
|
152
|
+
* last-writer-wins as before. Exported for tests.
|
|
153
|
+
*/
|
|
154
|
+
export function withRegistryLock(path, fn) {
|
|
155
|
+
const fd = acquireLock(path);
|
|
156
|
+
try {
|
|
157
|
+
const { entries, result, save } = fn(loadRegistry(path));
|
|
158
|
+
if (save !== false)
|
|
159
|
+
saveRegistry(entries, path);
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
if (fd !== undefined)
|
|
164
|
+
releaseLock(fd, path);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Upsert by id. A re-enroll refreshes lastSeenAt, merges the new fields over
|
|
169
|
+
* the stored ones, and REVIVES an ended entry (endedAt is dropped) — e.g. a
|
|
170
|
+
* claude SessionStart on a resumed conversation.
|
|
171
|
+
*/
|
|
172
|
+
export function enroll(input, path = resolveRegistryPath()) {
|
|
173
|
+
return withRegistryLock(path, (entries) => {
|
|
174
|
+
const entry = applyEnroll(entries, input);
|
|
175
|
+
return { entries, result: entry };
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Upsert `input` into `entries` IN PLACE and return the resulting entry. Pure
|
|
180
|
+
* over the array (no fs); shared by `enroll` (under the lock) and the atomic
|
|
181
|
+
* check-cap-and-enroll helper. The lock is held by the caller.
|
|
182
|
+
*/
|
|
183
|
+
function applyEnroll(entries, input) {
|
|
184
|
+
const now = new Date().toISOString();
|
|
185
|
+
const idx = entries.findIndex((e) => e.id === input.id);
|
|
186
|
+
const prev = idx >= 0 ? entries[idx] : undefined;
|
|
187
|
+
const entry = {
|
|
188
|
+
id: input.id,
|
|
189
|
+
tool: input.tool,
|
|
190
|
+
kind: input.kind,
|
|
191
|
+
cwd: input.cwd,
|
|
192
|
+
source: input.source,
|
|
193
|
+
enrolledAt: prev?.enrolledAt ?? now,
|
|
194
|
+
lastSeenAt: now,
|
|
195
|
+
};
|
|
196
|
+
const label = input.label ?? prev?.label;
|
|
197
|
+
if (label !== undefined)
|
|
198
|
+
entry.label = label;
|
|
199
|
+
const convId = input.convId ?? prev?.convId;
|
|
200
|
+
if (convId !== undefined)
|
|
201
|
+
entry.convId = convId;
|
|
202
|
+
const remoteId = input.remoteId ?? prev?.remoteId;
|
|
203
|
+
if (remoteId !== undefined)
|
|
204
|
+
entry.remoteId = remoteId;
|
|
205
|
+
const tmuxSession = input.tmuxSession ?? prev?.tmuxSession;
|
|
206
|
+
if (tmuxSession !== undefined)
|
|
207
|
+
entry.tmuxSession = tmuxSession;
|
|
208
|
+
const pid = input.pid ?? prev?.pid;
|
|
209
|
+
if (pid !== undefined)
|
|
210
|
+
entry.pid = pid;
|
|
211
|
+
const role = input.role ?? prev?.role;
|
|
212
|
+
if (role !== undefined)
|
|
213
|
+
entry.role = role;
|
|
214
|
+
const jobState = input.jobState ?? prev?.jobState;
|
|
215
|
+
if (jobState !== undefined)
|
|
216
|
+
entry.jobState = jobState;
|
|
217
|
+
const parent = input.parent ?? prev?.parent;
|
|
218
|
+
if (parent !== undefined)
|
|
219
|
+
entry.parent = parent;
|
|
220
|
+
const task = input.task ?? prev?.task;
|
|
221
|
+
if (task !== undefined)
|
|
222
|
+
entry.task = task;
|
|
223
|
+
const callbackTo = input.callbackTo ?? prev?.callbackTo;
|
|
224
|
+
if (callbackTo !== undefined)
|
|
225
|
+
entry.callbackTo = callbackTo;
|
|
226
|
+
const remoteTarget = input.remoteTarget ?? prev?.remoteTarget;
|
|
227
|
+
if (remoteTarget !== undefined)
|
|
228
|
+
entry.remoteTarget = remoteTarget;
|
|
229
|
+
const headless = input.headless ?? prev?.headless;
|
|
230
|
+
if (headless !== undefined)
|
|
231
|
+
entry.headless = headless;
|
|
232
|
+
const originCwd = input.originCwd ?? prev?.originCwd;
|
|
233
|
+
if (originCwd !== undefined)
|
|
234
|
+
entry.originCwd = originCwd;
|
|
235
|
+
const explicitCwd = input.explicitCwd ?? prev?.explicitCwd;
|
|
236
|
+
if (explicitCwd !== undefined)
|
|
237
|
+
entry.explicitCwd = explicitCwd;
|
|
238
|
+
const depthBudget = input.depthBudget ?? prev?.depthBudget;
|
|
239
|
+
if (depthBudget !== undefined)
|
|
240
|
+
entry.depthBudget = depthBudget;
|
|
241
|
+
const trackWp = input.trackWp ?? prev?.trackWp;
|
|
242
|
+
if (trackWp !== undefined)
|
|
243
|
+
entry.trackWp = trackWp;
|
|
244
|
+
const throttle = input.throttle ?? prev?.throttle;
|
|
245
|
+
if (throttle !== undefined)
|
|
246
|
+
entry.throttle = throttle;
|
|
247
|
+
const model = input.model ?? prev?.model;
|
|
248
|
+
if (model !== undefined)
|
|
249
|
+
entry.model = model;
|
|
250
|
+
const effort = input.effort ?? prev?.effort;
|
|
251
|
+
if (effort !== undefined)
|
|
252
|
+
entry.effort = effort;
|
|
253
|
+
const gatewayMode = input.gatewayMode ?? prev?.gatewayMode;
|
|
254
|
+
if (gatewayMode !== undefined)
|
|
255
|
+
entry.gatewayMode = gatewayMode;
|
|
256
|
+
if (idx >= 0)
|
|
257
|
+
entries[idx] = entry;
|
|
258
|
+
else
|
|
259
|
+
entries.push(entry);
|
|
260
|
+
return entry;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* ATOMIC "is there a free slot? → enroll-as-running" (S3 fix). The cap check and
|
|
264
|
+
* the running-enroll happen in ONE locked critical section, so two concurrent
|
|
265
|
+
* `delegate`s can never both see the same free slot and overshoot the cap.
|
|
266
|
+
* `running` counts CURRENT `running` jobs (`role:"job"`); when `running < cap`
|
|
267
|
+
* the `input` is upserted with `jobState:"running"` and the returned entry is
|
|
268
|
+
* non-undefined. When the cap is full, NOTHING is written and `undefined` is
|
|
269
|
+
* returned (the caller enqueues a `pending` entry instead). Exported for tests.
|
|
270
|
+
*/
|
|
271
|
+
export function tryClaimSlot(input, cap, path = resolveRegistryPath()) {
|
|
272
|
+
return withRegistryLock(path, (entries) => {
|
|
273
|
+
if (cap <= 0)
|
|
274
|
+
return { entries, result: undefined, save: false };
|
|
275
|
+
// A `throttled` job KEEPS its slot (the rate-limit is account-wide; admitting
|
|
276
|
+
// a replacement just burns the same quota), so it counts toward the cap too.
|
|
277
|
+
const running = entries.filter((e) => e.role === "job" && occupiesSlot(e.jobState ?? "pending")).length;
|
|
278
|
+
// The job being claimed may already exist as `pending` (delegate enrolled it
|
|
279
|
+
// first); don't double-count it against itself.
|
|
280
|
+
const self = entries.find((e) => e.id === input.id);
|
|
281
|
+
const selfRunning = self?.role === "job" && occupiesSlot(self.jobState ?? "pending") ? 1 : 0;
|
|
282
|
+
if (running - selfRunning >= cap) {
|
|
283
|
+
return { entries, result: undefined, save: false };
|
|
284
|
+
}
|
|
285
|
+
const entry = applyEnroll(entries, { ...input, jobState: "running" });
|
|
286
|
+
return { entries, result: entry };
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* The legal job lifecycle transitions (P1 keeps it linear; P4 adds the queue's
|
|
291
|
+
* pending→running). A transition not listed here is rejected by `advanceJob`.
|
|
292
|
+
* Pure, exported for tests.
|
|
293
|
+
*/
|
|
294
|
+
const JOB_TRANSITIONS = {
|
|
295
|
+
pending: ["running", "failed"],
|
|
296
|
+
// A HEADLESS LOCAL job that finished on a transient rate-limit goes
|
|
297
|
+
// running→throttled (reliability slice 1); it is NOT terminal.
|
|
298
|
+
running: ["throttled", "done", "failed"],
|
|
299
|
+
// The conductor resumes a throttled job (→running) on its backoff schedule, or
|
|
300
|
+
// gives up after the attempt cap (→failed). A reconcile that sees fresh success
|
|
301
|
+
// before the resumed run is re-observed may also settle it →done directly.
|
|
302
|
+
throttled: ["running", "done", "failed"],
|
|
303
|
+
done: [],
|
|
304
|
+
failed: [],
|
|
305
|
+
};
|
|
306
|
+
export function canTransitionJob(from, to) {
|
|
307
|
+
return JOB_TRANSITIONS[from].includes(to);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Does a job in `state` OCCUPY a concurrency slot? `running` does, and so does
|
|
311
|
+
* `throttled` — a throttled job is mid-flight (it KEEPS its slot rather than
|
|
312
|
+
* letting the conductor admit a replacement that would immediately throttle on
|
|
313
|
+
* the same account-wide limit). `pending`/`done`/`failed` do not. Pure, exported
|
|
314
|
+
* for the cap/admission logic in delegate.ts and its tests.
|
|
315
|
+
*/
|
|
316
|
+
export function occupiesSlot(state) {
|
|
317
|
+
return state === "running" || state === "throttled";
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Move a job to `to`, persisting the new state (and stamping endedAt for the
|
|
321
|
+
* terminal states). Returns the updated entry, or undefined when the id is
|
|
322
|
+
* unknown / not a job / the transition is illegal. Reuses the atomic write.
|
|
323
|
+
*/
|
|
324
|
+
export function advanceJob(id, to, path = resolveRegistryPath()) {
|
|
325
|
+
return withRegistryLock(path, (entries) => {
|
|
326
|
+
const entry = entries.find((e) => e.id === id);
|
|
327
|
+
if (!entry || entry.role !== "job") {
|
|
328
|
+
return { entries, result: undefined, save: false };
|
|
329
|
+
}
|
|
330
|
+
const from = entry.jobState ?? "pending";
|
|
331
|
+
if (from !== to && !canTransitionJob(from, to)) {
|
|
332
|
+
return { entries, result: undefined, save: false };
|
|
333
|
+
}
|
|
334
|
+
entry.jobState = to;
|
|
335
|
+
entry.lastSeenAt = new Date().toISOString();
|
|
336
|
+
if (to === "done" || to === "failed") {
|
|
337
|
+
entry.endedAt = entry.endedAt ?? entry.lastSeenAt;
|
|
338
|
+
}
|
|
339
|
+
return { entries, result: entry };
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
/** Live job entries (role "job"), liveness reconciled like any other entry. */
|
|
343
|
+
export function listJobs(opts = {}) {
|
|
344
|
+
const path = opts.path ?? resolveRegistryPath();
|
|
345
|
+
return loadRegistry(path).filter((e) => e.role === "job");
|
|
346
|
+
}
|
|
347
|
+
/** Refresh lastSeenAt. Returns false when the id is unknown. */
|
|
348
|
+
export function touchEntry(id, path = resolveRegistryPath()) {
|
|
349
|
+
return withRegistryLock(path, (entries) => {
|
|
350
|
+
const entry = entries.find((e) => e.id === id);
|
|
351
|
+
if (!entry)
|
|
352
|
+
return { entries, result: false, save: false };
|
|
353
|
+
entry.lastSeenAt = new Date().toISOString();
|
|
354
|
+
return { entries, result: true };
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
/** Record the session's end. Returns false when the id is unknown. */
|
|
358
|
+
export function markEnded(id, path = resolveRegistryPath()) {
|
|
359
|
+
return withRegistryLock(path, (entries) => {
|
|
360
|
+
const entry = entries.find((e) => e.id === id);
|
|
361
|
+
if (!entry)
|
|
362
|
+
return { entries, result: false, save: false };
|
|
363
|
+
const now = new Date().toISOString();
|
|
364
|
+
entry.endedAt = now;
|
|
365
|
+
entry.lastSeenAt = now;
|
|
366
|
+
return { entries, result: true };
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
function defaultTmuxHasSession(name) {
|
|
370
|
+
try {
|
|
371
|
+
// "=" prefix forces an exact session-name match (no prefix matching).
|
|
372
|
+
return (spawnSync("tmux", ["has-session", "-t", `=${name}`], {
|
|
373
|
+
stdio: "ignore",
|
|
374
|
+
}).status === 0);
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function defaultPidAlive(pid) {
|
|
381
|
+
try {
|
|
382
|
+
process.kill(pid, 0);
|
|
383
|
+
return true;
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* The cmdline of a live pid (NUL-separated args joined with spaces), or
|
|
391
|
+
* undefined when it can't be read. Used to detect PID REUSE: after a crash the
|
|
392
|
+
* CLI's pid may be reassigned to an unrelated process, which `kill(pid,0)`
|
|
393
|
+
* still reports as alive. /proc is Linux-only; elsewhere this returns undefined
|
|
394
|
+
* and the caller stays conservative (treats the pid as still ours).
|
|
395
|
+
*/
|
|
396
|
+
function defaultProcessCmdline(pid) {
|
|
397
|
+
try {
|
|
398
|
+
return readFileSync(`/proc/${pid}/cmdline`, "utf8")
|
|
399
|
+
.replace(/\0/g, " ")
|
|
400
|
+
.trim();
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
return undefined;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Does the process at `pid` look like the `tool` CLI? Reads its cmdline and
|
|
408
|
+
* checks for the tool name. CONSERVATIVE on doubt: if the cmdline can't be read
|
|
409
|
+
* (non-Linux, permissions) we return true (assume it is still ours) so the
|
|
410
|
+
* single-writer guard never DROPS a real writer (which would risk two CLIs
|
|
411
|
+
* corrupting one .jsonl). Only a readable cmdline that clearly isn't the tool
|
|
412
|
+
* (a reused pid) returns false.
|
|
413
|
+
*/
|
|
414
|
+
function processIsTool(pid, tool, read) {
|
|
415
|
+
const cmd = read(pid);
|
|
416
|
+
if (cmd === undefined)
|
|
417
|
+
return true; // can't tell → assume still ours
|
|
418
|
+
return cmd.includes(tool);
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Liveness:
|
|
422
|
+
* - local-tmux -> the tmux session exists,
|
|
423
|
+
* - local -> pid alive (when recorded) AND not endedAt; without a pid
|
|
424
|
+
* (hook-enrolled: the hook's parent pid is a throwaway shell)
|
|
425
|
+
* we trust SessionEnd + prune,
|
|
426
|
+
* - remote -> always "live" here; the CALLER reconciles against
|
|
427
|
+
* listRemoteSessions (the registry cannot probe the cluster).
|
|
428
|
+
*/
|
|
429
|
+
export function isLive(e, opts = {}) {
|
|
430
|
+
if (e.endedAt)
|
|
431
|
+
return false;
|
|
432
|
+
if (e.kind === "local-tmux") {
|
|
433
|
+
const has = opts.tmuxHasSession ?? defaultTmuxHasSession;
|
|
434
|
+
return has(e.tmuxSession ?? `remote-${e.id}`);
|
|
435
|
+
}
|
|
436
|
+
if (e.kind === "local") {
|
|
437
|
+
// A process cannot survive a reboot: an entry last seen BEFORE the machine
|
|
438
|
+
// booted is dead, whether or not it carries a pid.
|
|
439
|
+
const bootMs = opts.bootTimeMs ?? defaultBootTimeMs();
|
|
440
|
+
if (Date.parse(e.lastSeenAt) < bootMs)
|
|
441
|
+
return false;
|
|
442
|
+
// No pid (the claude SessionStart hook can't reliably capture claude's pid):
|
|
443
|
+
// unverifiable. Treat as live here, but convOwners demotes a no-pid local
|
|
444
|
+
// entry to a SUSPECT (warn), not a hard block — so a stale hook entry left
|
|
445
|
+
// by a crash never refuses a relaunch.
|
|
446
|
+
if (e.pid === undefined)
|
|
447
|
+
return true;
|
|
448
|
+
if (!(opts.pidAlive ?? defaultPidAlive)(e.pid))
|
|
449
|
+
return false;
|
|
450
|
+
// pid alive — but is it STILL our CLI? After a crash the dead CLI's pid can
|
|
451
|
+
// be reassigned to an unrelated process that kill(pid,0) reports as alive;
|
|
452
|
+
// verify the process identity to avoid a false live-writer.
|
|
453
|
+
return processIsTool(e.pid, e.tool, opts.processCmdline ?? defaultProcessCmdline);
|
|
454
|
+
}
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
/** Entries considered live right now (see isLive for the per-kind rules). */
|
|
458
|
+
export function listLive(opts = {}) {
|
|
459
|
+
const path = opts.path ?? resolveRegistryPath();
|
|
460
|
+
return loadRegistry(path).filter((e) => isLive(e, opts));
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Drop DEAD entries whose last activity (endedAt, else lastSeenAt) is older
|
|
464
|
+
* than maxAgeHours. Live entries always stay; recently-dead ones stay too so
|
|
465
|
+
* `restore` can still resume them after a reboot via the scan fallback.
|
|
466
|
+
* Returns the number of removed entries.
|
|
467
|
+
*/
|
|
468
|
+
export function prune(maxAgeHours, opts = {}) {
|
|
469
|
+
const path = opts.path ?? resolveRegistryPath();
|
|
470
|
+
const cutoff = Date.now() - maxAgeHours * 3600 * 1000;
|
|
471
|
+
return withRegistryLock(path, (entries) => {
|
|
472
|
+
const kept = entries.filter((e) => {
|
|
473
|
+
if (isLive(e, opts))
|
|
474
|
+
return true;
|
|
475
|
+
const last = Date.parse(e.endedAt ?? e.lastSeenAt);
|
|
476
|
+
return Number.isFinite(last) && last >= cutoff;
|
|
477
|
+
});
|
|
478
|
+
if (kept.length === entries.length)
|
|
479
|
+
return { entries, result: 0, save: false };
|
|
480
|
+
return { entries: kept, result: entries.length - kept.length };
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
/** Map a CLI profile name to a registry tool (undefined for shell/opencode/…). */
|
|
484
|
+
export function coerceRegistryTool(profile) {
|
|
485
|
+
switch (profile) {
|
|
486
|
+
case "claude":
|
|
487
|
+
case "claude-code":
|
|
488
|
+
return "claude";
|
|
489
|
+
case "codex":
|
|
490
|
+
return "codex";
|
|
491
|
+
case "agy":
|
|
492
|
+
case "antigravity":
|
|
493
|
+
return "agy";
|
|
494
|
+
default:
|
|
495
|
+
return undefined;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Auto-enrolment after `remote run` started a local tmux session. Best-effort
|
|
500
|
+
* plumbing: never throws (a registry hiccup must not break the run).
|
|
501
|
+
*/
|
|
502
|
+
export function enrollFromRun(args) {
|
|
503
|
+
const tool = coerceRegistryTool(args.profile);
|
|
504
|
+
if (!tool)
|
|
505
|
+
return; // shell/opencode/… sessions stay tmux-only
|
|
506
|
+
try {
|
|
507
|
+
enroll({
|
|
508
|
+
id: args.slug,
|
|
509
|
+
tool,
|
|
510
|
+
kind: "local-tmux",
|
|
511
|
+
cwd: args.cwd,
|
|
512
|
+
source: "run",
|
|
513
|
+
label: args.slug,
|
|
514
|
+
tmuxSession: args.tmuxSession,
|
|
515
|
+
...(args.convId !== undefined ? { convId: args.convId } : {}),
|
|
516
|
+
...(args.gatewayMode !== undefined ? { gatewayMode: args.gatewayMode } : {}),
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
catch {
|
|
520
|
+
// best-effort: the tmux session is up regardless
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* LOCAL rows for `remote ls`: live tmux sessions joined with the registry
|
|
525
|
+
* ([registry] vs [guess] badge), plus live registry-only sessions (e.g. a
|
|
526
|
+
* hook-enrolled claude running in a plain terminal). Dead registry entries are
|
|
527
|
+
* pruned on the way (layout maxAgeHours).
|
|
528
|
+
*/
|
|
529
|
+
export function listLocalForLs(opts = {}) {
|
|
530
|
+
const path = opts.path ?? resolveRegistryPath();
|
|
531
|
+
try {
|
|
532
|
+
prune(getLayoutConfig().maxAgeHours, { ...opts, path });
|
|
533
|
+
}
|
|
534
|
+
catch {
|
|
535
|
+
// a config/registry hiccup must not break `remote ls`
|
|
536
|
+
}
|
|
537
|
+
const live = listLive({ ...opts, path });
|
|
538
|
+
const rows = [];
|
|
539
|
+
const matched = new Set();
|
|
540
|
+
for (const s of listLocalSessions()) {
|
|
541
|
+
const entry = live.find((e) => e.tmuxSession === s.name || e.id === s.slug);
|
|
542
|
+
if (entry)
|
|
543
|
+
matched.add(entry.id);
|
|
544
|
+
rows.push({
|
|
545
|
+
slug: s.slug,
|
|
546
|
+
profile: s.profile,
|
|
547
|
+
state: s.attached ? "attached" : "detached",
|
|
548
|
+
path: s.path,
|
|
549
|
+
badge: entry ? "registry" : "guess",
|
|
550
|
+
...(s.displayName !== undefined ? { displayName: s.displayName } : {}),
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
// Only surface local-tmux entries that were NOT matched above — these are
|
|
554
|
+
// orphaned registry records for tmux sessions remote itself created.
|
|
555
|
+
// kind:"local" entries are Claude Code conversation sessions (UUID ids,
|
|
556
|
+
// no tmuxSession) — they are internal CC state, not user-facing sessions.
|
|
557
|
+
for (const e of live) {
|
|
558
|
+
if (e.kind !== "local-tmux" || matched.has(e.id))
|
|
559
|
+
continue;
|
|
560
|
+
rows.push({
|
|
561
|
+
slug: e.label ?? e.id.slice(0, 12),
|
|
562
|
+
profile: e.tool,
|
|
563
|
+
state: "live",
|
|
564
|
+
path: e.cwd,
|
|
565
|
+
badge: "registry",
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
return rows;
|
|
569
|
+
}
|
|
570
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `remote relaunch` — bring back local tmux sessions whose CLI has dropped to a
|
|
3
|
+
* shell (in situ, keeping the windows), each resuming ITS OWN conversation.
|
|
4
|
+
*
|
|
5
|
+
* Why a dedicated command: closing the terminal windows does NOT kill the tmux
|
|
6
|
+
* sessions, and `remote restore` goes through `remote run -r`, which the
|
|
7
|
+
* single-writer guard refuses while the (idle) session still holds the
|
|
8
|
+
* conversation. This relaunches the CLI inside the existing session — no
|
|
9
|
+
* `remote run`, no guard fight — and crucially resumes each session's OWN
|
|
10
|
+
* convId (from the registry), never "most recent", so the N sessions that share
|
|
11
|
+
* a cwd never collide on one .jsonl.
|
|
12
|
+
*/
|
|
13
|
+
/** The shell command that resumes `convId` for `profile`, or undefined if the */
|
|
14
|
+
/** profile has no resume form (e.g. shell). */
|
|
15
|
+
export declare function resumeCommandFor(profile: string, convId: string): string | undefined;
|
|
16
|
+
export type RelaunchCandidate = {
|
|
17
|
+
/** short name, e.g. `sentropic#2` */
|
|
18
|
+
slug: string;
|
|
19
|
+
/** full tmux session name, e.g. `remote-sentropic#2` */
|
|
20
|
+
name: string;
|
|
21
|
+
profile: string;
|
|
22
|
+
/** true when the pane is an idle shell (CLI gone) — only these are relaunched */
|
|
23
|
+
idle: boolean;
|
|
24
|
+
/** this session's own conversation id, from the registry */
|
|
25
|
+
convId?: string;
|
|
26
|
+
};
|
|
27
|
+
export type RelaunchAction = {
|
|
28
|
+
slug: string;
|
|
29
|
+
name: string;
|
|
30
|
+
profile: string;
|
|
31
|
+
convId: string;
|
|
32
|
+
/** the command to run in the session (e.g. `claude --resume <id>`) */
|
|
33
|
+
cmd: string;
|
|
34
|
+
};
|
|
35
|
+
export type RelaunchSkip = {
|
|
36
|
+
slug: string;
|
|
37
|
+
reason: string;
|
|
38
|
+
};
|
|
39
|
+
export type RelaunchPlan = {
|
|
40
|
+
actions: RelaunchAction[];
|
|
41
|
+
skipped: RelaunchSkip[];
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Decide what to relaunch. Pure: takes fully-resolved candidates (idle flag +
|
|
45
|
+
* convId already gathered) so it is unit-testable without tmux/registry I/O.
|
|
46
|
+
* Skips running sessions (never disturb a live CLI), sessions with no known
|
|
47
|
+
* convId (relaunch by hand rather than guess and risk a collision), and
|
|
48
|
+
* profiles with no resume form. Also refuses to point two sessions at the SAME
|
|
49
|
+
* convId (defensive: the registry should already be 1:1).
|
|
50
|
+
*/
|
|
51
|
+
export declare function planRelaunch(candidates: ReadonlyArray<RelaunchCandidate>): RelaunchPlan;
|
|
52
|
+
//# sourceMappingURL=relaunch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relaunch.d.ts","sourceRoot":"","sources":["../src/relaunch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,iFAAiF;AACjF,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,SAAS,CAMpB;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,EAAE,OAAO,CAAC;IACd,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAC3C,YAAY,CA0Cd"}
|