shadok-ai 0.13.12 → 0.13.14

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/README.md CHANGED
@@ -359,6 +359,41 @@ every 25s (tunable with `SHADOK_WS_PING_MS`) to keep the connection warm, so no
359
359
  proxy change is normally needed; if your proxy still cuts it, raise
360
360
  `proxy_read_timeout` above the ping interval.
361
361
 
362
+ ### Cross-instance peers
363
+
364
+ Agents can spawn and drive agents on **another** instance — another of yours, or
365
+ a teammate's. It is opt-in and gated like an account.
366
+
367
+ On the instance being reached (call it **B**), an admin **invites an agent** —
368
+ in the **Users** panel, exactly like inviting a person, except the invitee is a
369
+ machine so it gets a **prompt to paste** instead of a login link. Give it a name
370
+ and, optionally, a brief (what you want it to do); B mints a named, revocable
371
+ credential and hands you a ready-to-paste block: the cockpit URL, the key, the
372
+ brief, and the commands to join. Copy it into whatever agent you're inviting.
373
+
374
+ (The same thing over the API: `POST /peers {name, brief}` returns
375
+ `{ name, token, invitePrompt }` — the token is shown once.)
376
+
377
+ On the calling instance **A**, the invited agent registers B and drives it with
378
+ `pilotctl --peer` (the pasted prompt spells this out):
379
+
380
+ ```bash
381
+ pilotctl peer add B https://B <token>
382
+ pilotctl spawn --peer B --profile dev --cwd /workspace
383
+ pilotctl prompt <id> "run the migration" --peer B
384
+ pilotctl diff <id> --peer B
385
+ ```
386
+
387
+ The token is a **non-expiring, revocable** credential (an HMAC of the peer name;
388
+ `DELETE /peers?name=instance-a` on B kills it immediately — future calls **and**
389
+ the live link). A peer is **scoped to the agents it creates**: it can never see,
390
+ resume, drive or diff B's other agents, nor reach B's vault, profiles or crons.
391
+
392
+ **This is remote code execution by a third party** — a peer that can `spawn`
393
+ runs commands on B's machine. It is a deliberate admin grant, and a container per
394
+ instance stays the real boundary (see *Exposing it beyond this machine*). Manage
395
+ peers only for instances you trust to that degree.
396
+
362
397
  ### Signing in to Claude
363
398
 
364
399
  A fresh machine — most often a fresh container — has two things in its way, and
@@ -113,10 +113,36 @@ time, and the information comes to you.
113
113
  `--parent none` spawns an agent deliberately unattached; `--parent <id>`
114
114
  attaches it elsewhere.
115
115
 
116
+ ## Driving agents on ANOTHER instance (`--peer`)
117
+
118
+ You can spawn and drive agents on a **different** shadok instance — another one
119
+ of your own, or a teammate's — over an authenticated link. Add `--peer <alias>`
120
+ **after the command** (like `--profile`/`--cwd`) and it runs against that
121
+ instance instead of this one:
122
+
123
+ ```
124
+ pilotctl peer add brasdroit1 https://brasdroit1.example.com <token> # once
125
+ pilotctl spawn --peer brasdroit1 --profile dev --cwd /workspace # spawn there
126
+ pilotctl prompt <id> "run the migration" --peer brasdroit1 # drive it
127
+ pilotctl diff <id> --peer brasdroit1 # read its work
128
+ pilotctl stop <id> --peer brasdroit1
129
+ ```
130
+
131
+ - The **token** is minted by the REMOTE instance's admin (a human, in its
132
+ cockpit — `POST /peers`). Paste it in once with `peer add`; it is kept in a
133
+ 600 file, `peer list` never prints it. You cannot mint your own — that is the
134
+ point: the other instance decides who may reach it.
135
+ - A peer is **scoped to the agents it creates**: `--peer X` can only resume /
136
+ drive / diff / stop agents YOU spawned on X, never its other agents. A refusal
137
+ comes back as `peer-scope`.
138
+ - `list` is not available over `--peer` (a peer sees only its own agents) — track
139
+ the ids you `spawn` and drive them by id.
140
+
116
141
  ## Guardrails
117
142
 
118
143
  - NEVER `stop` a session this conversation did not create: it may belong to the
