@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.
- package/README.md +21 -15
- package/dist/argv.js +95 -7
- package/dist/commands/agent.js +41 -0
- package/dist/commands/artifact.js +31 -4
- package/dist/commands/blob-delete.js +37 -0
- package/dist/commands/blob-download.js +49 -0
- package/dist/commands/blob-list.js +50 -0
- package/dist/commands/blob-show.js +37 -0
- package/dist/commands/blob-token.js +133 -0
- package/dist/commands/blob-upload.js +79 -0
- package/dist/commands/blob.js +135 -0
- package/dist/commands/config.js +26 -7
- package/dist/commands/create.js +78 -12
- package/dist/commands/delete.js +7 -3
- package/dist/commands/feedback.js +6 -0
- package/dist/commands/{keys.js → key.js} +23 -17
- package/dist/commands/list.js +91 -0
- package/dist/commands/logout.js +10 -6
- package/dist/commands/participant.js +137 -0
- package/dist/commands/register.js +8 -4
- package/dist/commands/send.js +54 -6
- package/dist/commands/session.js +118 -0
- package/dist/commands/skill.js +20 -11
- package/dist/commands/state.js +9 -5
- package/dist/commands/taste.js +36 -19
- package/dist/commands/watch.js +10 -6
- package/dist/config.js +4 -4
- package/dist/index.js +85 -80
- package/dist/input.js +2 -2
- package/dist/output.js +1 -1
- package/dist/store.js +2 -2
- package/dist/version.js +1 -1
- package/package.json +4 -4
package/dist/commands/logout.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
}
|
package/dist/commands/send.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
37
|
-
|
|
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
|
+
}
|
package/dist/commands/skill.js
CHANGED
|
@@ -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
|
|
11
|
-
// `pane skill`
|
|
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
|
|
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
|
-
|
|
38
|
-
|
|
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`
|
|
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
|
|
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
|
|
143
|
+
fail(`unknown skill verb '${sub}' — expected show|version (run 'pane skill --help')`, "invalid_args");
|
|
135
144
|
}
|
|
136
145
|
}
|
package/dist/commands/state.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
// `pane
|
|
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
|
-
|
|
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
|
|
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
|
|
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");
|