@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
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* h2a bridge (`remote h2a bridge`): connect the LOCAL h2a agent network — a
|
|
3
|
+
* file store under ~/h2a-workspace/.h2a where agents exchange JSON envelopes
|
|
4
|
+
* by dropping them into inbox/<instance-dir>/ — with a remote session Pod, so
|
|
5
|
+
* the Pod's agent is reachable/wakeable from the local bus and vice versa.
|
|
6
|
+
*
|
|
7
|
+
* Everything rides `kubectl exec` against the configured tunnel (same pattern
|
|
8
|
+
* as soft-refresh/sync), base64 on the wire — encoded exactly ONCE per
|
|
9
|
+
* direction, never double-encoded. Two flows per pass:
|
|
10
|
+
*
|
|
11
|
+
* PULL Pod → local: envelopes the Pod's agent EMITTED toward non-Pod
|
|
12
|
+
* instances (every Pod inbox/<dir>/ except the Pod's own instances')
|
|
13
|
+
* land in the same-named local inbox dir.
|
|
14
|
+
* PUSH local → Pod: envelopes locally addressed TO the Pod's instances
|
|
15
|
+
* (local inbox/<pod-instance-dir>/) land in the Pod's inbox.
|
|
16
|
+
*
|
|
17
|
+
* Idempotent by FILE NAME: a file that already exists on the destination is
|
|
18
|
+
* skipped — never overwritten. The bridge NEVER deletes anything on either
|
|
19
|
+
* side: acks/cleanup belong to h2a itself, the bridge is transport only.
|
|
20
|
+
*
|
|
21
|
+
* The Pod's instances are the union of a default mapping
|
|
22
|
+
* `<tool>:remote:<sessionId>` (tool from the session profile) and whatever is
|
|
23
|
+
* registered in the Pod's own registry/instances.jsonl. Instance ids map to
|
|
24
|
+
* inbox dir names by encoding ":" as "__" (h2a convention, e.g.
|
|
25
|
+
* `claude:remote:abc123` → `claude__remote__abc123`).
|
|
26
|
+
*
|
|
27
|
+
* A Pod without ~/h2a-workspace/.h2a gets the skeleton (inbox/) plus a
|
|
28
|
+
* README.md documenting the envelope-drop convention, so agents in the Pod
|
|
29
|
+
* can participate by writing plain JSON files — no h2a binary required.
|
|
30
|
+
*/
|
|
31
|
+
import { spawnSync } from "node:child_process";
|
|
32
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, } from "node:fs";
|
|
33
|
+
import { homedir } from "node:os";
|
|
34
|
+
import { join } from "node:path";
|
|
35
|
+
import { getTunnel } from "./config.js";
|
|
36
|
+
/** h2a store root in the Pod, relative to $HOME (used as "$HOME/<this>"). */
|
|
37
|
+
export const H2A_POD_ROOT = "h2a-workspace/.h2a";
|
|
38
|
+
/** Local h2a store root (the agent network's shared filesystem). */
|
|
39
|
+
export function defaultLocalH2aRoot() {
|
|
40
|
+
return join(homedir(), "h2a-workspace", ".h2a");
|
|
41
|
+
}
|
|
42
|
+
/** Inbox dir name for an instance id — h2a encodes ":" as "__" on disk. */
|
|
43
|
+
export function instanceInboxDir(instance) {
|
|
44
|
+
return instance.replace(/:/g, "__");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Tool segment of the default Pod instance, from the session profile (same
|
|
48
|
+
* mapping as the local registry's coerceRegistryTool; unknown profiles keep
|
|
49
|
+
* their own name so the dir stays predictable).
|
|
50
|
+
*/
|
|
51
|
+
function profileTool(profile) {
|
|
52
|
+
switch (profile) {
|
|
53
|
+
case "claude":
|
|
54
|
+
case "claude-code":
|
|
55
|
+
return "claude";
|
|
56
|
+
case "codex":
|
|
57
|
+
return "codex";
|
|
58
|
+
case "agy":
|
|
59
|
+
case "antigravity":
|
|
60
|
+
return "agy";
|
|
61
|
+
case "gemini":
|
|
62
|
+
case "mistral":
|
|
63
|
+
return profile;
|
|
64
|
+
default:
|
|
65
|
+
return profile && profile.length > 0 ? profile : "claude";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Default h2a instance id for a session Pod's agent: <tool>:remote:<sessionId>. */
|
|
69
|
+
export function defaultPodInstance(sessionId, profile) {
|
|
70
|
+
return `${profileTool(profile)}:remote:${sessionId}`;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Names embedded in kubectl-exec scripts are restricted to this shape (the
|
|
74
|
+
* observed h2a convention: `claude__track__abc/env__...json`). Anything else
|
|
75
|
+
* — path tricks, quotes, whitespace — is IGNORED, never executed.
|
|
76
|
+
*/
|
|
77
|
+
const SAFE_ENTRY = /^[A-Za-z0-9][A-Za-z0-9._-]*\/[A-Za-z0-9][A-Za-z0-9._-]*\.json$/;
|
|
78
|
+
/**
|
|
79
|
+
* Pure sync plan: given the two inbox listings ("dir/file" entries) and the
|
|
80
|
+
* set of inbox dirs owned by the Pod's instances, decide what moves where.
|
|
81
|
+
* No deletion exists in the model — the plan can only copy or skip.
|
|
82
|
+
*/
|
|
83
|
+
export function planBridge(args) {
|
|
84
|
+
const { podInstanceDirs } = args;
|
|
85
|
+
const split = (entry) => {
|
|
86
|
+
const slash = entry.indexOf("/");
|
|
87
|
+
return { dir: entry.slice(0, slash), file: entry.slice(slash + 1) };
|
|
88
|
+
};
|
|
89
|
+
let skipped = 0;
|
|
90
|
+
let ignored = 0;
|
|
91
|
+
const podSet = new Set();
|
|
92
|
+
const pull = [];
|
|
93
|
+
const push = [];
|
|
94
|
+
for (const entry of args.podFiles) {
|
|
95
|
+
if (!SAFE_ENTRY.test(entry)) {
|
|
96
|
+
ignored += 1;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
podSet.add(entry);
|
|
100
|
+
}
|
|
101
|
+
const localSet = new Set();
|
|
102
|
+
for (const entry of args.localFiles) {
|
|
103
|
+
if (!SAFE_ENTRY.test(entry)) {
|
|
104
|
+
ignored += 1;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
localSet.add(entry);
|
|
108
|
+
}
|
|
109
|
+
// PULL: Pod inbox dirs that are NOT the Pod's own — outbound envelopes.
|
|
110
|
+
for (const entry of podSet) {
|
|
111
|
+
const f = split(entry);
|
|
112
|
+
if (podInstanceDirs.has(f.dir))
|
|
113
|
+
continue; // the Pod's own inbox: inbound, not pulled
|
|
114
|
+
if (localSet.has(entry))
|
|
115
|
+
skipped += 1;
|
|
116
|
+
else
|
|
117
|
+
pull.push(f);
|
|
118
|
+
}
|
|
119
|
+
// PUSH: local envelopes addressed to the Pod's instances.
|
|
120
|
+
for (const entry of localSet) {
|
|
121
|
+
const f = split(entry);
|
|
122
|
+
if (!podInstanceDirs.has(f.dir))
|
|
123
|
+
continue;
|
|
124
|
+
if (podSet.has(entry))
|
|
125
|
+
skipped += 1;
|
|
126
|
+
else
|
|
127
|
+
push.push(f);
|
|
128
|
+
}
|
|
129
|
+
return { pull, push, skipped, ignored };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Parse the single listing exec's output: an `==INSTANCES==` section (one
|
|
133
|
+
* registered instance id per line, from the Pod's registry/instances.jsonl)
|
|
134
|
+
* then a `==FILES==` section ("dir/file" per line, relative to the Pod's
|
|
135
|
+
* inbox/). Anything before the first marker (login-shell noise) is ignored.
|
|
136
|
+
*/
|
|
137
|
+
export function parsePodListing(out) {
|
|
138
|
+
const instances = [];
|
|
139
|
+
const files = [];
|
|
140
|
+
let section = "none";
|
|
141
|
+
for (const raw of out.split("\n")) {
|
|
142
|
+
const line = raw.trim();
|
|
143
|
+
if (line === "==INSTANCES==") {
|
|
144
|
+
section = "instances";
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (line === "==FILES==") {
|
|
148
|
+
section = "files";
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (line.length === 0)
|
|
152
|
+
continue;
|
|
153
|
+
if (section === "instances")
|
|
154
|
+
instances.push(line);
|
|
155
|
+
else if (section === "files")
|
|
156
|
+
files.push(line);
|
|
157
|
+
}
|
|
158
|
+
return { instances, files };
|
|
159
|
+
}
|
|
160
|
+
function expandHome(p) {
|
|
161
|
+
return p.startsWith("~") ? join(homedir(), p.slice(1)) : p;
|
|
162
|
+
}
|
|
163
|
+
/** Exec a bash -lc script in the session-agent container. Throws on non-zero. */
|
|
164
|
+
function execPod(tunnel, pod, script, input) {
|
|
165
|
+
const args = ["-n", tunnel.namespace, "exec"];
|
|
166
|
+
if (input !== undefined)
|
|
167
|
+
args.push("-i");
|
|
168
|
+
args.push(pod, "-c", "session-agent", "--", "bash", "-lc", script);
|
|
169
|
+
const env = { ...process.env };
|
|
170
|
+
if (tunnel.kubeconfig)
|
|
171
|
+
env.KUBECONFIG = expandHome(tunnel.kubeconfig);
|
|
172
|
+
const r = spawnSync("kubectl", args, {
|
|
173
|
+
encoding: "utf8",
|
|
174
|
+
env,
|
|
175
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
176
|
+
...(input !== undefined ? { input } : {}),
|
|
177
|
+
});
|
|
178
|
+
if (r.status !== 0) {
|
|
179
|
+
// stderr only (kubectl/bash diagnostics) — never envelope content.
|
|
180
|
+
throw new Error(`kubectl exec failed: ${(r.stderr || "").trim().slice(0, 200)}`);
|
|
181
|
+
}
|
|
182
|
+
return r.stdout;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* README dropped in the Pod when the skeleton is created: documents the
|
|
186
|
+
* envelope-drop convention so agents in the Pod can join the h2a network by
|
|
187
|
+
* writing plain JSON files, with no h2a binary installed.
|
|
188
|
+
*/
|
|
189
|
+
function podReadme(podInboxDir) {
|
|
190
|
+
return [
|
|
191
|
+
"# h2a store (bridged)",
|
|
192
|
+
"",
|
|
193
|
+
"This directory is an h2a file store kept in sync with the operator's",
|
|
194
|
+
"local ~/h2a-workspace/.h2a by `remote h2a bridge` (no h2a binary needed",
|
|
195
|
+
"in this Pod).",
|
|
196
|
+
"",
|
|
197
|
+
"To MESSAGE another agent, write a JSON envelope",
|
|
198
|
+
' { "protocol": "sentropic.h2a", "version": "0.1", "id": "env:<ts>:<slug>",',
|
|
199
|
+
' "type": "event", "actor": { "instance", "role", "scope" }, "body", "createdAt" }',
|
|
200
|
+
"to inbox/<instance-dir>/env__<ts>__<slug>.json, where <instance-dir> is",
|
|
201
|
+
'the target instance id with ":" replaced by "__"',
|
|
202
|
+
"(claude:track:abc -> claude__track__abc).",
|
|
203
|
+
"",
|
|
204
|
+
`Your own inbox is inbox/${podInboxDir}/ — check it for new envelopes.`,
|
|
205
|
+
"The bridge never deletes files; acks/cleanup belong to h2a on the local",
|
|
206
|
+
"side. Existing file names are never overwritten.",
|
|
207
|
+
"",
|
|
208
|
+
].join("\n");
|
|
209
|
+
}
|
|
210
|
+
/** List local inbox entries as "dir/file" (missing store = empty listing). */
|
|
211
|
+
function listLocalInbox(localRoot) {
|
|
212
|
+
const inbox = join(localRoot, "inbox");
|
|
213
|
+
if (!existsSync(inbox))
|
|
214
|
+
return [];
|
|
215
|
+
const entries = [];
|
|
216
|
+
for (const dir of readdirSync(inbox, { withFileTypes: true })) {
|
|
217
|
+
if (!dir.isDirectory())
|
|
218
|
+
continue;
|
|
219
|
+
for (const f of readdirSync(join(inbox, dir.name), {
|
|
220
|
+
withFileTypes: true,
|
|
221
|
+
})) {
|
|
222
|
+
if (f.isFile() && f.name.endsWith(".json"))
|
|
223
|
+
entries.push(`${dir.name}/${f.name}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return entries;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* One bridge pass for a session Pod: scaffold the Pod store if missing, list
|
|
230
|
+
* both sides, then PULL new Pod-emitted envelopes and PUSH new locally
|
|
231
|
+
* addressed ones. Returns counters only — envelope content is transferred
|
|
232
|
+
* verbatim but never printed.
|
|
233
|
+
*/
|
|
234
|
+
export async function bridgeSession(sessionId, options = {}) {
|
|
235
|
+
const stderr = options.stderr ?? process.stderr;
|
|
236
|
+
const tunnel = getTunnel();
|
|
237
|
+
if (!tunnel) {
|
|
238
|
+
throw new Error("h2a bridge needs a tunnel configured (remote config tunnel …)");
|
|
239
|
+
}
|
|
240
|
+
const pod = `session-${sessionId}`;
|
|
241
|
+
const localRoot = options.localRoot ?? defaultLocalH2aRoot();
|
|
242
|
+
const podInbox = `$HOME/${H2A_POD_ROOT}/inbox`;
|
|
243
|
+
const defaultDir = instanceInboxDir(defaultPodInstance(sessionId, options.profile));
|
|
244
|
+
// 1. Pod skeleton: create inbox/ + README on first contact, so Pod agents
|
|
245
|
+
// can drop envelopes even without the h2a binary. Never touches an existing
|
|
246
|
+
// store.
|
|
247
|
+
const scaffold = execPod(tunnel, pod, [
|
|
248
|
+
`root="$HOME/${H2A_POD_ROOT}"`,
|
|
249
|
+
`if [ -d "$root/inbox" ]; then echo h2a-store-exists; else`,
|
|
250
|
+
`mkdir -p "$root/inbox/${defaultDir}"`,
|
|
251
|
+
`cat > "$root/README.md" <<'H2ADOC'`,
|
|
252
|
+
podReadme(defaultDir),
|
|
253
|
+
`H2ADOC`,
|
|
254
|
+
`echo h2a-store-created`,
|
|
255
|
+
`fi`,
|
|
256
|
+
].join("\n"));
|
|
257
|
+
const scaffolded = scaffold.includes("h2a-store-created");
|
|
258
|
+
// 2. One listing exec: the Pod's registered instances + its inbox files.
|
|
259
|
+
const listing = parsePodListing(execPod(tunnel, pod, [
|
|
260
|
+
`cd "$HOME/${H2A_POD_ROOT}" 2>/dev/null || exit 0`,
|
|
261
|
+
`echo ==INSTANCES==`,
|
|
262
|
+
`sed -n 's/.*"instance"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' registry/instances.jsonl 2>/dev/null`,
|
|
263
|
+
`echo ==FILES==`,
|
|
264
|
+
`shopt -s nullglob`,
|
|
265
|
+
`for f in inbox/*/*.json; do printf '%s\\n' "\${f#inbox/}"; done`,
|
|
266
|
+
].join("\n")));
|
|
267
|
+
const podInstanceDirs = new Set([defaultDir]);
|
|
268
|
+
for (const instance of listing.instances) {
|
|
269
|
+
podInstanceDirs.add(instanceInboxDir(instance));
|
|
270
|
+
}
|
|
271
|
+
// 3. Plan: pure decision over the two listings.
|
|
272
|
+
const plan = planBridge({
|
|
273
|
+
podFiles: listing.files,
|
|
274
|
+
localFiles: listLocalInbox(localRoot),
|
|
275
|
+
podInstanceDirs,
|
|
276
|
+
});
|
|
277
|
+
if (plan.ignored > 0) {
|
|
278
|
+
stderr.write(`[remote] h2a bridge ${sessionId}: ignored ${plan.ignored} unsafe inbox entry name(s)\n`);
|
|
279
|
+
}
|
|
280
|
+
let pulled = 0;
|
|
281
|
+
let pushed = 0;
|
|
282
|
+
let skipped = plan.skipped;
|
|
283
|
+
let failed = 0;
|
|
284
|
+
// 4. PULL Pod → local (encoded ONCE in the Pod, decoded ONCE here).
|
|
285
|
+
for (const f of plan.pull) {
|
|
286
|
+
const dst = join(localRoot, "inbox", f.dir, f.file);
|
|
287
|
+
if (existsSync(dst)) {
|
|
288
|
+
skipped += 1; // appeared since the listing — never overwrite
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
const b64 = execPod(tunnel, pod, `base64 < "${podInbox}/${f.dir}/${f.file}" | tr -d '\\n'`);
|
|
293
|
+
mkdirSync(join(localRoot, "inbox", f.dir), { recursive: true });
|
|
294
|
+
writeFileSync(dst, Buffer.from(b64.trim(), "base64"));
|
|
295
|
+
pulled += 1;
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
failed += 1;
|
|
299
|
+
stderr.write(`[remote] h2a bridge ${sessionId}: pull ${f.dir}/${f.file} failed: ${String(error instanceof Error ? error.message : error).slice(0, 160)}\n`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// 5. PUSH local → Pod (encoded ONCE here, decoded ONCE in the Pod; the Pod
|
|
303
|
+
// side re-checks existence so a racing writer is never overwritten).
|
|
304
|
+
for (const f of plan.push) {
|
|
305
|
+
const src = join(localRoot, "inbox", f.dir, f.file);
|
|
306
|
+
try {
|
|
307
|
+
const payload = readFileSync(src).toString("base64");
|
|
308
|
+
const out = execPod(tunnel, pod, [
|
|
309
|
+
`d="${podInbox}/${f.dir}"; f="$d/${f.file}"`,
|
|
310
|
+
`mkdir -p "$d"`,
|
|
311
|
+
`if [ -e "$f" ]; then echo h2a-exists; else base64 -d > "$f" && echo h2a-written; fi`,
|
|
312
|
+
].join("\n"), payload);
|
|
313
|
+
if (out.includes("h2a-written"))
|
|
314
|
+
pushed += 1;
|
|
315
|
+
else
|
|
316
|
+
skipped += 1;
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
failed += 1;
|
|
320
|
+
stderr.write(`[remote] h2a bridge ${sessionId}: push ${f.dir}/${f.file} failed: ${String(error instanceof Error ? error.message : error).slice(0, 160)}\n`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
sessionId,
|
|
325
|
+
pulled,
|
|
326
|
+
pushed,
|
|
327
|
+
skipped,
|
|
328
|
+
failed,
|
|
329
|
+
scaffolded,
|
|
330
|
+
podInstanceDirs: [...podInstanceDirs].sort(),
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=h2a-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"h2a-bridge.js","sourceRoot":"","sources":["../src/h2a-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* h2a job callback + decision channel — P3 of cross-type agent delegation.
|
|
3
|
+
*
|
|
4
|
+
* Pure helpers (builders + parsing + instance derivation) plus a thin fs layer
|
|
5
|
+
* to DROP an envelope into a local h2a inbox. The bridge (`remote h2a bridge`)
|
|
6
|
+
* already transports envelopes pod↔local and is idempotent by file name, so
|
|
7
|
+
* everything here is best-effort: an undelivered envelope never blocks a job.
|
|
8
|
+
*
|
|
9
|
+
* - `job.done` agent → PARENT, when a delegated job terminates (body:
|
|
10
|
+
* {jobId, type, state, exitCode?, summary?, resultRef?}).
|
|
11
|
+
* - `decision.requested` agent → PARENT, when the job needs a human/parent
|
|
12
|
+
* decision (body: {jobId, question, options?}).
|
|
13
|
+
* - `decision.reply` PARENT → agent, the answer (body: {jobId, answer}).
|
|
14
|
+
*
|
|
15
|
+
* Envelopes mirror the on-disk h2a shape exactly (the format `h2a-bridge.ts`
|
|
16
|
+
* documents in the Pod README): {protocol, version, id, type, actor:{instance,
|
|
17
|
+
* role, scope}, to, body, createdAt}. They drop into
|
|
18
|
+
* `<localRoot>/inbox/<recipient-dir>/env__<ts>__<slug>.json`, where the dir is
|
|
19
|
+
* the recipient instance id with ":" → "__" — the bridge's SAFE_ENTRY shape.
|
|
20
|
+
*
|
|
21
|
+
* SECURITY: jobId / answer / question ride structured argv → the envelope body,
|
|
22
|
+
* NEVER a shell string. jobId is `assertSafeName`-checked before it becomes a
|
|
23
|
+
* file slug. The bridge itself re-validates every entry name (SAFE_ENTRY).
|
|
24
|
+
*
|
|
25
|
+
* KNOWN LIMIT — depends on agent behavior: a delegated interactive agent must
|
|
26
|
+
* CHOOSE to call its h2a MCP tool (h2a_inbox / write an envelope) to read a
|
|
27
|
+
* `decision.reply` or to emit a `decision.requested`. We build the channel and
|
|
28
|
+
* the transport; we cannot force the agent to use it. `job.done` for an
|
|
29
|
+
* interactive job is independent of that (it rides the SessionEnd hook), and
|
|
30
|
+
* for headless rides reconciliation — neither needs the agent to cooperate.
|
|
31
|
+
*/
|
|
32
|
+
import { type DelegateType } from "./delegate.js";
|
|
33
|
+
import type { JobState, RegistryEntry } from "./registry.js";
|
|
34
|
+
export declare const H2A_PROTOCOL = "sentropic.h2a";
|
|
35
|
+
export declare const H2A_VERSION = "0.1";
|
|
36
|
+
/** The P3 envelope types (the spec's vocabulary, on the envelope `type` field). */
|
|
37
|
+
export type JobEnvelopeType = "job.done" | "decision.requested" | "decision.reply";
|
|
38
|
+
export type EnvelopeActor = {
|
|
39
|
+
instance: string;
|
|
40
|
+
role: string;
|
|
41
|
+
scope: string;
|
|
42
|
+
};
|
|
43
|
+
export type H2aEnvelope<TBody> = {
|
|
44
|
+
protocol: typeof H2A_PROTOCOL;
|
|
45
|
+
version: typeof H2A_VERSION;
|
|
46
|
+
id: string;
|
|
47
|
+
type: JobEnvelopeType;
|
|
48
|
+
actor: EnvelopeActor;
|
|
49
|
+
/** Recipient instance id (who this envelope is addressed to). */
|
|
50
|
+
to: string;
|
|
51
|
+
body: TBody;
|
|
52
|
+
createdAt: string;
|
|
53
|
+
};
|
|
54
|
+
export type JobDoneBody = {
|
|
55
|
+
jobId: string;
|
|
56
|
+
/** The agent type (claude/codex/agy) so the parent need not re-look-up. */
|
|
57
|
+
type: DelegateType;
|
|
58
|
+
state: JobState;
|
|
59
|
+
exitCode?: number;
|
|
60
|
+
summary?: string;
|
|
61
|
+
resultRef?: string;
|
|
62
|
+
};
|
|
63
|
+
export type DecisionRequestedBody = {
|
|
64
|
+
jobId: string;
|
|
65
|
+
question: string;
|
|
66
|
+
options?: string[];
|
|
67
|
+
};
|
|
68
|
+
export type DecisionReplyBody = {
|
|
69
|
+
jobId: string;
|
|
70
|
+
answer: string;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* The h2a INSTANCE id of a delegated job's agent — the inbox a `decision.reply`
|
|
74
|
+
* must reach, and the `actor.instance` on envelopes the job emits.
|
|
75
|
+
* - remote (kind:"remote"): the Pod default mapping `<tool>:remote:<sessionId>`
|
|
76
|
+
* (same as `h2a-bridge.ts` defaultPodInstance), so the bridge already routes
|
|
77
|
+
* to/from it.
|
|
78
|
+
* - local: `<tool>:job:<jobId>` — a stable, predictable instance for the local
|
|
79
|
+
* job's h2a side-window. jobId already passed assertSafeName at delegate time.
|
|
80
|
+
* Pure, exported for tests.
|
|
81
|
+
*/
|
|
82
|
+
export declare function jobInstance(entry: Pick<RegistryEntry, "tool" | "kind" | "id" | "remoteId">): string;
|
|
83
|
+
/**
|
|
84
|
+
* The PARENT instance to address a callback to: the explicit `callbackTo`
|
|
85
|
+
* recorded on the job at delegate time (`--parent`/`--on-done`), else undefined
|
|
86
|
+
* (no parent → no callback is emitted; best-effort). Pure, exported for tests.
|
|
87
|
+
*/
|
|
88
|
+
export declare function parentInstance(entry: Pick<RegistryEntry, "callbackTo">): string | undefined;
|
|
89
|
+
/** The `actor.instance` an envelope carries, or undefined when malformed. Pure. */
|
|
90
|
+
export declare function envelopeActorInstance(envelope: H2aEnvelope<unknown>): string | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Is `envelope`'s sender the instance we EXPECT for this job? `expectedInstance`
|
|
93
|
+
* is the job's `jobInstance(...)` (for job.done / decision.requested ABOUT the
|
|
94
|
+
* job) or the job's recorded parent (for decision.reply). An undefined expected
|
|
95
|
+
* instance means we can't verify (no job/parent on record) → reject (fail
|
|
96
|
+
* closed). Pure, exported for tests.
|
|
97
|
+
*/
|
|
98
|
+
export declare function isEnvelopeFromExpected(envelope: H2aEnvelope<unknown>, expectedInstance: string | undefined): boolean;
|
|
99
|
+
/** On-disk file name for an envelope — matches the bridge's SAFE_ENTRY shape. */
|
|
100
|
+
export declare function envelopeFileName(kind: JobEnvelopeType, jobId: string, ts: number): string;
|
|
101
|
+
/**
|
|
102
|
+
* STABLE (timestamp-free) file name for a `job.done` callback: ONE per job, so
|
|
103
|
+
* the SessionEnd hook and the reconcile loop can BOTH attempt the emit and the
|
|
104
|
+
* second one is a no-op (dropEnvelope skips an existing file; the bridge skips
|
|
105
|
+
* by file name too). Idempotency by name, exactly the bridge's contract.
|
|
106
|
+
*/
|
|
107
|
+
export declare function jobDoneFileName(jobId: string): string;
|
|
108
|
+
/**
|
|
109
|
+
* Build a `job.done` envelope: emitted BY the job's agent, addressed TO the
|
|
110
|
+
* parent. The body carries jobId/type/state and optional exitCode/summary/
|
|
111
|
+
* resultRef. Pure, exported for tests (ts/id are injected for determinism).
|
|
112
|
+
*/
|
|
113
|
+
export declare function buildJobDoneEnvelope(args: {
|
|
114
|
+
job: Pick<RegistryEntry, "tool" | "kind" | "id" | "remoteId">;
|
|
115
|
+
to: string;
|
|
116
|
+
state: JobState;
|
|
117
|
+
exitCode?: number;
|
|
118
|
+
summary?: string;
|
|
119
|
+
resultRef?: string;
|
|
120
|
+
nowMs?: number;
|
|
121
|
+
}): H2aEnvelope<JobDoneBody>;
|
|
122
|
+
/**
|
|
123
|
+
* Build a `decision.requested` envelope: emitted BY the job's agent, addressed
|
|
124
|
+
* TO the parent. Pure, exported for tests.
|
|
125
|
+
*/
|
|
126
|
+
export declare function buildDecisionRequested(args: {
|
|
127
|
+
job: Pick<RegistryEntry, "tool" | "kind" | "id" | "remoteId">;
|
|
128
|
+
to: string;
|
|
129
|
+
question: string;
|
|
130
|
+
options?: string[];
|
|
131
|
+
nowMs?: number;
|
|
132
|
+
}): H2aEnvelope<DecisionRequestedBody>;
|
|
133
|
+
/**
|
|
134
|
+
* Build a `decision.reply` envelope: emitted BY the parent, addressed TO the
|
|
135
|
+
* job's agent inbox. The `answer` is opaque text — passed straight through, no
|
|
136
|
+
* shell concat. Pure, exported for tests.
|
|
137
|
+
*/
|
|
138
|
+
export declare function buildDecisionReply(args: {
|
|
139
|
+
job: Pick<RegistryEntry, "tool" | "kind" | "id" | "remoteId">;
|
|
140
|
+
parentInstance: string;
|
|
141
|
+
answer: string;
|
|
142
|
+
nowMs?: number;
|
|
143
|
+
}): H2aEnvelope<DecisionReplyBody>;
|
|
144
|
+
export type DropResult = {
|
|
145
|
+
/** Absolute path written (or that already existed). */
|
|
146
|
+
path: string;
|
|
147
|
+
/** false when the file already existed — never overwritten. */
|
|
148
|
+
written: boolean;
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Drop an envelope into `<localRoot>/inbox/<to-dir>/<fileName>`, where <to-dir>
|
|
152
|
+
* is `envelope.to` with ":" → "__". Idempotent by FILE NAME (an existing file is
|
|
153
|
+
* left untouched — same contract as the bridge). The jobId in the file name is
|
|
154
|
+
* already assertSafeName-checked by the caller. Returns where it landed.
|
|
155
|
+
*/
|
|
156
|
+
export declare function dropEnvelope(envelope: H2aEnvelope<unknown>, fileName: string, localRoot?: string): DropResult;
|
|
157
|
+
export type PendingDecision = {
|
|
158
|
+
jobId: string;
|
|
159
|
+
question: string;
|
|
160
|
+
options?: string[];
|
|
161
|
+
/** The envelope id, so a future ack/reply can reference it. */
|
|
162
|
+
envelopeId: string;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Resolver: the expected `actor.instance` for an envelope about `jobId`, by
|
|
166
|
+
* envelope type. For `job.done`/`decision.requested` (ABOUT the job) it is the
|
|
167
|
+
* job's own `jobInstance(...)`; for `decision.reply` (FROM the parent) it is the
|
|
168
|
+
* job's recorded parent. Returns undefined when the job is unknown → the
|
|
169
|
+
* envelope is rejected (fail closed). The CLI builds this off the registry.
|
|
170
|
+
*/
|
|
171
|
+
export type ExpectedInstanceResolver = (jobId: string, type: JobEnvelopeType) => string | undefined;
|
|
172
|
+
/**
|
|
173
|
+
* AUTHENTICATE a flat list of job envelopes (S1): keep only those whose claimed
|
|
174
|
+
* `actor.instance` matches the instance the addressed job is known to use (per
|
|
175
|
+
* the resolver). A forged cross-job envelope (wrong actor) is DROPPED. Envelopes
|
|
176
|
+
* that aren't one of our job types pass through untouched (they're not our
|
|
177
|
+
* concern here). Pure over (envelopes, resolver), exported for tests.
|
|
178
|
+
*/
|
|
179
|
+
export declare function authenticateJobEnvelopes(envelopes: ReadonlyArray<H2aEnvelope<unknown>>, expectedInstanceOf: ExpectedInstanceResolver): H2aEnvelope<unknown>[];
|
|
180
|
+
/**
|
|
181
|
+
* From a flat list of (fileName, rawJson) envelopes found in the PARENT's inbox
|
|
182
|
+
* and the JOB inboxes, return the `decision.requested` that have NO matching
|
|
183
|
+
* `decision.reply` yet (same jobId). Pure, exported for tests — the fs read is
|
|
184
|
+
* done by the caller so this stays deterministic.
|
|
185
|
+
*
|
|
186
|
+
* A reply is matched to a request by jobId (the channel is one open decision per
|
|
187
|
+
* job at a time; P4 may add a per-request id). `repliedJobIds` is the set of
|
|
188
|
+
* jobIds for which a `decision.reply` exists anywhere we can see.
|
|
189
|
+
*/
|
|
190
|
+
export declare function pendingDecisions(envelopes: ReadonlyArray<H2aEnvelope<unknown>>, repliedJobIds: ReadonlySet<string>): PendingDecision[];
|
|
191
|
+
/** The set of jobIds that already have a `decision.reply` in `envelopes`. Pure. */
|
|
192
|
+
export declare function repliedDecisionJobIds(envelopes: ReadonlyArray<H2aEnvelope<unknown>>): Set<string>;
|
|
193
|
+
/**
|
|
194
|
+
* Read every envelope under `<localRoot>/inbox/**` (one dir level deep, the h2a
|
|
195
|
+
* layout). The fs read is isolated HERE so the listing/matching above stays
|
|
196
|
+
* pure. Missing store → empty. Never throws on a bad file (skips it).
|
|
197
|
+
*/
|
|
198
|
+
export declare function readInboxEnvelopes(localRoot?: string): H2aEnvelope<unknown>[];
|
|
199
|
+
/**
|
|
200
|
+
* Does the job have an UNANSWERED `decision.requested`? Used by `jobs status` to
|
|
201
|
+
* show `awaiting-decision`. Pure over the envelope list, exported for tests.
|
|
202
|
+
*/
|
|
203
|
+
export declare function isAwaitingDecision(jobId: string, envelopes: ReadonlyArray<H2aEnvelope<unknown>>): boolean;
|
|
204
|
+
/**
|
|
205
|
+
* One-line render of a pending decision for `jobs decisions` — jobId + question
|
|
206
|
+
* only (no raw envelope body beyond the essentials, per the security note).
|
|
207
|
+
* Pure, exported for tests.
|
|
208
|
+
*/
|
|
209
|
+
export declare function renderPendingDecisions(decisions: ReadonlyArray<PendingDecision>): string;
|
|
210
|
+
export type EmitJobDoneResult = {
|
|
211
|
+
emitted: true;
|
|
212
|
+
path: string;
|
|
213
|
+
written: boolean;
|
|
214
|
+
to: string;
|
|
215
|
+
} | {
|
|
216
|
+
emitted: false;
|
|
217
|
+
reason: "no-parent" | "error";
|
|
218
|
+
error?: string;
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Best-effort: emit a `job.done` envelope for a finished job into the parent's
|
|
222
|
+
* local inbox. No-op (emitted:false, "no-parent") when the job has no recorded
|
|
223
|
+
* `callbackTo` — a job delegated without a parent simply has nobody to notify.
|
|
224
|
+
* NEVER throws: any fs/build error is swallowed into emitted:false so a callback
|
|
225
|
+
* failure can't take down the SessionEnd hook or the reconcile loop.
|
|
226
|
+
*/
|
|
227
|
+
export declare function emitJobDone(job: RegistryEntry, args?: {
|
|
228
|
+
state: JobState;
|
|
229
|
+
exitCode?: number;
|
|
230
|
+
summary?: string;
|
|
231
|
+
resultRef?: string;
|
|
232
|
+
localRoot?: string;
|
|
233
|
+
nowMs?: number;
|
|
234
|
+
}): EmitJobDoneResult;
|
|
235
|
+
//# sourceMappingURL=h2a-jobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"h2a-jobs.d.ts","sourceRoot":"","sources":["../src/h2a-jobs.ts"],"names":[],"mappings":"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"}
|