agent-relay 9.2.3 → 9.2.4

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.
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Durable, project-local journal of external cleanup work that failed or may
3
+ * have been orphaned by a crash. It exists because several ids have no other
4
+ * durable home once their run ends:
5
+ *
6
+ * - a superseded relayfile-cloud webhook subscription id is overwritten in the
7
+ * binding record the moment the replacement bind() lands;
8
+ * - a rollback after a failed subscribe tears down resources that were never
9
+ * bound anywhere;
10
+ * - a crash between any remote create and persisting its server-assigned id
11
+ * leaves a live resource findable only by a deterministic recovery key —
12
+ * recorded here as a `subscribe-attempt` entry written BEFORE the first
13
+ * create and upgraded with concrete ids as they are assigned.
14
+ *
15
+ * Entries are retried best-effort on later subscribe/unsubscribe runs and are
16
+ * scoped to the connection identity that created them, so a sweep never
17
+ * deletes resources through the wrong workspace/daemon. An entry carrying an
18
+ * `owner` is the LEASE of a live transaction: other processes must neither
19
+ * sweep it nor clear it unless the owner is provably dead on this host.
20
+ *
21
+ * The journal file lives in the CLI's project data dir (`.agentworkforce/relay/`,
22
+ * excluded from git by @agent-relay/config's ensureGitExclude) and is written
23
+ * 0600 via temp-file write + fsync + atomic rename + parent-directory fsync,
24
+ * so a committed update survives host/power crashes, and every
25
+ * read-modify-write runs under an exclusive lockfile so concurrent CLI
26
+ * processes cannot lose entries. A corrupt or unreadable journal FAILS
27
+ * CLOSED: reads throw, nothing is swept, and callers abort before creating
28
+ * new external resources.
29
+ *
30
+ * Attempt entries carry the inbound-target `url`, which may be capability
31
+ * bearing — callers must never log entry urls or ids (the 0600 file is their
32
+ * only home).
33
+ */
34
+ export type PendingCleanupKind = 'relayfile-webhook-subscription' | 'relay-webhook' | 'relay-subscription' | 'subscribe-attempt';
35
+ export interface PendingCleanupOwner {
36
+ pid: number;
37
+ host: string;
38
+ /** Unique per transaction, so a run only ever clears ITS OWN entries. */
39
+ attemptId: string;
40
+ /**
41
+ * Epoch-ms lease heartbeat, stamped when the owner takes (or re-takes) the
42
+ * lease. Liveness requires BOTH a passing pid probe AND a fresh heartbeat:
43
+ * PID reuse (or an unprobeable foreign host) can therefore wedge later
44
+ * lifecycles for at most the bounded lease window, never permanently.
45
+ */
46
+ heartbeatAt: number;
47
+ }
48
+ export interface PendingCleanupEntry {
49
+ kind: PendingCleanupKind;
50
+ /** Connection identity that may retry this entry (never a secret). */
51
+ scope: string;
52
+ /**
53
+ * Lifecycle operation a `subscribe-attempt` reservation belongs to. Both
54
+ * operations share one per-(scope, provider, resource) lease so a
55
+ * subscribe and an unsubscribe can never interleave on the same binding;
56
+ * an `unsubscribe` reservation creates nothing, so it carries no recovery
57
+ * keys and a dead one is simply dropped.
58
+ */
59
+ operation?: 'subscribe' | 'unsubscribe';
60
+ /** Concrete resource id — required for the three concrete kinds. */
61
+ id?: string;
62
+ /**
63
+ * relayfile-cloud workspace the resource lives in, when known. Sweeps pin
64
+ * delete/list calls to it, and a cloud 404 only counts as convergence when
65
+ * the entry is pinned — an unpinned 404 might just be the wrong active
66
+ * workspace, so the entry is retained instead.
67
+ */
68
+ relayfileWorkspaceId?: string;
69
+ /**
70
+ * subscribe-attempt recovery keys. `url`+`pathGlobs` deterministically find
71
+ * the relayfile-cloud subscription; the exact `webhookName` finds the relay
72
+ * inbound webhook; `writebackUrl` (+ binding references) finds the relay
73
+ * event subscription. `relayScope` scopes the relay-side recovery.
74
+ */
75
+ provider?: string;
76
+ resource?: string;
77
+ url?: string;
78
+ pathGlobs?: string[];
79
+ /** Exact inbound webhook name (chosen before create, unique per attempt) —
80
+ * recovery matches on it precisely so it can never delete a DIFFERENT
81
+ * attempt's pre-bind webhook for the same resource. */
82
+ webhookName?: string;
83
+ writebackUrl?: string;
84
+ relayScope?: string;
85
+ /** Concrete ids, filled in as each create returns (best-effort). */
86
+ webhookId?: string;
87
+ webhookSubscriptionId?: string;
88
+ subscriptionId?: string;
89
+ /**
90
+ * Present while a live transaction owns this entry (its lease across
91
+ * remote creates → bind). Terminal failure records are written without an
92
+ * owner so any later run may retry them.
93
+ */
94
+ owner?: PendingCleanupOwner;
95
+ }
96
+ export interface CleanupJournal {
97
+ /** Snapshot of the journal. Throws CleanupJournalError if unreadable/corrupt. */
98
+ list(): Promise<PendingCleanupEntry[]>;
99
+ /**
100
+ * Atomic read-modify-write under the exclusive journal lock. The mutation
101
+ * may be async — remote lifecycle actions that must serialize with
102
+ * reservations (e.g. URL-keyed recovery deletes) run inside it. Throws
103
+ * CleanupJournalError when the journal is corrupt or the lock cannot be
104
+ * acquired — callers must treat that as fail-closed.
105
+ */
106
+ update(mutate: (entries: PendingCleanupEntry[]) => PendingCleanupEntry[] | Promise<PendingCleanupEntry[]>): Promise<void>;
107
+ }
108
+ export declare class CleanupJournalError extends Error {
109
+ readonly code: 'corrupt' | 'locked' | 'io';
110
+ constructor(code: 'corrupt' | 'locked' | 'io', message: string);
111
+ }
112
+ /** Stable identity for dedup/removal. Order-insensitive over pathGlobs; an
113
+ * owned entry is keyed by its attemptId too, so a transaction only ever adds,
114
+ * upgrades, or clears ITS OWN entries and never a concurrent attempt's. The
115
+ * delimiter is an escaped NUL, which cannot occur in any component. */
116
+ export declare function cleanupEntryKey(entry: PendingCleanupEntry): string;
117
+ /** File-backed CleanupJournal in the project data dir. Paths resolve per call.
118
+ * `dataDirOverride` exists for tests only — production callers use the default. */
119
+ export declare function fileCleanupJournal(dataDirOverride?: string): CleanupJournal;
120
+ //# sourceMappingURL=integration-cleanup-journal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-cleanup-journal.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/integration-cleanup-journal.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,MAAM,MAAM,kBAAkB,GAC1B,gCAAgC,GAChC,eAAe,GACf,oBAAoB,GACpB,mBAAmB,CAAC;AAExB,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,kBAAkB,CAAC;IACzB,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC;IACxC,oEAAoE;IACpE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;2DAEuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,KAAK,CAAC,EAAE,mBAAmB,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,IAAI,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACvC;;;;;;OAMG;IACH,MAAM,CACJ,MAAM,EAAE,CAAC,OAAO,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,GACjG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,qBAAa,mBAAoB,SAAQ,KAAK;aAE1B,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,IAAI;gBAAjC,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,IAAI,EACjD,OAAO,EAAE,MAAM;CAKlB;AAED;;;uEAGuE;AACvE,wBAAgB,eAAe,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAYlE;AAkTD;mFACmF;AACnF,wBAAgB,kBAAkB,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,cAAc,CA0C3E"}
@@ -0,0 +1,299 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { getProjectPaths } from '@agent-relay/config';
6
+ import { formatBrokerNotFoundError, getBrokerBinaryPath } from '@agent-relay/harness-driver/broker-path';
7
+ export class CleanupJournalError extends Error {
8
+ code;
9
+ constructor(code, message) {
10
+ super(message);
11
+ this.code = code;
12
+ this.name = 'CleanupJournalError';
13
+ }
14
+ }
15
+ /** Stable identity for dedup/removal. Order-insensitive over pathGlobs; an
16
+ * owned entry is keyed by its attemptId too, so a transaction only ever adds,
17
+ * upgrades, or clears ITS OWN entries and never a concurrent attempt's. The
18
+ * delimiter is an escaped NUL, which cannot occur in any component. */
19
+ export function cleanupEntryKey(entry) {
20
+ const globs = [...(entry.pathGlobs ?? [])].sort().join(',');
21
+ return [
22
+ entry.kind,
23
+ entry.scope,
24
+ entry.id ?? '',
25
+ entry.provider ?? '',
26
+ entry.resource ?? '',
27
+ entry.url ?? '',
28
+ globs,
29
+ entry.owner?.attemptId ?? '',
30
+ ].join('\u0000');
31
+ }
32
+ const LOCK_TIMEOUT_MS = 5_000;
33
+ const CONCRETE_KINDS = new Set([
34
+ 'relayfile-webhook-subscription',
35
+ 'relay-webhook',
36
+ 'relay-subscription',
37
+ ]);
38
+ function isNonEmptyString(value) {
39
+ return typeof value === 'string' && value.trim() !== '';
40
+ }
41
+ function isOptionalString(value) {
42
+ return value === undefined || isNonEmptyString(value);
43
+ }
44
+ function isValidOwner(owner) {
45
+ if (owner === undefined)
46
+ return true;
47
+ if (!owner || typeof owner !== 'object')
48
+ return false;
49
+ const candidate = owner;
50
+ return (typeof candidate.pid === 'number' &&
51
+ Number.isInteger(candidate.pid) &&
52
+ candidate.pid > 0 &&
53
+ isNonEmptyString(candidate.host) &&
54
+ isNonEmptyString(candidate.attemptId) &&
55
+ typeof candidate.heartbeatAt === 'number' &&
56
+ Number.isFinite(candidate.heartbeatAt) &&
57
+ candidate.heartbeatAt > 0);
58
+ }
59
+ /** Discriminated validation — anything short of a well-formed entry is corrupt,
60
+ * so a mangled journal can never be silently treated as "nothing pending". */
61
+ function isValidEntry(value) {
62
+ if (!value || typeof value !== 'object' || Array.isArray(value))
63
+ return false;
64
+ const entry = value;
65
+ if (!isNonEmptyString(entry.scope))
66
+ return false;
67
+ if (!isValidOwner(entry.owner))
68
+ return false;
69
+ if (!isOptionalString(entry.relayfileWorkspaceId))
70
+ return false;
71
+ if (CONCRETE_KINDS.has(entry.kind))
72
+ return isNonEmptyString(entry.id);
73
+ if (entry.kind === 'subscribe-attempt') {
74
+ if (entry.operation !== undefined &&
75
+ entry.operation !== 'subscribe' &&
76
+ entry.operation !== 'unsubscribe') {
77
+ return false;
78
+ }
79
+ if (entry.operation === 'unsubscribe') {
80
+ return isNonEmptyString(entry.provider) && isNonEmptyString(entry.resource);
81
+ }
82
+ return (isNonEmptyString(entry.url) &&
83
+ isNonEmptyString(entry.provider) &&
84
+ isNonEmptyString(entry.resource) &&
85
+ isNonEmptyString(entry.webhookName) &&
86
+ isNonEmptyString(entry.writebackUrl) &&
87
+ isNonEmptyString(entry.relayScope) &&
88
+ Array.isArray(entry.pathGlobs) &&
89
+ entry.pathGlobs.length > 0 &&
90
+ entry.pathGlobs.every(isNonEmptyString) &&
91
+ isOptionalString(entry.webhookId) &&
92
+ isOptionalString(entry.webhookSubscriptionId) &&
93
+ isOptionalString(entry.subscriptionId));
94
+ }
95
+ return false;
96
+ }
97
+ function parseEntries(raw, file) {
98
+ let parsed;
99
+ try {
100
+ parsed = JSON.parse(raw);
101
+ }
102
+ catch {
103
+ throw new CleanupJournalError('corrupt', `The pending-cleanup journal at ${file} is not valid JSON. Nothing was swept or overwritten; inspect it (it may reference external resources that still need deletion) and remove it to continue.`);
104
+ }
105
+ if (!Array.isArray(parsed) || !parsed.every(isValidEntry)) {
106
+ throw new CleanupJournalError('corrupt', `The pending-cleanup journal at ${file} has an unexpected shape. Nothing was swept or overwritten; inspect it and remove it to continue.`);
107
+ }
108
+ return parsed;
109
+ }
110
+ async function beginJournalTransaction(lockFile, journalFile) {
111
+ const binary = getBrokerBinaryPath();
112
+ if (!binary) {
113
+ throw new CleanupJournalError('io', formatBrokerNotFoundError());
114
+ }
115
+ const child = spawn(binary, [
116
+ 'journal-lock',
117
+ '--file',
118
+ lockFile,
119
+ '--journal-file',
120
+ journalFile,
121
+ '--timeout-ms',
122
+ String(LOCK_TIMEOUT_MS),
123
+ ], { stdio: ['pipe', 'pipe', 'pipe'] });
124
+ const exit = new Promise((resolve) => {
125
+ child.on('exit', (code) => resolve(code));
126
+ child.on('error', () => resolve(null));
127
+ });
128
+ let exited = false;
129
+ void exit.then(() => {
130
+ exited = true;
131
+ });
132
+ // Exact framed handshake: buffer stdout until the first newline and demand
133
+ // the line be precisely `locked` — no substring matching, and a hard
134
+ // startup deadline that kills a wedged helper.
135
+ await new Promise((resolve, reject) => {
136
+ let settled = false;
137
+ let buffer = '';
138
+ const settle = (fn) => {
139
+ if (settled)
140
+ return;
141
+ settled = true;
142
+ clearTimeout(deadline);
143
+ fn();
144
+ };
145
+ const deadline = setTimeout(() => {
146
+ settle(() => {
147
+ child.kill('SIGKILL');
148
+ reject(new CleanupJournalError('io', `The journal-lock helper did not complete its handshake for ${lockFile} in time and was killed.`));
149
+ });
150
+ }, LOCK_TIMEOUT_MS + 2_000);
151
+ child.stdout.on('data', (chunk) => {
152
+ buffer += chunk.toString('utf8');
153
+ const newline = buffer.indexOf('\n');
154
+ if (newline < 0)
155
+ return;
156
+ const line = buffer.slice(0, newline);
157
+ if (line === 'locked') {
158
+ settle(resolve);
159
+ }
160
+ else {
161
+ settle(() => {
162
+ child.kill('SIGKILL');
163
+ reject(new CleanupJournalError('io', `The journal-lock helper sent an unexpected handshake for ${lockFile}.`));
164
+ });
165
+ }
166
+ });
167
+ child.on('error', (err) => settle(() => reject(new CleanupJournalError('io', `Could not spawn the journal-lock helper (${binary}): ${err.message}`))));
168
+ void exit.then((code) => {
169
+ settle(() => {
170
+ if (code === 4) {
171
+ reject(new CleanupJournalError('locked', `Timed out waiting for the pending-cleanup journal lock at ${lockFile}: another agent-relay process holds it. The kernel releases it automatically when that process exits; retry afterwards.`));
172
+ }
173
+ else if (code === 3) {
174
+ reject(new CleanupJournalError('locked', `The pending-cleanup journal lock at ${lockFile} contains an unrecognized sentinel from an older format. Nothing was swept or overwritten; inspect and remove the file to continue.`));
175
+ }
176
+ else if (code === 2) {
177
+ // clap usage error: this broker binary predates the journal-lock
178
+ // helper (version skew), or the invocation is malformed.
179
+ reject(new CleanupJournalError('io', `The resolved agent-relay-broker binary (${binary}) does not support the journal-lock helper; upgrade the broker (or set AGENT_RELAY_BIN to a current build) and retry.`));
180
+ }
181
+ else {
182
+ reject(new CleanupJournalError('io', `The journal-lock helper exited unexpectedly (code ${code ?? 'unknown'}) before acquiring ${lockFile}.`));
183
+ }
184
+ });
185
+ });
186
+ });
187
+ const finish = async (payload, failure) => {
188
+ const committing = payload !== undefined;
189
+ if (exited) {
190
+ if (committing) {
191
+ // The lock (and with it transactional isolation) is already gone; the
192
+ // journal is untouched — surface instead of committing blind.
193
+ throw new CleanupJournalError('io', failure);
194
+ }
195
+ return; // abort: nothing left to release
196
+ }
197
+ // The helper can die between the `exited` check and (or during) the
198
+ // stdin write: swallow the stream error (EPIPE would otherwise be an
199
+ // unhandled 'error' event) and never hang on an end-callback that will
200
+ // no longer fire — the authoritative verdict is the exit code below.
201
+ await new Promise((resolve) => {
202
+ let settled = false;
203
+ const settle = () => {
204
+ if (settled)
205
+ return;
206
+ settled = true;
207
+ resolve();
208
+ };
209
+ const stdin = child.stdin;
210
+ stdin.once('error', settle);
211
+ void exit.then(settle);
212
+ try {
213
+ if (committing) {
214
+ stdin.end(payload, settle);
215
+ }
216
+ else {
217
+ stdin.end(settle);
218
+ }
219
+ }
220
+ catch {
221
+ settle();
222
+ }
223
+ });
224
+ const code = await exit;
225
+ if (committing && code !== 0) {
226
+ throw new CleanupJournalError('io', failure);
227
+ }
228
+ };
229
+ return {
230
+ async abort() {
231
+ if (exited)
232
+ return;
233
+ await finish(undefined, '');
234
+ },
235
+ async commit(payload) {
236
+ // Framed envelope: magic/version + declared byte length + SHA-256 of
237
+ // the payload. The helper commits ONLY after both validate exactly, so
238
+ // a parent dying mid-write (partial bytes + clean EOF) can never
239
+ // replace good journal contents with a truncated payload. Frame
240
+ // construction failures release the lock (abort) instead of leaving
241
+ // the helper's stdin open.
242
+ let framed;
243
+ try {
244
+ const body = Buffer.from(payload, 'utf8');
245
+ const digest = createHash('sha256').update(body).digest('hex');
246
+ framed = Buffer.concat([Buffer.from(`ARJL1\n${body.byteLength}\n${digest}\n`, 'utf8'), body]);
247
+ }
248
+ catch (err) {
249
+ await finish(undefined, '');
250
+ throw new CleanupJournalError('io', `Could not frame the pending-cleanup journal payload: ${err instanceof Error ? err.message : String(err)}`);
251
+ }
252
+ await finish(framed, `The journal-lock helper was lost before the pending-cleanup journal at ${journalFile} could be committed; the journal was left unmodified.`);
253
+ },
254
+ };
255
+ }
256
+ /** File-backed CleanupJournal in the project data dir. Paths resolve per call.
257
+ * `dataDirOverride` exists for tests only — production callers use the default. */
258
+ export function fileCleanupJournal(dataDirOverride) {
259
+ const journalFile = () => path.join(dataDirOverride ?? getProjectPaths().dataDir, 'pending-cleanups.json');
260
+ const read = (file) => {
261
+ let raw;
262
+ try {
263
+ raw = fs.readFileSync(file, 'utf8');
264
+ }
265
+ catch (err) {
266
+ if (err.code === 'ENOENT')
267
+ return [];
268
+ throw new CleanupJournalError('io', `Could not read the pending-cleanup journal at ${file}: ${err instanceof Error ? err.message : String(err)}`);
269
+ }
270
+ return parseEntries(raw, file);
271
+ };
272
+ return {
273
+ async list() {
274
+ return read(journalFile());
275
+ },
276
+ async update(mutate) {
277
+ const file = journalFile();
278
+ fs.mkdirSync(path.dirname(file), { recursive: true });
279
+ const transaction = await beginJournalTransaction(`${file}.lock`, file);
280
+ // EVERYTHING that can throw before the commit — the read, the mutator,
281
+ // and the serialization itself — runs inside the abort-protected block,
282
+ // or a failure would leave the helper's stdin open and the lock held
283
+ // until this process exits.
284
+ let payload;
285
+ try {
286
+ const next = await mutate(read(file));
287
+ payload = `${JSON.stringify(next)}\n`;
288
+ }
289
+ catch (err) {
290
+ await transaction.abort();
291
+ throw err;
292
+ }
293
+ // The helper performs the durable replacement (temp + fsync + atomic
294
+ // rename + dir fsync) while it still holds the kernel lock.
295
+ await transaction.commit(payload);
296
+ },
297
+ };
298
+ }
299
+ //# sourceMappingURL=integration-cleanup-journal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-cleanup-journal.js","sourceRoot":"","sources":["../../../src/cli/commands/integration-cleanup-journal.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  import type { Command } from 'commander';
2
+ import { type CleanupJournal } from './integration-cleanup-journal.js';
2
3
  import { type SdkCommandDeps } from '../lib/sdk-command.js';