119
- user in the web UI. `stop` ends the session for all its clients.
144
+ user in the web UI. `stop` ends the session for all its clients. (Over `--peer`
145
+ the server enforces this for you: you can only touch your own remote agents.)
120
146
  - Every agent consumes the Claude quota like an ordinary session. Do not
121
147
  multiply agents without an explicit request from the user.
122
148
  - `prompt` on a session whose turn is already running → the error "a response is
@@ -30,8 +30,45 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
30
30
  export const REPO_ROOT = path.resolve(__dirname, "..", "..", "..");
31
31
 
32
32
  export const port = () => Number(process.env.SHADOK_PORT ?? 3789);
33
- export const httpBase = () => `http://localhost:${port()}`;
34
- export const wsUrl = () => `ws://localhost:${port()}/ws`;
33
+
34
+ // A REMOTE peer to target for this command, set from `--peer <alias>` (or
35
+ // `--peer-url`/`--peer-token`). When set, every call goes to the peer's URL and
36
+ // authenticates with `x-shadok-peer` instead of the local session key — an agent
37
+ // on THIS instance driving an agent on ANOTHER. Null = the local server, as ever.
38
+ let PEER = null; // { url, token }
39
+ export function setPeer(p) { PEER = p; }
40
+
41
+ export const httpBase = () => (PEER ? PEER.url : `http://localhost:${port()}`);
42
+ export const wsUrl = () =>
43
+ PEER ? PEER.url.replace(/^http/, "ws") + "/ws" : `ws://localhost:${port()}/ws`;
44
+
45
+ // The per-instance outbound-peers file the server hands us as SHADOK_PEERS_FILE
46
+ // (a plain agent's cwd is a worktree, so it cannot derive its launch dir). A
47
+ // hand-run pilotctl with no such env falls back to a machine-global file.
48
+ export const peersFile = () =>
49
+ (process.env.SHADOK_PEERS_FILE || "").trim() ||
50
+ path.join(os.homedir(), ".shadok-ai", "peers-out.json");
51
+ export function loadPeersOut() {
52
+ try {
53
+ const j = JSON.parse(fs.readFileSync(peersFile(), "utf8"));
54
+ return j && typeof j === "object" ? j : {};
55
+ } catch {
56
+ return {};
57
+ }
58
+ }
59
+ export function savePeersOut(map) {
60
+ fs.mkdirSync(path.dirname(peersFile()), { recursive: true });
61
+ const tmp = peersFile() + ".tmp";
62
+ fs.writeFileSync(tmp, JSON.stringify(map, null, 2), { mode: 0o600 });
63
+ fs.renameSync(tmp, peersFile());
64
+ }
65
+ /** Pure: the {url, token} for an alias, or null. Trailing slashes trimmed so
66
+ * `${url}/ws` and `${url}/diff` never double up. */
67
+ export function resolvePeer(peersOut, alias) {
68
+ const p = peersOut && peersOut[alias];
69
+ if (!p || typeof p.url !== "string" || typeof p.token !== "string" || !p.url || !p.token) return null;
70
+ return { url: p.url.replace(/\/+$/, ""), token: p.token };
71
+ }
35
72
  // When a GUI password is set, the server injects SHADOK_AUTH=sk_auth=<token>
36
73
  // into every agent's env; loopback HTTP + WS calls must present it as the cookie
37
74
  // or the password gate 401s them — exactly what secret.py / schedule.py and the
@@ -43,12 +80,17 @@ export const wsUrl = () => `ws://localhost:${port()}/ws`;
43
80
  // session id, verifies for as long as the agent runs, and grants exactly what
44
81
  // the cookie did. Both are sent: the cookie still works, and an older server
45
82
  // that does not know the header simply ignores it.
46
- export const authHeaders = () => ({
47
- ...(process.env.SHADOK_AUTH ? { cookie: process.env.SHADOK_AUTH } : {}),
48
- ...(process.env.SHADOK_SESSION_KEY
49
- ? { "x-shadok-session-key": process.env.SHADOK_SESSION_KEY }
50
- : {}),
51
- });
83
+ export const authHeaders = () =>
84
+ PEER
85
+ ? // Targeting a remote peer: the ONLY credential it accepts is the peer token.
86
+ // Never leak the local cookie/session key to another instance.
87
+ { "x-shadok-peer": PEER.token }
88
+ : {
89
+ ...(process.env.SHADOK_AUTH ? { cookie: process.env.SHADOK_AUTH } : {}),
90
+ ...(process.env.SHADOK_SESSION_KEY
91
+ ? { "x-shadok-session-key": process.env.SHADOK_SESSION_KEY }
92
+ : {}),
93
+ };
52
94
  export const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
