@paneui/cli 0.0.6 → 0.0.7

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
@@ -34,12 +34,12 @@ Uniform `pane <noun> <verb> [options]`:
34
34
  ```
35
35
  pane agent register Provision an agent API key and save it locally
36
36
  pane agent logout Clear the locally-saved URL + API key
37
- pane session create Create a session — returns session_id, urls, tokens
38
- pane session show <id> Non-blocking snapshot: metadata + event log
39
- pane session send <id> Emit an agent event into a session
40
- pane session watch <id> Stream a session's events as JSON-lines on stdout
41
- pane session delete <id> Close / delete a session
42
- pane artifact <verb> Manage reusable, versioned artifacts
37
+ pane surface create Create a surface — returns surface_id, urls, tokens
38
+ pane surface show <id> Non-blocking snapshot: metadata + event log
39
+ pane surface send <id> Emit an agent event into a surface
40
+ pane surface watch <id> Stream a surface's events as JSON-lines on stdout
41
+ pane surface delete <id> Close / delete a surface
42
+ pane template <verb> Manage reusable, versioned templates
43
43
  pane key list | revoke Inspect or revoke your agent's API key
44
44
  pane taste get | set | clear Read / write / clear UI-taste notes
45
45
  pane feedback create | list Submit / list one-shot feedback to the operator
@@ -56,12 +56,12 @@ stdout is machine-readable JSON. Errors go to stderr as
56
56
  `{"error":{"code","message"}}` with a non-zero exit.
57
57
 
58
58
  ```sh
59
- SESSION=$(pane session create --template form --schema ./q.json | jq -r .session_id)
60
- pane session watch "$SESSION" | jq 'select(.type == "human_response")'
59
+ SESSION=$(pane surface create --template form --schema ./q.json | jq -r .surface_id)
60
+ pane surface watch "$SESSION" | jq 'select(.type == "human_response")'
61
61
  ```
62
62
 
63
63
  ## Links
64
64
 
65
65
  - Repo: <https://github.com/aerolalit/paneui>
66
- - Spec: <https://github.com/aerolalit/paneui/blob/main/docs/SPEC.md>
66
+ - Spec: <https://github.com/aerolalit/paneui/attachment/main/docs/SPEC.md>
67
67
  - License: MIT
@@ -9,6 +9,7 @@
9
9
  // logout.ts.
10
10
  import { runRegister } from "./register.js";
11
11
  import { runLogout } from "./logout.js";
12
+ import { runClaim } from "./claim.js";
12
13
  import { fail } from "../output.js";
13
14
  export const agentHelp = `pane agent — manage this agent's identity on the relay
14
15
 
@@ -18,24 +19,36 @@ Usage:
18
19
  Verbs:
19
20
  register Provision an agent API key (POST /v1/register) and save it
20
21
  to the CLI config file. Run this once before other commands.
22
+ claim <code> Bind this agent to a human via a one-shot claim code the
23
+ human generated in their Settings UI (POST /v1/agents/claim).
24
+ One-way; no unclaim in v1.
21
25
  logout Clear the locally-saved relay URL + API key. Does NOT
22
26
  revoke the key on the relay — use 'pane key revoke' for
23
27
  that.
24
28
 
25
29
  Run \`pane agent <verb> --help\` for verb-specific options.`;
26
30
  export async function runAgent(args) {
31
+ // Strip the first positional (the verb) so each verb runner sees its
32
+ // own arguments at positionals[0..n].
33
+ const verbArgs = {
34
+ ...args,
35
+ positionals: args.positionals.slice(1),
36
+ };
27
37
  const verb = args.positionals[0];
28
38
  switch (verb) {
29
39
  case "register":
30
- await runRegister(args);
40
+ await runRegister(verbArgs);
41
+ break;
42
+ case "claim":
43
+ await runClaim(verbArgs);
31
44
  break;
32
45
  case "logout":
33
- await runLogout(args);
46
+ await runLogout(verbArgs);
34
47
  break;
35
48
  case undefined:
36
- fail("missing verb — usage: pane agent <register|logout> (run 'pane agent --help')", "invalid_args");
49
+ fail("missing verb — usage: pane agent <register|claim|logout> (run 'pane agent --help')", "invalid_args");
37
50
  break;
38
51
  default:
39
- fail(`unknown agent verb '${verb}' — expected register|logout (run 'pane agent --help')`, "invalid_args");
52
+ fail(`unknown agent verb '${verb}' — expected register|claim|logout (run 'pane agent --help')`, "invalid_args");
40
53
  }
41
54
  }