4
+ import type { SdkClientOptions } from '../lib/sdk-client.js';
3
5
  import { MIN_RELAYFILE_VERSION, assertRelayfileVersion, type RelayfileClientOptions } from '@relayfile/client';
4
6
  export { MIN_RELAYFILE_VERSION, assertRelayfileVersion };
5
7
  export interface LocalRelayOptions {
@@ -12,6 +14,11 @@ export interface RelayfileBinding {
12
14
  channel: string;
13
15
  webhookId: string;
14
16
  subscriptionId: string;
17
+ /** relayfile-cloud subscription that forwards provider records to the inbound webhook. */
18
+ webhookSubscriptionId?: string;
19
+ /** Workspace that subscription was created in — pins cleanup deletes across
20
+ * active-workspace switches. */
21
+ webhookSubscriptionWorkspaceId?: string;
15
22
  }
16
23
  export interface RelayfileResolvedResource {
17
24
  /** Canonical VFS path glob relayfile stores the binding under (begins with '/'). */
@@ -24,10 +31,15 @@ export interface RelayfileWritebackBinding {
24
31
  url: string;
25
32
  /** Per-channel HMAC secret the subscription signs deliveries with. */
26
33
  secret: string;
34
+ /** Workspace that resolved this binding (daemons >= relayfile#346) — the
35
+ * pre-create workspace pin for the cleanup journal. */
36
+ workspaceId?: string;
27
37
  }
28
38
  export interface RelayfileWebhookSubscription {
29
39
  subscriptionId: string;
30
40
  secret?: string;
41
+ /** Workspace the subscription was created in (daemons >= relayfile#346). */
42
+ workspaceId?: string;
31
43
  }
32
44
  export interface RelayfileBridge {
33
45
  isConnected(provider: string): Promise<boolean>;
@@ -39,6 +51,8 @@ export interface RelayfileBridge {
39
51
  webhookId: string;
40
52
  webhookToken: string;
41
53
  subscriptionId: string;
54
+ webhookSubscriptionId: string;
55
+ webhookSubscriptionWorkspaceId?: string;
42
56
  }): Promise<void>;
43
57
  listBindings(): Promise<RelayfileBinding[]>;
44
58
  unbind(provider: string, resource: string): Promise<void>;
@@ -69,12 +83,29 @@ export interface RelayfileBridge {
69
83
  url: string;
70
84
  pathGlobs: string[];
71
85
  secret: string;
86
+ /** Pins the create to the pre-resolved workspace, so the created
87
+ * subscription can never land in a workspace other than the one already
88
+ * journaled in the attempt record. */
89
+ workspace?: string;
72
90
  }): Promise<RelayfileWebhookSubscription>;
73
- deleteWebhookSubscription(subscriptionId: string): Promise<void>;
91
+ /** `workspace` pins the delete to the workspace the subscription was
92
+ * created in, guarding against active-workspace switches between runs. */
93
+ deleteWebhookSubscription(subscriptionId: string, workspace?: string): Promise<void>;
94
+ /** Lists a workspace's inbound webhook subscriptions so crash-recovery can
95
+ * find subscriptions whose server-assigned id was never persisted. */
96
+ listWebhookSubscriptions: (workspace?: string) => Promise<{
97
+ workspaceId?: string;
98
+ subscriptions: Array<{
99
+ subscriptionId: string;
100
+ url: string;
101
+ pathGlobs: string[];
102
+ }>;
103
+ }>;
74
104
  }
