@paneui/cli 0.0.4 → 0.0.6

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.
@@ -1,25 +1,29 @@
1
- // `pane logout` — clear the locally-saved relay URL + API key.
1
+ // `pane agent logout` — clear the locally-saved relay URL + API key.
2
+ import { assertKnownFlags } from "../argv.js";
2
3
  import { clearStore } from "../store.js";
3
4
  import { printJson } from "../output.js";
4
- export const logoutHelp = `pane logout — clear the saved relay URL + API key
5
+ const NO_FLAGS = [];
6
+ const NO_BOOLS = [];
7
+ export const logoutHelp = `pane agent logout — clear the saved relay URL + API key
5
8
 
6
9
  Usage:
7
- pane logout [options]
10
+ pane agent logout [options]
8
11
 
9
12
  Deletes the CLI config file (\${XDG_CONFIG_HOME:-~/.config}/pane/config.json),
10
- which holds the relay URL and the agent API key saved by 'pane register'.
13
+ which holds the relay URL and the agent API key saved by 'pane agent register'.
11
14
  Idempotent — no error if there is nothing to clear.
12
15
 
13
16
  This only clears the LOCAL config. It does NOT revoke the key on the relay —
14
17
  the key keeps working until it is revoked. To revoke it on the relay, use
15
- 'pane keys revoke'.
18
+ 'pane key revoke'.
16
19
 
17
20
  Options:
18
21
  -h, --help Show this help.
19
22
 
20
23
  Output (stdout, JSON):