@@ -0,0 +1,37 @@
1
+ // `pane attachment delete <attachment-id>` — soft-delete a attachment.
2
+ import { assertKnownFlags } from "../argv.js";
3
+ import { makeClient } from "../config.js";
4
+ import { fail, failFromError, printJson } from "../output.js";
5
+ const KNOWN_FLAGS = [];
6
+ const KNOWN_BOOLS = [];
7
+ export const blobDeleteHelp = `pane attachment delete — soft-delete a attachment
8
+
9
+ Usage:
10
+ pane attachment delete <attachment-id> [options]
11
+
12
+ Marks the attachment as deleted (DELETE /v1/attachments/:id). Idempotent: deleting an
13
+ already-deleted attachment still returns success. Tokens minted against this attachment
14
+ become unusable.
15
+
16
+ Options:
17
+ --url <url> Relay base URL (overrides PANE_URL).
18
+ --api-key <key> Agent API key (overrides PANE_API_KEY).
19
+ -h, --help Show this help.
20
+
21
+ Output (stdout, JSON):
22
+ { attachment_id, deleted: true }`;
23
+ export async function runBlobDelete(args) {
24
+ assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane attachment delete");
25
+ const attachmentId = args.positionals[0];
26
+ if (!attachmentId) {
27
+ fail("missing <attachment-id> — 'pane attachment delete <attachment-id>'", "invalid_args");
28
+ }
29
+ const client = makeClient(args);
30
+ try {
31
+ const r = await client.deleteBlob(attachmentId);
32
+ printJson({ attachment_id: attachmentId, ...r });
33
+ }
34
+ catch (e) {
35
+ failFromError(e);
36
+ }
37
+ }
@@ -1,16 +1,16 @@
1
- // `pane blob download <blob-id>` — fetch blob bytes by id.
1
+ // `pane attachment download <attachment-id>` — fetch attachment bytes by id.
2
2
  import { writeFileSync } from "node:fs";
3
3
  import { assertKnownFlags } from "../argv.js";
4
4
  import { makeClient } from "../config.js";
5
5
  import { fail, failFromError, printJson } from "../output.js";
6
6
  const KNOWN_FLAGS = ["out"];
7
7
  const KNOWN_BOOLS = [];
8
- export const blobDownloadHelp = `pane blob download — fetch a blob's bytes
8
+ export const blobDownloadHelp = `pane attachment download — fetch a attachment's bytes
9
9
 
10
10
  Usage:
11
- pane blob download <blob-id> [--out <path>] [options]
11
+ pane attachment download <attachment-id> [--out <path>] [options]
12
12
 
13
- GETs the blob bytes. With --out <path> the bytes are written to that file and
13
+ GETs the attachment bytes. With --out <path> the bytes are written to that file and
14
14
  a JSON summary is printed on stdout; without --out the bytes are written to
15
15
  stdout verbatim (useful for piping into another tool — but binary on a TTY
16
16
  is rarely useful).
@@ -23,20 +23,24 @@ Options:
23
23
 
24
24
  Output:
25
25
  Without --out: raw bytes to stdout.