75
105
  export type IntegrationCommandDependencies = SdkCommandDeps & {
76
106
  resolveLocalRelayOptions: () => Promise<LocalRelayOptions | undefined>;
77
107
  relayfile: RelayfileBridge;
108
+ cleanupJournal: CleanupJournal;
78
109
  isInteractive: () => boolean;
79
110
  prompt: (question: string) => Promise<string>;
80
111
  };
@@ -86,5 +117,36 @@ export type IntegrationCommandDependencies = SdkCommandDeps & {
86
117
  * field/method drift is a typed error, not a silent runtime surprise.
87
118
  */
88
119
  export declare function defaultRelayfileBridge(options?: RelayfileClientOptions): RelayfileBridge;
120
+ /**
121
+ * Non-secret identity of the relay connection a journal entry may retry
122
+ * through. The workspace key is a credential, so it is run through a
123
+ * purpose-domain PBKDF2 (never a bare hash — CodeQL
124
+ * js/insufficient-password-hash) with the base URL as the salt domain; only
125
+ * the derived digest is ever stored.
126
+ */
127
+ export declare function relayCleanupScope(options: SdkClientOptions): string;
128
+ /**
129
+ * Bounded lease window for entry owners, set safely ABOVE every remote
130
+ * request timeout any lifecycle or recovery performs (each spans seconds; a
131
+ * reconciliation at most a few request timeouts). Explicit bounded-lease
132
+ * tradeoff: a process paused (e.g. SIGSTOP) past this window loses its
133
+ * lease and a rival may proceed — accepted deliberately, because the
134
+ * alternative (pure pid probing) lets PID reuse wedge lifecycles FOREVER.
135
+ */
136
+ /**
137
+ * Lease timing knobs, exported as one mutable object ONLY so tests can run
138
+ * deterministic renewal scenarios with tiny windows; production code never
139
+ * mutates it. renewalMs sits well below leaseMs so an active lifecycle
140
+ * refreshes its lease several times per window.
141
+ */
142
+ export declare const OWNER_LEASE_CONFIG: {
143
+ leaseMs: number;
144
+ renewalMs: number;
145
+ /** Tolerated forward clock skew. A heartbeat further in the FUTURE than
146
+ * this is malformed or from a skewed clock and counts as expired —
147
+ * otherwise a finite future value (e.g. 9e15) would make its owner live
148
+ * forever and unbound the lease again. */
149
+ skewMs: number;
150
+ };
89
151
  export declare function registerIntegrationCommands(program: Command, overrides?: Partial<IntegrationCommandDependencies>): void;
90
152
  //# sourceMappingURL=integration.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/integration.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/integration.ts"],"names":[],"mappings":"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"}