21
24
  { cleared: true, path }`;
22
- export async function runLogout() {
25
+ export async function runLogout(args) {
26
+ assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "pane agent logout");
23
27
  const path = clearStore();
24
28
  printJson({ cleared: true, path });
25
29
  }
@@ -0,0 +1,137 @@
1
+ // `pane session participant <new|revoke>` — mint or invalidate one
2
+ // participant URL on an existing session. Recovery + leak-containment
3
+ // primitives that together replace the destructive `pane session delete +
4
+ // pane session create` workaround for the lost-URL case.
5
+ //
6
+ // This file is a sub-noun dispatcher under `pane session`. The session
7
+ // dispatcher hands us a ParsedArgs whose positionals[0] is "participant"
8
+ // (our sub-noun marker), so we read the verb from positionals[1] and the
9
+ // args from positionals[2..]. This mirrors the way every other sub-verb
10
+ // runner (runState, runDelete, ...) reads positionals[0] as its first arg
11
+ // after a single shift.
12
+ import { assertKnownFlags } from "../argv.js";
13
+ import { makeClient } from "../config.js";
14
+ import { printJson, fail, failFromError } from "../output.js";
15
+ const NO_FLAGS = [];
16
+ const NO_BOOLS = [];
17
+ export const participantHelp = `pane session participant — manage one session's participant URLs
18
+
19
+ Participant tokens are stored hashed on the relay and CANNOT be recovered.
20
+ If you lost the create-response (and the URL with it), use 'new' to mint a
21
+ fresh URL — the session keeps its event log, artifact pin, and created_at.
22
+ Use 'revoke' to invalidate a single URL while keeping the session alive.
23
+
24
+ Usage:
25
+ pane session participant <verb> <args>
26
+
27
+ Verbs:
28
+ list <session-id> List the participants on one session, including
29
+ revoked rows (for audit). Returns
30
+ { session_id, items: [...] } where each item
31
+ carries { participant_id, kind, token_prefix,
32
+ joined_at, revoked_at }. Use this to find the
33
+ participant_id you need to pass to 'revoke'.
34
+
35
+ new <session-id> Mint a fresh human URL on an existing session.
36
+ Returns { participant_id, kind, token, url,
37
+ created_at } — ONCE. The plaintext token is
38
+ never recoverable; save the response (pipe to
39
+ a JSONL log) before delivering the URL.
40
+
41
+ revoke <session-id> <participant-id>
42
+ Invalidate one participant URL. The session's
43
+ other participants (and the agent's own
44
+ websocket) are untouched. Idempotent: running
45
+ revoke twice still returns success.
46
+ Note: existing WebSocket connections held
47
+ under the revoked token are NOT actively
48
+ kicked in v1; new HTTP and WS connections
49
+ under that token will fail with 404.
50
+
51
+ Options:
52
+ --url <url> Relay base URL (overrides PANE_URL).
53
+ --api-key <key> Agent API key (overrides PANE_API_KEY).
54
+ -h, --help Show this help.
55
+
56
+ Recovery recipe:
57
+ pane session list # find session_id
58
+ pane session participant list <session-id> # find participant
59
+ # ids on that
60
+ # session
61
+ pane session participant new <session-id> # mint a new URL
62
+ pane session participant revoke <session-id> <p-id> # invalidate the
63
+ # old URL
64
+
65
+ Output: stdout is machine-readable JSON.`;
66
+ async function runParticipantList(args) {
67
+ assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "pane session participant list");
68
+ const sessionId = args.positionals[1];
69
+ if (!sessionId) {
70
+ fail("missing <session-id> — usage: pane session participant list <session-id>", "invalid_args");
71
+ }
72
+ const client = makeClient(args);
73
+ try {
74
+ const res = await client.listParticipants(sessionId);
75
+ printJson(res);
76
+ }
77
+ catch (e) {
78
+ failFromError(e);
79
+ }
80
+ }
81
+ async function runParticipantNew(args) {
82
+ assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "pane session participant new");
83
+ const sessionId = args.positionals[1];
84
+ if (!sessionId) {
85
+ fail("missing <session-id> — usage: pane session participant new <session-id>", "invalid_args");
86
+ }
87
+ const client = makeClient(args);
88
+ try {
89
+ const res = await client.mintParticipant(sessionId);
90
+ printJson(res);
91
+ }
92
+ catch (e) {
93
+ failFromError(e);
94
+ }
95
+ }
96
+ async function runParticipantRevoke(args) {
97
+ assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "pane session participant revoke");
98
+ const sessionId = args.positionals[1];
99
+ const participantId = args.positionals[2];
100
+ if (!sessionId || !participantId) {
101
+ fail("missing arguments — usage: pane session participant revoke <session-id> <participant-id>", "invalid_args");
102
+ }
103
+ const client = makeClient(args);
104
+ try {
105
+ await client.revokeParticipant(sessionId, participantId);
106
+ printJson({
107
+ session_id: sessionId,
108
+ participant_id: participantId,
109
+ revoked: true,
110
+ });
111
+ }
112
+ catch (e) {
113
+ failFromError(e);
114
+ }
115
+ }
116
+ export async function runParticipant(args) {
117
+ // positionals[0] is the verb (list | new | revoke), positionals[1..] are
118
+ // the verb's args. (The session.ts dispatcher already shifted off the
119
+ // "participant" marker before calling us.)
120
+ const verb = args.positionals[0];
121
+ switch (verb) {
122
+ case "list":
123
+ await runParticipantList(args);
124
+ break;
125
+ case "new":
126
+ await runParticipantNew(args);
127
+ break;
128
+ case "revoke":
129
+ await runParticipantRevoke(args);
130
+ break;
131
+ case undefined:
132
+ fail("missing verb — usage: pane session participant <list|new|revoke> (run 'pane session participant --help')", "invalid_args");
133
+ break;
134
+ default:
135
+ fail(`unknown participant verb '${verb}' — expected list|new|revoke (run 'pane session participant --help')`, "invalid_args");
136
+ }
137
+ }
@@ -1,4 +1,4 @@
1
- // `pane register` — self-provision an agent API key from the relay.
1
+ // `pane agent register` — self-provision an agent API key from the relay.
2
2
  //
3
3
  // This is the one command that needs no API key: it is the call that obtains
4
4
  // one. If the relay runs REGISTRATION_MODE=secret, pass the shared
@@ -6,14 +6,17 @@
6
6
  // (and relay URL) are persisted to the CLI config file, so every later command
7
7
  // works with only PANE_URL (or nothing) set.
8
8
  import { registerAgent, PaneApiError } from "@paneui/core";
9
+ import { assertKnownFlags } from "../argv.js";
9
10
  import { DEFAULT_RELAY_URL } from "../config.js";
10
11
  import { printJson, fail, failUpgradeRequired } from "../output.js";
11
12
  import { readStore, writeStore } from "../store.js";
12
13
  import { VERSION } from "../version.js";
13
- export const registerHelp = `pane register — register this agent with the relay and save the key locally
14
+ const KNOWN_FLAGS = ["name", "secret"];
15
+ const KNOWN_BOOLS = ["print-key"];
16
+ export const registerHelp = `pane agent register — register this agent with the relay and save the key locally
14
17
 
15
18
  Usage:
16
- pane register [options]
19
+ pane agent register [options]
17
20
 
18
21
  Calls POST /v1/register, then saves the returned API key (and relay URL) to the
19
22
  CLI config file — so afterwards every other command works with only PANE_URL
@@ -36,6 +39,7 @@ Output (stdout, JSON):
36
39
  The API key is saved to the CLI config file (mode 0600); it is not printed
37
40
  unless --print-key is passed.`;
38
41
  export async function runRegister(args) {
42
+ assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane agent register");
39
43
  const store = readStore();
40
44
  const url = args.flags.get("url") ??
41
45
  process.env.PANE_URL ??
@@ -56,7 +60,7 @@ export async function runRegister(args) {
56
60
  if (e instanceof PaneApiError) {
57
61
  // 426 cli_upgrade_required goes through the shared upgrade-message
58
62
  // path (stderr block + exit 75) so the SKILL.md's instructions to the
59
- // agent's harness fire on `pane register` too.
63
+ // agent's harness fire on `pane agent register` too.
60
64
  if (e.status === 426 && e.code === "cli_upgrade_required") {
61
65
  failUpgradeRequired(e);
62
66
  }
@@ -1,11 +1,17 @@
1
- // `pane send <id>` — append an agent event to a session.
1
+ // `pane session send <id>` — append an agent event to a session.
2
+ import { readFileSync } from "node:fs";
3
+ import { basename } from "node:path";
4
+ import { assertKnownFlags } from "../argv.js";
2
5
  import { makeClient } from "../config.js";
3
6
  import { resolveJson } from "../input.js";
4
7
  import { printJson, fail, failFromError } from "../output.js";
5
- export const sendHelp = `pane send emit an agent event into a session
8
+ const KNOWN_FLAGS = ["type", "data", "blob", "causation-id", "idempotency-key"];
9
+ const KNOWN_BOOLS = [];
10
+ export const sendHelp = `pane session send — emit an agent event into a session
6
11
 
7
12
  Usage:
8
- pane send <session-id> --type <event-type> --data <path|json> [options]
13
+ pane session send <session-id> --type <event-type> --data <path|json> [options]
14
+ pane session send <session-id> --type <event-type> --blob <file-path> [options]
9
15
 
10
16
  POSTs an event to /v1/sessions/:id/events. The event is stamped as authored by
11
17
  the agent (the relay derives identity from the API key — it cannot be spoofed).
@@ -16,6 +22,12 @@ Required:
16
22
  --data <v> Event payload: a file path to a .json file, or inline
17
23
  JSON. Use --data 'null' or --data '{}' for no payload.
18
24
 
25
+ ALTERNATIVE to --data:
26
+ --blob <path> One-shot: upload <path> as a session-scope blob, then
27
+ send an event whose payload is the BlobRef. The event
28
+ data is { blob: <BlobRef> }; declare it in your event
29
+ schema with \`format: pane-blob-id\` on \`blob.blob_id\`.
30
+
19
31
  Options:
20
32
  --causation-id <id> Opaque causation id stored verbatim on the event.
21
33
  --idempotency-key <k> Dedup key — a repeat send with the same key is a no-op.
@@ -26,6 +38,7 @@ Options:
26
38
  Output (stdout, JSON):
27
39
  { event, deduped }`;