26
- With --out: { blob_id, written: <path>, bytes: <n> } to stdout.`;
26
+ With --out: { attachment_id, written: <path>, bytes: <n> } to stdout.`;
27
27
  export async function runBlobDownload(args) {
28
- assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane blob download");
29
- const blobId = args.positionals[0];
30
- if (!blobId) {
31
- fail("missing <blob-id> — 'pane blob download <blob-id>'", "invalid_args");
28
+ assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane attachment download");
29
+ const attachmentId = args.positionals[0];
30
+ if (!attachmentId) {
31
+ fail("missing <attachment-id> — 'pane attachment download <attachment-id>'", "invalid_args");
32
32
  }
33
33
  const out = args.flags.get("out");
34
34
  const client = makeClient(args);
35
35
  try {
36
- const buf = await client.downloadBlob(blobId);
36
+ const buf = await client.downloadBlob(attachmentId);
37
37
  if (out) {
38
38
  writeFileSync(out, Buffer.from(buf));
39
- printJson({ blob_id: blobId, written: out, bytes: buf.byteLength });
39
+ printJson({
40
+ attachment_id: attachmentId,
41
+ written: out,
42
+ bytes: buf.byteLength,
43
+ });
40
44
  }
41
45
  else {
42
46
  // Binary to stdout — useful for piping into another tool.
@@ -1,19 +1,19 @@
1
- // `pane blob list` — enumerate YOUR agent's blobs.
1
+ // `pane attachment list` — enumerate YOUR agent's attachments.
2
2
  //
3
- // Lists blobs owned by the calling agent, newest first. Soft-deleted blobs
4
- // are excluded; tokens are not enumerated here (use 'pane blob token list
5
- // <blob-id>' for that).
3
+ // Lists attachments owned by the calling agent, newest first. Soft-deleted attachments
4
+ // are excluded; tokens are not enumerated here (use 'pane attachment token list
5
+ // <attachment-id>' for that).
6
6
  import { assertKnownFlags } from "../argv.js";
7
7
  import { makeClient } from "../config.js";
8
8
  import { fail, printJson, failFromError } from "../output.js";
9
9
  const KNOWN_FLAGS = ["cursor", "limit"];
10
10
  const KNOWN_BOOLS = [];
11
- export const blobListHelp = `pane blob list — enumerate YOUR agent's blobs
11
+ export const blobListHelp = `pane attachment list — enumerate YOUR agent's attachments
12
12
 
13
13
  Usage:
14
- pane blob list [--cursor <token>] [--limit <n>] [options]
14
+ pane attachment list [--cursor <token>] [--limit <n>] [options]
15
15
 
16
- Returns the agent's non-deleted blobs (newest first). Paginated via opaque
16
+ Returns the agent's non-deleted attachments (newest first). Paginated via opaque
17
17
  cursor: when next_cursor is non-null in the response, pass it back as
18
18
  --cursor to get the next page.
19
19
 
@@ -26,9 +26,9 @@ Options:
26
26
  -h, --help Show this help.
27
27
 
28
28
  Output (stdout, JSON):
29
- { items: BlobRef[], next_cursor: string | null }`;
29
+ { items: AttachmentRef[], next_cursor: string | null }`;
30
30
  export async function runBlobList(args) {
31
- assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane blob list");
31
+ assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane attachment list");
32
32
  const cursor = args.flags.get("cursor");
33
33
  const limitRaw = args.flags.get("limit");
34
34
  let limit;
@@ -1,16 +1,16 @@
1
- // `pane blob show <blob-id>` — print a blob's metadata.
1
+ // `pane attachment show <attachment-id>` — print a attachment's metadata.
2
2
  import { assertKnownFlags } from "../argv.js";
3
3
  import { makeClient } from "../config.js";
4
4
  import { fail, failFromError, printJson } from "../output.js";
5
5
  const KNOWN_FLAGS = [];
6
6
  const KNOWN_BOOLS = [];
7
- export const blobShowHelp = `pane blob show — print a blob's metadata (no bytes)
7
+ export const blobShowHelp = `pane attachment show — print a attachment's metadata (no bytes)
8
8
 
9
9
  Usage:
10
- pane blob show <blob-id> [options]
10
+ pane attachment show <attachment-id> [options]
11
11
 
12
- Looks up the blob by id and prints its BlobRef metadata — owner, scope,
13
- mime, size, sha256, etc. Does NOT download the bytes; use 'pane blob
12
+ Looks up the attachment by id and prints its AttachmentRef metadata — owner, scope,
13
+ mime, size, sha256, etc. Does NOT download the bytes; use 'pane attachment
14
14
  download' for that.
15
15
 
16
16
  Options:
@@ -19,16 +19,16 @@ Options:
19
19
  -h, --help Show this help.
20
20
 
21
21
  Output (stdout, JSON):
22
- BlobRef`;
22
+ AttachmentRef`;
23
23
  export async function runBlobShow(args) {
24
- assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane blob show");
25
- const blobId = args.positionals[0];
26
- if (!blobId) {
27
- fail("missing <blob-id> — 'pane blob show <blob-id>'", "invalid_args");
24
+ assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane attachment show");
25
+ const attachmentId = args.positionals[0];
26
+ if (!attachmentId) {
27
+ fail("missing <attachment-id> — 'pane attachment show <attachment-id>'", "invalid_args");
28
28
  }
29
29
  const client = makeClient(args);
30
30
  try {
31
- const ref = await client.getBlob(blobId);
31
+ const ref = await client.getBlob(attachmentId);
32
32
  printJson(ref);
33
33
  }
34
34
  catch (e) {
@@ -1,16 +1,16 @@
1
- // `pane blob token <mint|revoke|list>` — capability URLs for a blob.
1
+ // `pane attachment token <mint|revoke|list>` — capability URLs for a attachment.
2
2
  //
3
- // A capability URL (/b/<token>) is a participant-facing way to fetch a blob
4
- // without holding the agent's API key. Tokens are minted per-blob, can be
3
+ // A capability URL (/b/<token>) is a participant-facing way to fetch a attachment
4
+ // without holding the agent's API key. Tokens are minted per-attachment, can be
5
5
  // time-bound (--ttl) and/or single-use (--once), and are stored hashed on
6
6
  // the relay — the plaintext token is returned ONCE on 'mint' and cannot be
7
7
  // recovered.
8
8
  //
9
- // This file is a sub-noun dispatcher under `pane blob`. The blob dispatcher
9
+ // This file is a sub-noun dispatcher under `pane attachment`. The attachment dispatcher
10
10
  // hands us a ParsedArgs whose positionals[0] is "token" (our sub-noun
11
11
  // marker), so we read the verb from positionals[1] and the args from
12
12
  // positionals[2..]. Mirrors how participant.ts dispatches under `pane
13
- // session participant`.
13
+ // surface participant`.
14
14
  import { assertKnownFlags } from "../argv.js";
15
15
  import { makeClient } from "../config.js";
16
16
  import { fail, failFromError, printJson } from "../output.js";
@@ -18,31 +18,31 @@ const MINT_FLAGS = ["ttl"];
18
18
  const MINT_BOOLS = ["once"];
19
19
  const NO_FLAGS = [];
20
20
  const NO_BOOLS = [];
21
- export const blobTokenHelp = `pane blob token — manage a blob's capability URLs
21
+ export const blobTokenHelp = `pane attachment token — manage a attachment's capability URLs
22
22
 
23
23
  Capability URLs let a participant (or any browser holding the URL) fetch a
24
- blob without the agent's API key. Tokens are stored HASHED on the relay; the
24
+ attachment without the agent's API key. Tokens are stored HASHED on the relay; the
25
25
  plaintext token is returned only ONCE from 'mint' — save the response before
26
26
  delivering the URL.
27
27
 
28
28
  Usage:
29
- pane blob token <verb> <args>
29
+ pane attachment token <verb> <args>
30
30
 
31
31
  Verbs:
32
- mint <blob-id> Mint a /b/<token> capability URL for one blob.
32
+ mint <attachment-id> Mint a /b/<token> capability URL for one attachment.
33
33
  Optional: --ttl <seconds> (defaults by scope:
34
- 30d artifact / session TTL / 24h agent; the caller
34
+ 30d template / surface TTL / 24h agent; the caller
35
35
  can only shorten), --once (token self-deletes on
36
36
  first successful GET). Returns { token, url,
37
37
  expires_at, ... } — ONCE.
38
38
 
39
- revoke <blob-id> <token-id>
39
+ revoke <attachment-id> <token-id>
40
40
  Invalidate one previously-minted token by id.
41
41
  Idempotent: revoking twice still returns success.
42
42
 
43
- list <blob-id> Enumerate the tokens minted against one blob,
43
+ list <attachment-id> Enumerate the tokens minted against one attachment,
44
44
  including revoked rows (for audit). Returns
45
- { blob_id, items: [...] } where each item carries
45
+ { attachment_id, items: [...] } where each item carries
46
46
  { token_id, token_prefix, expires_at, once,
47
47
  created_at, last_used_at, use_count, revoked_at }.
48
48
  The token plaintext is NEVER returned.
@@ -56,10 +56,10 @@ Options:
56
56
 
57
57
  Output: stdout is machine-readable JSON.`;
58
58
  async function runBlobTokenMint(args) {
59
- assertKnownFlags(args, MINT_FLAGS, MINT_BOOLS, "pane blob token mint");
60
- const blobId = args.positionals[1];
61
- if (!blobId) {
62
- fail("missing <blob-id> — 'pane blob token mint <blob-id>'", "invalid_args");
59
+ assertKnownFlags(args, MINT_FLAGS, MINT_BOOLS, "pane attachment token mint");
60
+ const attachmentId = args.positionals[1];
61
+ if (!attachmentId) {
62
+ fail("missing <attachment-id> — 'pane attachment token mint <attachment-id>'", "invalid_args");
63
63
  }
64
64
  const ttlRaw = args.flags.get("ttl");
65
65
  const ttl = ttlRaw === undefined ? undefined : Number(ttlRaw);
@@ -68,7 +68,7 @@ async function runBlobTokenMint(args) {
68
68
  }
69
69
  const client = makeClient(args);
70
70
  try {
71
- const r = await client.mintBlobToken(blobId, {
71
+ const r = await client.mintBlobToken(attachmentId, {
72
72
  ttlSeconds: ttl,
73
73
  once: args.bools.has("once"),
74
74
  });
@@ -79,15 +79,15 @@ async function runBlobTokenMint(args) {
79
79
  }
80
80
  }
81
81
  async function runBlobTokenRevoke(args) {
82
- assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "pane blob token revoke");
83
- const blobId = args.positionals[1];
82
+ assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "pane attachment token revoke");
83
+ const attachmentId = args.positionals[1];
84
84
  const tokenId = args.positionals[2];
85
- if (!blobId || !tokenId) {
86
- fail("missing arguments — 'pane blob token revoke <blob-id> <token-id>'", "invalid_args");
85
+ if (!attachmentId || !tokenId) {
86
+ fail("missing arguments — 'pane attachment token revoke <attachment-id> <token-id>'", "invalid_args");
87
87
  }
88
88
  const client = makeClient(args);
89
89
  try {
90
- const r = await client.revokeBlobToken(blobId, tokenId);
90
+ const r = await client.revokeBlobToken(attachmentId, tokenId);
91
91
  printJson(r);
92
92
  }
93
93
  catch (e) {
@@ -95,14 +95,14 @@ async function runBlobTokenRevoke(args) {
95
95
  }
96
96
  }
97
97
  async function runBlobTokenList(args) {
98
- assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "pane blob token list");
99
- const blobId = args.positionals[1];
100
- if (!blobId) {
101
- fail("missing <blob-id> — 'pane blob token list <blob-id>'", "invalid_args");
98
+ assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "pane attachment token list");
99
+ const attachmentId = args.positionals[1];
100
+ if (!attachmentId) {
101
+ fail("missing <attachment-id> — 'pane attachment token list <attachment-id>'", "invalid_args");
102
102
  }
103
103
  const client = makeClient(args);
104
104
  try {
105
- const r = await client.listBlobTokens(blobId);
105
+ const r = await client.listBlobTokens(attachmentId);
106
106
  printJson(r);
107
107
  }
108
108
  catch (e) {
@@ -111,7 +111,7 @@ async function runBlobTokenList(args) {
111
111
  }
112
112
  export async function runBlobToken(args) {
113
113
  // positionals[0] is the verb (mint | revoke | list), positionals[1..] are
114
- // the verb's args. (The blob.ts dispatcher already shifted off the "token"
114
+ // the verb's args. (The attachment.ts dispatcher already shifted off the "token"
115
115
  // marker before calling us.)
116
116
  const verb = args.positionals[0];
117
117
  switch (verb) {
@@ -125,9 +125,9 @@ export async function runBlobToken(args) {
125
125
  await runBlobTokenList(args);
126
126
  break;
127
127
  case undefined:
128
- fail("missing verb — usage: pane blob token <mint|revoke|list> (run 'pane blob token --help')", "invalid_args");
128
+ fail("missing verb — usage: pane attachment token <mint|revoke|list> (run 'pane attachment token --help')", "invalid_args");
129
129
  break;
130
130
  default:
131
- fail(`unknown token verb '${verb}' — expected mint|revoke|list (run 'pane blob token --help')`, "invalid_args");
131
+ fail(`unknown token verb '${verb}' — expected mint|revoke|list (run 'pane attachment token --help')`, "invalid_args");
132
132
  }
133
133
  }
@@ -1,4 +1,4 @@
1
- // `pane blob upload` — POST /v1/blobs (multipart), three scopes.
1
+ // `pane attachment upload` — POST /v1/attachments (multipart), three scopes.
2
2
  import { readFileSync } from "node:fs";
3
3
  import { basename } from "node:path";
4
4
  import { assertKnownFlags } from "../argv.js";
@@ -7,24 +7,24 @@ import { fail, failFromError, printJson } from "../output.js";
7
7
  const KNOWN_FLAGS = [
8
8
  "file",
9
9
  "scope",
10
- "session-id",
11
- "artifact-id",
10
+ "surface-id",
11
+ "template-id",
12
12
  "filename",
13
13
  "mime",
14
14
  ];
15
15
  const KNOWN_BOOLS = [];
16
- export const blobUploadHelp = `pane blob upload — upload a local file as a blob
16
+ export const blobUploadHelp = `pane attachment upload — upload a local file as a attachment
17
17
 
18
18
  Usage:
19
- pane blob upload --file <path> [options]
19
+ pane attachment upload --file <path> [options]
20
20
 
21
21
  Required:
22
22
  --file <path> Local file to upload.
23
23
 
24
24
  Scope (default: agent):
25
- --scope <s> "agent" | "session" | "artifact".
26
- --session-id <id> Required when --scope=session.
27
- --artifact-id <id> Required when --scope=artifact.
25
+ --scope <s> "agent" | "surface" | "template".
26
+ --surface-id <id> Required when --scope=surface.
27
+ --template-id <id> Required when --scope=template.
28
28
 
29
29
  Optional:
30
30
  --filename <name> Display filename (otherwise basename of --file).
@@ -35,12 +35,12 @@ Optional:
35
35
  -h, --help Show this help.
36
36
 
37
37
  Output (stdout, JSON):
38
- BlobRef — { blob_id, scope, mime, size, sha256, ... }`;
38
+ AttachmentRef — { attachment_id, scope, mime, size, sha256, ... }`;
39
39
  export async function runBlobUpload(args) {
40
- assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane blob upload");
40
+ assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane attachment upload");
41
41
  const filePath = args.flags.get("file");
42
42
  if (!filePath) {
43
- fail("missing --file <path> — 'pane blob upload' requires a local file to upload", "invalid_args");
43
+ fail("missing --file <path> — 'pane attachment upload' requires a local file to upload", "invalid_args");
44
44
  }
45
45
  let bytes;
46
46
  try {
@@ -51,23 +51,23 @@ export async function runBlobUpload(args) {
51
51
  }
52
52
  const scopeRaw = args.flags.get("scope") ?? "agent";
53
53
  if (scopeRaw !== "agent" &&
54
- scopeRaw !== "session" &&
55
- scopeRaw !== "artifact") {
56
- fail(`unknown --scope '${scopeRaw}' — expected one of: agent, session, artifact`, "invalid_args");
54
+ scopeRaw !== "surface" &&
55
+ scopeRaw !== "template") {
56
+ fail(`unknown --scope '${scopeRaw}' — expected one of: agent, surface, template`, "invalid_args");
57
57
  }
58
58
  const scope = scopeRaw;
59
- if (scope === "session" && !args.flags.get("session-id")) {
60
- fail("--scope=session requires --session-id <id>", "invalid_args");
59
+ if (scope === "surface" && !args.flags.get("surface-id")) {
60
+ fail("--scope=surface requires --surface-id <id>", "invalid_args");
61
61
  }
62
- if (scope === "artifact" && !args.flags.get("artifact-id")) {
63
- fail("--scope=artifact requires --artifact-id <id>", "invalid_args");
62
+ if (scope === "template" && !args.flags.get("template-id")) {
63
+ fail("--scope=template requires --template-id <id>", "invalid_args");
64
64
  }
65
65
  const client = makeClient(args);
66
66
  try {
67
67
  const ref = await client.uploadBlob(bytes, {
68
68
  scope,
69
- sessionId: args.flags.get("session-id"),
70
- artifactId: args.flags.get("artifact-id"),
69
+ surfaceId: args.flags.get("surface-id"),
70
+ templateId: args.flags.get("template-id"),
71
71
  filename: args.flags.get("filename") ?? basename(filePath),
72
72
  mime: args.flags.get("mime"),
73
73
  });
@@ -1,77 +1,77 @@
1
- // `pane blob` — manage binary attachments (blobs) on the relay.
1
+ // `pane attachment` — manage binary attachments (attachments) on the relay.
2
2
  //
3
- // A blob is a typed binary file (image, PDF, audio, video, etc.) owned by an
4
- // agent and optionally bound to a session or artifact. Pages reference blobs
5
- // by id with `format: pane-blob-id`; participants can fetch a blob through a
3
+ // A attachment is a typed binary file (image, PDF, audio, video, etc.) owned by an
4
+ // agent and optionally bound to a surface or template. Pages reference attachments
5
+ // by id with `format: pane-attachment-id`; participants can fetch a attachment through a
6
6
  // minted capability URL (/b/<token>) without needing the agent's API key.
7
7
  //
8
8
  // This file is a thin dispatcher — each verb's actual logic lives in its own
9
- // file (blob-upload.ts, blob-download.ts, blob-show.ts, blob-delete.ts) and
10
- // the token sub-noun is dispatched via blob-token.ts.
9
+ // file (attachment-upload.ts, attachment-download.ts, attachment-show.ts, attachment-delete.ts) and
10
+ // the token sub-noun is dispatched via attachment-token.ts.
11
11
  //
12
- // Most blob verbs read their primary positional (the blob_id) at
12
+ // Most attachment verbs read their primary positional (the attachment_id) at
13
13
  // positionals[0]; we slice off our own verb before delegating so each verb
14
- // runner doesn't need to know it was reached through `pane blob`.
15
- import { runBlobUpload, blobUploadHelp } from "./blob-upload.js";
16
- import { runBlobDownload, blobDownloadHelp } from "./blob-download.js";
17
- import { runBlobShow, blobShowHelp } from "./blob-show.js";
18
- import { runBlobList, blobListHelp } from "./blob-list.js";
19
- import { runBlobDelete, blobDeleteHelp } from "./blob-delete.js";
20
- import { runBlobToken, blobTokenHelp } from "./blob-token.js";
14
+ // runner doesn't need to know it was reached through `pane attachment`.
15
+ import { runBlobUpload, blobUploadHelp } from "./attachment-upload.js";
16
+ import { runBlobDownload, blobDownloadHelp } from "./attachment-download.js";
17
+ import { runBlobShow, blobShowHelp } from "./attachment-show.js";
18
+ import { runBlobList, blobListHelp } from "./attachment-list.js";
19
+ import { runBlobDelete, blobDeleteHelp } from "./attachment-delete.js";
20
+ import { runBlobToken, blobTokenHelp } from "./attachment-token.js";
21
21
  import { fail } from "../output.js";
22
- export const blobHelp = `pane blob — manage blobs (binary attachments) on the relay
22
+ export const blobHelp = `pane attachment — manage attachments (binary attachments) on the relay
23
23
 
24
- A blob is a typed binary file (image, PDF, audio, video, ...) the agent has
24
+ A attachment is a typed binary file (image, PDF, audio, video, ...) the agent has
25
25
  uploaded to the relay. Blobs are scoped:
26
26
 
27
- agent — reusable across the agent's sessions (default)
28
- session — bound to one session; deleted with it
29
- artifact — bound to a reusable artifact; deleted with it
27
+ agent — reusable across the agent's surfaces (default)
28
+ surface — bound to one surface; deleted with it
29
+ template — bound to a reusable template; deleted with it
30
30
 
31
- Pages reference blobs by id (the relay's schema validates the id with
32
- \`format: pane-blob-id\`). For a participant-facing URL that bypasses the
33
- agent's API key, mint a token with 'pane blob token mint'.
31
+ Pages reference attachments by id (the relay's schema validates the id with
32
+ \`format: pane-attachment-id\`). For a participant-facing URL that bypasses the
33
+ agent's API key, mint a token with 'pane attachment token mint'.
34
34
 
35
35
  Usage:
36
- pane blob <verb> [options]
36
+ pane attachment <verb> [options]
37
37
 
38
38
  Verbs:
39
39
  upload Upload a local file. Required: --file. Optional:
40
- --scope, --session-id, --artifact-id, --filename,
41
- --mime. Prints { blob_id, scope, mime, size, sha256,
40
+ --scope, --surface-id, --template-id, --filename,
41
+ --mime. Prints { attachment_id, scope, mime, size, sha256,
42
42
  ... }.
43
43
 
44
- download <blob-id> Download a blob by id. Use --out <path> to write a
44
+ download <attachment-id> Download a attachment by id. Use --out <path> to write a
45
45
  file (default: writes to stdout — useful for piping).
46
46
 
47
- show <blob-id> Print a blob's metadata (HEAD-based — doesn't
47
+ show <attachment-id> Print a attachment's metadata (HEAD-based — doesn't
48
48
  download the bytes).
49
49
 
50
- list Enumerate YOUR agent's non-deleted blobs (newest
50
+ list Enumerate YOUR agent's non-deleted attachments (newest
51
51
  first). Supports --cursor + --limit for pagination.
52
52
 
53
- delete <blob-id> Soft-delete a blob. Idempotent.
53
+ delete <attachment-id> Soft-delete a attachment. Idempotent.
54
54
 
55
- token <verb> Capability URLs for a blob (mint | revoke | list).
55
+ token <verb> Capability URLs for a attachment (mint | revoke | list).
56
56
  'mint' returns a /b/<token> URL anyone can GET, with
57
57
  optional --ttl and --once. 'revoke' invalidates one
58
- token. 'list' enumerates a blob's tokens (without
58
+ token. 'list' enumerates a attachment's tokens (without
59
59
  the token plaintext, which is unrecoverable).
60
60
 
61
- Run \`pane blob <verb> --help\` for verb-specific options.
61
+ Run \`pane attachment <verb> --help\` for verb-specific options.
62
62
 
63
63
  Output: stdout is machine-readable JSON. Errors go to stderr as
64
64
  {"error":{"code","message"}} with a non-zero exit.`;
65
65
  /**
66
66
  * Build a new ParsedArgs with the leading positional (the verb) stripped.
67
- * The downstream verb runners read their primary positional (the blob_id)
67
+ * The downstream verb runners read their primary positional (the attachment_id)
68
68
  * at positionals[0], so we hand them an args object that looks exactly like
69
- * they were called directly — mirrors session.ts's shiftPositionals.
69
+ * they were called directly — mirrors surface.ts's shiftPositionals.
70
70
  */
71
71
  function shiftPositionals(args) {
72
72
  // Propagate danglingValueFlags so the leaf runner's assertKnownFlags
73
73
  // can still distinguish "unknown flag" from "missing value" — see the
74
- // matching note in session.ts's shiftPositionals.
74
+ // matching note in surface.ts's shiftPositionals.
75
75
  const out = {
76
76
  positionals: args.positionals.slice(1),
77
77
  flags: args.flags,
@@ -84,7 +84,7 @@ function shiftPositionals(args) {
84
84
  }
85
85
  export async function runBlob(args) {
86
86
  const verb = args.positionals[0];
87
- // `pane blob token --help` (verb-level help on the token sub-noun, with no
87
+ // `pane attachment token --help` (verb-level help on the token sub-noun, with no
88
88
  // further sub-verb). The general --help pre-empt in index.ts only fires
89
89
  // when no positional follows the noun; here a positional ("token") is
90
90
  // present, so the sub-noun must own its own --help routing.
@@ -94,8 +94,8 @@ export async function runBlob(args) {
94
94
  process.stdout.write(blobTokenHelp + "\n");
95
95
  return;
96
96
  }
97
- // `pane blob list --help` — same pattern (list takes no required positional
98
- // so the general pre-empt would already fire, but for parity with session.ts
97
+ // `pane attachment list --help` — same pattern (list takes no required positional
98
+ // so the general pre-empt would already fire, but for parity with surface.ts
99
99
  // we route through here when args carry the "list" positional explicitly).
100
100
  if (verb === "list" &&
101
101
  args.bools.has("help") &&
@@ -124,10 +124,10 @@ export async function runBlob(args) {
124
124
  await runBlobToken(inner);
125
125
  break;
126
126
  case undefined:
127
- fail("missing verb — usage: pane blob <upload|download|show|list|delete|token> (run 'pane blob --help')", "invalid_args");
127
+ fail("missing verb — usage: pane attachment <upload|download|show|list|delete|token> (run 'pane attachment --help')", "invalid_args");
128
128
  break;
129
129
  default:
130
- fail(`unknown blob verb '${verb}' — expected upload|download|show|list|delete|token (run 'pane blob --help')`, "invalid_args");
130
+ fail(`unknown attachment verb '${verb}' — expected upload|download|show|list|delete|token (run 'pane attachment --help')`, "invalid_args");
131
131
  }
132
132
  }
133
133
  // Re-export per-verb helps so tests / docs can import them by canonical name