53
95
 
54
96
  // The built-in WebSocket is WHATWG (addEventListener + event.data); the rest of
@@ -113,7 +155,10 @@ export function parseArgs(argv) {
113
155
  for (let i = 0; i < rest.length; i++) {
114
156
  const a = rest[i];
115
157
  if (a === "--worktree" || a === "--continue" || a === "--readonly") flags[a.slice(2)] = true;
116
- else if (a === "--cwd" || a === "--resume" || a === "--timeout" || a === "--profile" || a === "--parent") flags[a.slice(2)] = rest[++i];
158
+ else if (
159
+ a === "--cwd" || a === "--resume" || a === "--timeout" || a === "--profile" || a === "--parent" ||
160
+ a === "--peer" || a === "--peer-url" || a === "--peer-token"
161
+ ) flags[a.slice(2)] = rest[++i];
117
162
  else pos.push(a);
118
163
  }
119
164
  return { cmd, pos, flags };
@@ -221,6 +266,10 @@ async function serverUp() {
221
266
  }
222
267
 
223
268
  export async function ensureServer() {
269
+ // Targeting a remote peer (`--peer`): it is someone else's server — never probe
270
+ // or auto-start a local one. If the peer is unreachable the connection fails
271
+ // with a clear error, which is the honest outcome.
272
+ if (PEER) return;
224
273
  if (await serverUp()) return;
225
274
  if (process.env.SHADOK_NO_AUTOSTART)
226
275
  throw new Error(`shadok-ai server unreachable on :${port()}`);
@@ -263,7 +312,10 @@ export async function ensureHolder(id, cwd) {
263
312
  const child = spawnChild(process.execPath, args, {
264
313
  detached: true,
265
314
  stdio: ["ignore", "pipe", "ignore"],
266
- env: process.env,
315
+ // A holder for a REMOTE agent must connect to the peer, not the local server.
316
+ // The detached child gets no `--peer` flag, so carry it in the ENV (never
317
+ // argv — a token in argv is world-readable via `ps`); `run()` reads it back.
318
+ env: PEER ? { ...process.env, SHADOK_PEER_URL: PEER.url, SHADOK_PEER_TOKEN: PEER.token } : process.env,
267
319
  });
268
320
  try {
269
321
  await new Promise((resolve, reject) => {
@@ -504,10 +556,85 @@ async function cmdScreen(id, flags) {
504
556
  }
505
557
 
506
558
  const HELP =
507
- "usage: pilotctl <spawn|prompt|dialog|choose|toggle|confirm|freetext|list|diff|stop|screen|profile-prompt> …";
559
+ "usage: pilotctl <spawn|prompt|dialog|choose|toggle|confirm|freetext|list|diff|stop|screen|profile-prompt|peer> …\n" +
560
+ " add --peer <alias> to any command to run it against another instance's agents\n" +
561
+ " pilotctl peer <add <alias> <url> <ticket> [--token]|list|rm <alias>>";
562
+
563
+ /**
564
+ * Manage the outbound-peers file: aliases → { url, token }.
565
+ *
566
+ * `add` takes the single-use TICKET from the invitation and ENROLS with it: it
567
+ * posts the ticket to the remote `POST /peers/enrol`, which consumes it and
568
+ * returns the durable token stored here. So the credential we keep is one this
569
+ * side obtained itself — the invitation, which gets pasted into a session and
570
+ * lives on in a transcript, only ever held something that dies on first use.
571
+ *
572
+ * A ticket that has already been redeemed, expired or never existed is refused
573
+ * by the remote with one indistinguishable message, and we store NOTHING: a
574
+ * saved credential that does not authenticate is worse than a clear error.
575
+ *
576
+ * `--token` skips the exchange and stores the value as a durable token, for a
577
+ * credential issued some other way. `list` never prints either.
578
+ */
579
+ export async function cmdPeer(pos, flags = {}) {
580
+ const [sub, alias, url, secret] = pos;
581
+ const map = loadPeersOut();
582
+ if (sub === "add") {
583
+ if (!alias || !url || !secret)
584
+ throw new Error("usage: pilotctl peer add <alias> <url> <ticket> [--token]");
585
+ const base = String(url).replace(/\/+$/, "");
586
+ let token = secret;
587
+ if (!flags.token) {
588
+ const r = await fetch(`${base}/peers/enrol`, {
589
+ method: "POST",
590
+ headers: { "content-type": "application/json" },
591
+ body: JSON.stringify({ ticket: secret }),
592
+ });
593
+ const j = await r.json().catch(() => ({}));
594
+ if (!r.ok || !j?.token) throw new Error(j?.error || `enrolment refused (HTTP ${r.status})`);
595
+ token = j.token;
596
+ }
597
+ map[alias] = { url: base, token };
598
+ savePeersOut(map);
599
+ return { ok: true, alias, url: base, enrolled: !flags.token };
600
+ }
601
+ if (sub === "rm") {
602
+ if (!alias) throw new Error("usage: pilotctl peer rm <alias>");
603
+ delete map[alias];
604
+ savePeersOut(map);
605
+ return { ok: true, alias };
606
+ }
607
+ if (sub === "list" || sub === undefined)
608
+ return { peers: Object.entries(map).map(([a, p]) => ({ alias: a, url: p?.url })) };
609
+ throw new Error("usage: pilotctl peer <add|rm|list> …");
610
+ }
508
611
 
509
612
  export async function run(argv) {
510
613
  const { cmd, pos, flags } = parseArgs(argv);
614
+ // Manage the outbound-peers file (local, no server).
615
+ if (cmd === "peer") return cmdPeer(pos, flags);
616
+ // Target a REMOTE peer for this command — every call then goes to its URL with
617
+ // the peer token instead of the local session key. `--peer <alias>` resolves
618
+ // the outbound file; `--peer-url/--peer-token` is a one-off; SHADOK_PEER_URL/
619
+ // _TOKEN in the env is how a detached holder child inherits the peer.
620
+ if (flags.peer || flags["peer-url"] || process.env.SHADOK_PEER_URL) {
621
+ const target = flags["peer-url"]
622
+ ? flags["peer-token"]
623
+ ? { url: flags["peer-url"].replace(/\/+$/, ""), token: flags["peer-token"] }
624
+ : null
625
+ : flags.peer
626
+ ? resolvePeer(loadPeersOut(), flags.peer)
627
+ : process.env.SHADOK_PEER_URL && process.env.SHADOK_PEER_TOKEN
628
+ ? { url: process.env.SHADOK_PEER_URL.replace(/\/+$/, ""), token: process.env.SHADOK_PEER_TOKEN }
629
+ : null;
630
+ if (!target)
631
+ throw new Error(
632
+ flags["peer-url"]
633
+ ? "--peer-url needs a --peer-token"
634
+ : `unknown peer "${flags.peer}" — add it with: pilotctl peer add <alias> <url> <token>`,
635
+ );
636
+ setPeer(target);
637
+ }
511
638
  switch (cmd) {
512
639
  case "spawn":
513
640
  return cmdSpawn(flags);
@@ -44,6 +44,12 @@ export interface Channel {
44
44
  * blink, chime). Client-owned like `name`/`group`, stored here so the mute
45
45
  * survives a reload and follows the user's other devices. */
46
46
  muted?: boolean;
47
+ /** The PEER (another instance/harness) that spawned this agent, when a remote
48
+ * party created it via `x-shadok-peer`. A peer is scoped to agents it created,
49
+ * so this is the ownership key: only that peer may resume/drive/diff it, and
50
+ * this instance's admin sees who is driving what. Server-owned; absent for a
51
+ * locally-spawned agent. See `src/peers.ts`. */
52
+ createdByPeer?: string;
47
53
  }
48
54
  /**
49
55
  * Should this channel be mirrored into Telegram?
@@ -1 +1 @@
1
- {"version":3,"file":"channels.js","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"channels.js","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * PEERS — other instances (or harnesses) allowed to reach THIS one's agents.
3
+ *
4
+ * A peer is the cross-instance twin of a web account (`accounts.ts`), and it
5
+ * enrols the same way: named, revocable, per launch dir, and reached through a
6
+ * **single-use ticket** that is CONSUMED on first use, exactly as a user's
7
+ * invitation link is. What the invitee keeps afterwards is a durable token it
8
+ * obtained itself — so the long-lived credential never travels through an
9
+ * invitation, a chat, or an invitee's transcript.
10
+ *
11
+ * Two properties are load-bearing, and the first one was missing at first.
12
+ *
13
+ * The token is salted PER PEER. It used to be `hmac(secret, "peer:"+name)`,
14
+ * which is deterministic: deleting a row revoked the token, but re-adding a peer
15
+ * under the SAME name minted the identical token again — handing a leaked
16
+ * credential straight back. Revocation was not rotation. The row now carries a
17
+ * random `salt` mixed into the MAC, so re-inviting the same name yields a
18
+ * different token, and the only way to rotate used to be renaming the peer or
19
+ * rotating the instance secret (which is shared with every user session).
20
+ *
21
+ * It stays **non-expiring** once enrolled — a cross-instance link is persistent
22
+ * and must not hit the 7-day cookie cliff — and **revocable by the registry**:
23
+ * verifying requires the name to still be listed here, so deleting the row
24
+ * kills every token for it. See docs/superpowers/specs/2026-09-26-cross-instance-
25
+ * agent-collaboration-design.md.
26
+ *
27
+ * A peer that connects is a DISTINCT principal, scoped by the caller to the
28
+ * agents it created (`Channel.createdByPeer`) — never B's whole fleet.
29
+ */
30
+ /** A pending enrolment: the single-use ticket, and when it stops being usable. */
31
+ export interface PeerInvite {
32
+ ticket: string;
33
+ expiresAt: number;
34
+ }
35
+ export interface Peer {
36
+ name: string;
37
+ createdAt: number;
38
+ note?: string;
39
+ /**
40
+ * Random, per peer, mixed into the token's MAC. Without it the token is a
41
+ * pure function of the name, so revoke-then-re-invite returns the SAME
42
+ * credential — see the note above. Absent on a row written before this
43
+ * existed; `withSalts` backfills one, which invalidates that row's old token
44
+ * (deliberately: a deterministic token is the thing being removed).
45
+ */
46
+ salt?: string;
47
+ /** Present until the ticket is redeemed. While it is here the peer has NOT
48
+ * enrolled, and its durable token does not authenticate anything. */
49
+ invite?: PeerInvite;
50
+ /** When the ticket was redeemed and the durable token handed over. */
51
+ enrolledAt?: number;
52
+ }
53
+ /** How long a ticket stays redeemable. Long enough to reach an agent that is
54
+ * mid-task, short enough that a forgotten invitation is not a standing door. */
55
+ export declare const PEER_INVITE_TTL_MS: number;
56
+ /** INBOUND registry, per launch dir, 600 — peers allowed to reach THIS instance. */
57
+ export declare function peerFileFor(cwd?: string): string;
58
+ /** OUTBOUND registry, per launch dir, 600 — peers THIS instance can reach
59
+ * (`{ alias: { url, token } }`, managed by `pilotctl peer add`). The server
60
+ * hands its path to every agent as SHADOK_PEERS_FILE (twin of the ledger file),
61
+ * since an agent's cwd is a worktree, not the launch dir. Read by the client
62
+ * (pilotctl); the server only needs to compute the path. */
63
+ export declare function peersOutFileFor(cwd?: string): string;
64
+ export declare function loadPeers(file: string): Peer[];
65
+ export declare function savePeers(file: string, peers: Peer[]): void;
66
+ /** A peer name is a slug: lowercased, safe chars, non-empty. null if nothing
67
+ * usable survives — an empty/invalid name must never become a live credential. */
68
+ export declare function normPeerName(name: unknown): string | null;
69
+ /**
70
+ * Pure: add (or supersede) a peer by name, with a FRESH salt and a fresh
71
+ * single-use ticket.
72
+ *
73
+ * Superseding re-rolls the salt on purpose: re-inviting a name is exactly when
74
+ * the old credential must stop working. `salt`/`ticket` are injected so the
75
+ * result is testable; `newPeer` below supplies real randomness.
76
+ */
77
+ export declare function addPeer(peers: Peer[], name: string, now: number, note: string | undefined, salt: string, ticket: string, ttlMs?: number): Peer[];
78
+ /** Impure twin of `addPeer`: draws the salt and the ticket. */
79
+ export declare function newPeer(peers: Peer[], name: string, now: number, note?: string): {
80
+ peers: Peer[];
81
+ ticket: string;
82
+ };
83
+ /**
84
+ * Backfill a salt on any row written before salts existed.
85
+ *
86
+ * Doing this INVALIDATES that row's existing token, and that is the point: the
87
+ * saltless token is the deterministic one being removed. A peer whose token
88
+ * stops working is re-invited; a peer whose leaked token kept working would not
89
+ * know to.
90
+ */
91
+ export declare function withSalts(peers: Peer[], mint?: () => string): Peer[];
92
+ export type RedeemVerdict = {
93
+ ok: true;
94
+ name: string;
95
+ } | {
96
+ ok: false;
97
+ error: string;
98
+ };
99
+ /**
100
+ * Pure: may this ticket be redeemed right now?
101
+ *
102
+ * Refuses an unknown, an expired and an ALREADY-REDEEMED ticket with the same
103
+ * wording on purpose. Redemption deletes the ticket, so a used one and an
104
+ * invented one are indistinguishable from here — and saying which would tell a
105
+ * guesser that a ticket once existed. Same reasoning as the user invitation's
106
+ * "this link is no longer valid".
107
+ */
108
+ export declare function redeemVerdict(peers: readonly Peer[], ticket: unknown, now: number): RedeemVerdict;
109
+ /** Pure: consume the ticket — the row stays (that is the peer), the invitation
110
+ * goes. This is what makes the ticket single-use. */
111
+ export declare function redeemPeer(peers: readonly Peer[], name: string, now: number): Peer[];
112
+ /** Pure: drop a peer by name (revocation). */
113
+ export declare function removePeer(peers: Peer[], name: string): Peer[];
114
+ /**
115
+ * The peer token: `<b64url(name)>.<hmac("peer:"+b64+":"+salt)>`, twin of
116
+ * `signSessionKey` but SALTED per peer — see the note at the top of this file.
117
+ */
118
+ export declare function signPeerToken(name: string, secret: Buffer, salt: string): string;
119
+ /** Pure: the name a token CLAIMS, from its first half. Proves nothing on its
120
+ * own — the MAC is checked in `peerFromToken`, which needs the row's salt. */
121
+ export declare function peerTokenName(token: unknown): string | null;
122
+ /**
123
+ * The peer a token authenticates, or null.
124
+ *
125
+ * Three conditions, and each one is a different refusal:
126
+ * - the name is still in the registry — deleting the row is the revocation;
127
+ * - that row has ENROLLED (no pending invite left). A durable token for a peer
128
+ * that never redeemed its ticket authenticates nothing, which is what keeps
129
+ * the ticket the only way in;
130
+ * - the MAC verifies against THAT ROW's salt, so a token minted before a
131
+ * re-invitation is dead.
132
+ */
133
+ export declare function peerFromToken(token: string, secret: Buffer, peers: readonly Peer[]): string | null;
134
+ /**
135
+ * The ownership rule — a peer may only touch an agent IT created. The single
136
+ * named check behind every peer scope (resume, stop, /diff): a channel with a
137
+ * different `createdByPeer`, or none (a local agent), is NOT this peer's.
138
+ */
139
+ export declare function ownedByPeer(channel: {
140
+ createdByPeer?: string;
141
+ } | undefined, peer: string): boolean;
142
+ /**
143
+ * The copy-paste invitation for an AGENT — the peer equivalent of a user's
144
+ * single-use link, and single-use in the same way. The invitee is an agent, not a
145
+ * human, so instead of a page where it picks a password it gets a PROMPT to paste
146
+ * into its own session: the cockpit URL, a TICKET, the brief, and exactly how to
147
+ * join and report back.
148
+ *
149
+ * It carries the ticket and never the durable token, which is the point: an
150
+ * invitation is copied, pasted and kept in a transcript, so what it holds must
151
+ * be worthless once used.
152
+ * `brief` is the human's task (empty allowed). Pure so the wording is tested.
153
+ */
154
+ export declare function agentInvitePrompt(opts: {
155
+ url: string;
156
+ ticket: string;
157
+ brief?: string;
158
+ }): string;