28
40
  export async function runSend(args) {
41
+ assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane session send");
29
42
  const sessionId = args.positionals[0];
30
43
  if (!sessionId)
31
44
  fail("missing <session-id>", "invalid_args");
@@ -33,8 +46,44 @@ export async function runSend(args) {
33
46
  if (!type)
34
47
  fail("missing --type", "invalid_args");
35
48
  const dataRaw = args.flags.get("data");
36
- if (dataRaw === undefined)
37
- fail("missing --data", "invalid_args");
49
+ const blobPath = args.flags.get("blob");
50
+ if (dataRaw !== undefined && blobPath !== undefined) {
51
+ fail("--data and --blob are mutually exclusive", "invalid_args");
52
+ }
53
+ if (dataRaw === undefined && blobPath === undefined) {
54
+ fail("missing --data or --blob", "invalid_args");
55
+ }
56
+ const client = makeClient(args);
57
+ // --blob path: upload the file as a session-scope blob, then send an
58
+ // event whose data is { blob: <BlobRef> }. The session's event schema
59
+ // is expected to declare a blob field with format: pane-blob-id.
60
+ if (blobPath !== undefined) {
61
+ let bytes;
62
+ try {
63
+ bytes = readFileSync(blobPath);
64
+ }
65
+ catch (e) {
66
+ fail(`failed to read --blob '${blobPath}': ${e instanceof Error ? e.message : String(e)}`, "invalid_args");
67
+ }
68
+ try {
69
+ const ref = await client.uploadBlob(bytes, {
70
+ scope: "session",
71
+ sessionId: sessionId,
72
+ filename: basename(blobPath),
73
+ });
74
+ const res = await client.sendEvent(sessionId, {
75
+ type: type,
76
+ data: { blob: ref },
77
+ causationId: args.flags.get("causation-id"),
78
+ idempotencyKey: args.flags.get("idempotency-key"),
79
+ });
80
+ printJson(res);
81
+ }
82
+ catch (e) {
83
+ failFromError(e);
84
+ }
85
+ return;
86
+ }
38
87
  let data;
39
88
  try {
40
89
  data = resolveJson(dataRaw, "--data");
@@ -42,7 +91,6 @@ export async function runSend(args) {
42
91
  catch (e) {
43
92
  fail(e instanceof Error ? e.message : String(e), "invalid_args");
44
93
  }
45
- const client = makeClient(args);
46
94
  try {
47
95
  const res = await client.sendEvent(sessionId, {
48
96
  type: type,
@@ -0,0 +1,118 @@
1
+ // `pane session` — the central noun of pane: open, observe, send to, and
2
+ // close a session.
3
+ //
4
+ // A session is one *use* of an artifact: an open URL the human(s) interact
5
+ // with, plus an event log the agent reads and appends to. Every other noun
6
+ // (artifact, blob, key, taste, feedback) exists in service of sessions.
7
+ //
8
+ // This file is a thin dispatcher — each verb's actual logic lives in its own
9
+ // file (create.ts, state.ts, send.ts, watch.ts, delete.ts). The verb runners
10
+ // expect the session id at positionals[0]; we slice off our own verb before
11
+ // delegating so they don't need to know they're being called via `session`.
12
+ import { runCreate } from "./create.js";
13
+ import { runState } from "./state.js";
14
+ import { runSend } from "./send.js";
15
+ import { runWatch } from "./watch.js";
16
+ import { runDelete } from "./delete.js";
17
+ import { runList, listHelp } from "./list.js";
18
+ import { runParticipant, participantHelp } from "./participant.js";
19
+ import { fail } from "../output.js";
20
+ export const sessionHelp = `pane session — open, observe, send to, and close sessions
21
+
22
+ A session is one use of an artifact: an open URL the human(s) interact with,
23
+ plus an event log the agent reads and appends to.
24
+
25
+ Usage:
26
+ pane session <verb> [options]
27
+
28
+ Verbs:
29
+ create Create a session (POST /v1/sessions). Prints session_id,
30
+ urls, tokens, expires_at.
31
+ list Enumerate YOUR agent's sessions. The recovery primitive
32
+ for "I dropped the create response" — sessions are
33
+ listable, but participant tokens are stored hashed and
34
+ CANNOT be recovered. Use 'participant new' to mint a
35
+ fresh URL.
36
+ show <id> Non-blocking snapshot: session metadata + event log.
37
+ Supports --wait <secs> for relay-side long-polling.
38
+ send <id> Emit an agent event into a session.
39
+ watch <id> Stream a session's events as JSON-lines on stdout
40
+ (long-lived; the building block for pipe-readers).
41
+ delete <id> Close/delete a session (DELETE /v1/sessions/:id).
42
+ participant List / mint / revoke participant URLs on an existing
43
+ <list|new|revoke> session. 'list' returns the participant ids you need
44
+ for 'revoke'; 'new' replaces the destructive 'delete
45
+ + recreate' workaround for a lost URL; 'revoke'
46
+ invalidates one URL without touching the session.
47
+
48
+ Run \`pane session <verb> --help\` for verb-specific options.`;
49
+ /**
50
+ * Build a new ParsedArgs with the leading positional (the verb) stripped.
51
+ * The downstream verb runners (runState / runSend / runWatch / runDelete)
52
+ * read the session id at positionals[0], so we hand them an args object that
53
+ * looks exactly like the pre-restructure invocation.
54
+ */
55
+ function shiftPositionals(args) {
56
+ // Propagate danglingValueFlags too — otherwise the leaf runner's
57
+ // assertKnownFlags can't tell that the user wrote `--title` without a
58
+ // value, and falls through to a less-useful downstream error.
59
+ const out = {
60
+ positionals: args.positionals.slice(1),
61
+ flags: args.flags,
62
+ bools: args.bools,
63
+ };
64
+ if (args.danglingValueFlags !== undefined) {
65
+ out.danglingValueFlags = args.danglingValueFlags;
66
+ }
67
+ return out;
68
+ }
69
+ export async function runSession(args) {
70
+ const verb = args.positionals[0];
71
+ // `pane session participant --help` (verb-level help on the participant
72
+ // sub-noun, with no further sub-verb). The general --help pre-empt in
73
+ // index.ts only fires when no positional follows the noun; here a
74
+ // positional ("participant") is present, so the sub-noun must own its own
75
+ // --help routing.
76
+ if (verb === "participant" &&
77
+ args.bools.has("help") &&
78
+ args.positionals.length === 1) {
79
+ process.stdout.write(participantHelp + "\n");
80
+ return;
81
+ }
82
+ // `pane session list --help` — same pattern.
83
+ if (verb === "list" &&
84
+ args.bools.has("help") &&
85
+ args.positionals.length === 1) {
86
+ process.stdout.write(listHelp + "\n");
87
+ return;
88
+ }
89
+ const inner = shiftPositionals(args);
90
+ switch (verb) {
91
+ case "create":
92
+ await runCreate(inner);
93
+ break;
94
+ case "list":
95
+ await runList(inner);
96
+ break;
97
+ case "show":
98
+ await runState(inner);
99
+ break;
100
+ case "send":
101
+ await runSend(inner);
102
+ break;
103
+ case "watch":
104
+ await runWatch(inner);
105
+ break;
106
+ case "delete":
107
+ await runDelete(inner);
108
+ break;
109
+ case "participant":
110
+ await runParticipant(inner);
111
+ break;
112
+ case undefined:
113
+ fail("missing verb — usage: pane session <create|list|show|send|watch|delete|participant> (run 'pane session --help')", "invalid_args");
114
+ break;
115
+ default:
116
+ fail(`unknown session verb '${verb}' — expected create|list|show|send|watch|delete|participant (run 'pane session --help')`, "invalid_args");
117
+ }
118
+ }
@@ -7,37 +7,41 @@
7
7
  // agent always reads what the relay it's actually talking to wants it
8
8
  // to read.
9
9
  //
10
- // Two subcommands:
11
- // `pane skill` — print the full markdown to stdout (the
10
+ // Two verbs:
11
+ // `pane skill show` — print the full markdown to stdout (the
12
12
  // install / refresh path; pipe to a file).
13
13
  // `pane skill version` — print just the relay's skill version (the
14
14
  // "is my local copy stale?" probe). The agent
15
15
  // compares this to the `<!-- pane skill v… -->`
16
16
  // comment in its local skill file and re-runs
17
- // `pane skill > <path>` when they differ.
17
+ // `pane skill show > <path>` when they differ.
18
18
  //
19
19
  // Both are unauthenticated — the skill route is public on the relay and
20
20
  // an agent on a too-old CLI must be able to read the upgrade instructions
21
21
  // even before it has registered (or before its key was minted).
22
+ import { assertKnownFlags } from "../argv.js";
22
23
  import { resolveRelayUrl } from "../config.js";
23
24
  import { fail } from "../output.js";
25
+ const NO_FLAGS = [];
26
+ const NO_BOOLS = [];
27
+ const VERSION_BOOLS = ["plain"];
24
28
  import { VERSION } from "../version.js";
25
29
  export const skillHelp = `pane skill — fetch the relay's SKILL.md (or its version)
26
30
 
27
31
  Usage:
28
- pane skill Print the full skill to stdout.
32
+ pane skill show Print the full skill to stdout.
29
33
  pane skill version [--plain] Print just the relay's skill version.
30
34
 
31
35
  The skill is auto-updating: the relay's deployed image owns the version,
32
36
  so this is always the skill that matches the relay you are talking to.
33
37
 
34
38
  Unauthenticated — no API key needed. An agent can call either form
35
- before 'pane register' to bootstrap or refresh its local skill copy.
39
+ before 'pane agent register' to bootstrap or refresh its local skill copy.
36
40
 
37
- Subcommands:
38
- (bare) Fetch GET /skills/pane/SKILL.md and write the raw
41
+ Verbs:
42
+ show Fetch GET /skills/pane/SKILL.md and write the raw
39
43
  markdown to stdout. Pipe to your local skill path:
40
- pane skill > ~/.claude/skills/pane/SKILL.md
44
+ pane skill show > ~/.claude/skills/pane/SKILL.md
41
45
  version Fetch GET /skills/pane/SKILL.md/version and print
42
46
  the relay's skill version. Default output is the
43
47
  JSON envelope; --plain prints just the version
@@ -78,8 +82,9 @@ async function failOnNon2xx(res, target) {
78
82
  const body = await res.text().catch(() => "");
79
83
  fail(`relay returned ${res.status} for ${target}${body ? ": " + body.slice(0, 200) : ""}`, "relay_error");
80
84
  }
81
- // `pane skill` (no positional) — print the full skill.
85
+ // `pane skill show` — print the full skill.
82
86
  async function runSkillFetch(args) {
87
+ assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "pane skill show");
83
88
  const url = resolveRelayUrl(args);
84
89
  const target = url + "/skills/pane/SKILL.md";
85
90
  const res = await fetchOrFail(target);
@@ -94,6 +99,7 @@ async function runSkillFetch(args) {
94
99
  }
95
100
  // `pane skill version [--plain]` — print just the version.
96
101
  async function runSkillVersion(args) {
102
+ assertKnownFlags(args, NO_FLAGS, VERSION_BOOLS, "pane skill version");
97
103
  const url = resolveRelayUrl(args);
98
104
  const target = url + "/skills/pane/SKILL.md/version";
99
105
  const res = await fetchOrFail(target);
@@ -124,13 +130,16 @@ async function runSkillVersion(args) {
124
130
  export async function runSkill(args) {
125
131
  const sub = args.positionals[0];
126
132
  switch (sub) {
127
- case undefined:
133
+ case "show":
128
134
  await runSkillFetch(args);
129
135
  break;
130
136
  case "version":
131
137
  await runSkillVersion(args);
132
138
  break;
139
+ case undefined:
140
+ fail("missing verb — usage: pane skill <show|version> (run 'pane skill --help')", "invalid_args");
141
+ break;
133
142
  default:
134
- fail(`unknown skill subcommand '${sub}' — expected 'version' or no subcommand (run 'pane skill --help')`, "invalid_args");
143
+ fail(`unknown skill verb '${sub}' — expected show|version (run 'pane skill --help')`, "invalid_args");
135
144
  }
136
145
  }
@@ -1,10 +1,13 @@
1
- // `pane state <id>` — snapshot of a session, optionally long-polled.
1
+ // `pane session show <id>` — snapshot of a session, optionally long-polled.
2
+ import { assertKnownFlags } from "../argv.js";
2
3
  import { makeClient } from "../config.js";
3
4
  import { printJson, fail, failFromError } from "../output.js";
4
- export const stateHelp = `pane state — show a session's metadata and event log
5
+ const KNOWN_FLAGS = ["since", "wait"];
6
+ const KNOWN_BOOLS = [];
7
+ export const stateHelp = `pane session show — show a session's metadata and event log
5
8
 
6
9
  Usage:
7
- pane state <session-id> [options]
10
+ pane session show <session-id> [options]
8
11
 
9
12
  By default non-blocking: fetches session metadata (GET /v1/sessions/:id) plus
10
13
  the event log (GET /v1/sessions/:id/events) and prints them together.
@@ -13,8 +16,8 @@ With --wait, blocks at the relay for up to <secs> if no new events are
13
16
  available since the cursor — returns as soon as something lands. Use this
14
17
  for headless polling agents that can't keep a WebSocket open (cron,
15
18
  FaaS, slow links): poll, then re-poll using next_cursor as --since on the
16
- next call. Compared to 'pane watch', it's higher latency per round-trip
17
- but no long-lived connection.
19
+ next call. Compared to 'pane session watch', it's higher latency per
20
+ round-trip but no long-lived connection.
18
21
 
19
22
  Options:
20
23
  --since <cursor> Only return events after this opaque cursor. Pass
@@ -31,6 +34,7 @@ Options:
31
34
  Output (stdout, JSON):
32
35
  { meta, events, next_cursor }`;
33
36
  export async function runState(args) {
37
+ assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane session show");
34
38
  const sessionId = args.positionals[0];
35
39
  if (!sessionId)
36
40
  fail("missing <session-id>", "invalid_args");