@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/taste.js
CHANGED
|
@@ -18,8 +18,13 @@
|
|
|
18
18
|
// somewhere else. Today the blob is keyed by the agent's API key (per-agent);
|
|
19
19
|
// when pane gains first-class humans, this may move to per-human.
|
|
20
20
|
import { readFileSync } from "node:fs";
|
|
21
|
+
import { assertKnownFlags } from "../argv.js";
|
|
21
22
|
import { makeClient } from "../config.js";
|
|
22
23
|
import { printJson, fail, failFromError } from "../output.js";
|
|
24
|
+
const NO_FLAGS = [];
|
|
25
|
+
const NO_BOOLS = [];
|
|
26
|
+
const SET_FLAGS = ["file"];
|
|
27
|
+
const CLEAR_BOOLS = ["yes"];
|
|
23
28
|
export const tasteHelp = `pane taste — read / write / clear YOUR agent's UI taste notes
|
|
24
29
|
|
|
25
30
|
Taste notes are a small markdown blob storing presentation preferences your
|
|
@@ -37,16 +42,18 @@ Subcommands:
|
|
|
37
42
|
{ taste: string|null, updated_at: string|null, bytes: number }.
|
|
38
43
|
taste is null and bytes is 0 when notes have never been written.
|
|
39
44
|
|
|
40
|
-
set Whole-blob replace.
|
|
41
|
-
(
|
|
42
|
-
|
|
45
|
+
set Whole-blob replace. Source the markdown via --file <path>,
|
|
46
|
+
--file - (read stdin), or by piping into 'pane taste set' with
|
|
47
|
+
no flag. The relay rejects empty/whitespace-only payloads and
|
|
48
|
+
caps the blob at MAX_TASTE_BYTES (utf8). To clear the notes,
|
|
43
49
|
use 'pane taste clear', not 'set' with an empty body.
|
|
44
50
|
|
|
45
51
|
clear Delete the notes. Requires --yes (it is destructive). Prints
|
|
46
52
|
{ cleared: true }.
|
|
47
53
|
|
|
48
54
|
Options:
|
|
49
|
-
--file <path
|
|
55
|
+
--file <path|-> Source for 'set' — a file path, or '-' to read stdin
|
|
56
|
+
explicitly. Omit to fall back to piped stdin.
|
|
50
57
|
--yes Confirm 'clear'.
|
|
51
58
|
--url <url> Relay base URL (overrides PANE_URL).
|
|
52
59
|
--api-key <key> Agent API key (overrides PANE_API_KEY).
|
|
@@ -54,17 +61,17 @@ Options:
|
|
|
54
61
|
|
|
55
62
|
Examples:
|
|
56
63
|
pane taste get
|
|
57
|
-
echo "- denser layout\\n- no rounded corners" | pane taste set
|
|
58
64
|
pane taste set --file ./taste.md
|
|
65
|
+
pane taste set --file - # explicit stdin
|
|
66
|
+
echo "- denser layout" | pane taste set
|
|
59
67
|
pane taste clear --yes
|
|
60
68
|
|
|
61
69
|
Output: stdout is machine-readable JSON.`;
|
|
62
|
-
// Drain process.stdin to a utf8 string.
|
|
63
|
-
//
|
|
64
|
-
//
|
|
70
|
+
// Drain process.stdin to a utf8 string. The caller is responsible for
|
|
71
|
+
// deciding that stdin should be read (e.g. an explicit `--file -`, or a
|
|
72
|
+
// non-TTY stdin where data is actually piped). In a TTY this would block
|
|
73
|
+
// waiting for ^D, so the caller MUST gate on `process.stdin.isTTY` first.
|
|
65
74
|
async function readStdin() {
|
|
66
|
-
if (process.stdin.isTTY)
|
|
67
|
-
return "";
|
|
68
75
|
const chunks = [];
|
|
69
76
|
for await (const chunk of process.stdin) {
|
|
70
77
|
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
@@ -72,6 +79,7 @@ async function readStdin() {
|
|
|
72
79
|
return Buffer.concat(chunks).toString("utf8");
|
|
73
80
|
}
|
|
74
81
|
async function runTasteGet(args) {
|
|
82
|
+
assertKnownFlags(args, NO_FLAGS, NO_BOOLS, "pane taste get");
|
|
75
83
|
const client = makeClient(args);
|
|
76
84
|
try {
|
|
77
85
|
const info = await client.getTaste();
|
|
@@ -82,16 +90,21 @@ async function runTasteGet(args) {
|
|
|
82
90
|
}
|
|
83
91
|
}
|
|
84
92
|
async function runTasteSet(args) {
|
|
93
|
+
assertKnownFlags(args, SET_FLAGS, NO_BOOLS, "pane taste set");
|
|
85
94
|
const filePath = args.flags.get("file");
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
// Source the blob deterministically — no isTTY-flag fusing, because
|
|
96
|
+
// `!process.stdin.isTTY` is true under every non-interactive caller
|
|
97
|
+
// (pipes, redirects, closed fd, CI, agent harnesses) and would wrongly
|
|
98
|
+
// reject `--file` for the entire target audience. See issue #148.
|
|
99
|
+
//
|
|
100
|
+
// --file - → explicit stdin sentinel
|
|
101
|
+
// --file <path> → read that path (works in TTY and non-TTY alike)
|
|
102
|
+
// (no --file) → fall back to stdin IF non-TTY; error in a TTY
|
|
93
103
|
let taste;
|
|
94
|
-
if (filePath
|
|
104
|
+
if (filePath === "-") {
|
|
105
|
+
taste = await readStdin();
|
|
106
|
+
}
|
|
107
|
+
else if (filePath !== undefined) {
|
|
95
108
|
try {
|
|
96
109
|
taste = readFileSync(filePath, "utf8");
|
|
97
110
|
}
|
|
@@ -99,9 +112,12 @@ async function runTasteSet(args) {
|
|
|
99
112
|
fail(`failed to read --file '${filePath}': ${e instanceof Error ? e.message : String(e)}`, "invalid_args");
|
|
100
113
|
}
|
|
101
114
|
}
|
|
102
|
-
else {
|
|
115
|
+
else if (!process.stdin.isTTY) {
|
|
103
116
|
taste = await readStdin();
|
|
104
117
|
}
|
|
118
|
+
else {
|
|
119
|
+
fail("'pane taste set' needs input — pass --file <path>, pipe markdown on stdin, or use --file -", "invalid_args");
|
|
120
|
+
}
|
|
105
121
|
if (taste.trim().length === 0) {
|
|
106
122
|
fail("'pane taste set' refuses an empty or whitespace-only blob — use 'pane taste clear --yes' to delete the notes", "invalid_args");
|
|
107
123
|
}
|
|
@@ -115,6 +131,7 @@ async function runTasteSet(args) {
|
|
|
115
131
|
}
|
|
116
132
|
}
|
|
117
133
|
async function runTasteClear(args) {
|
|
134
|
+
assertKnownFlags(args, NO_FLAGS, CLEAR_BOOLS, "pane taste clear");
|
|
118
135
|
if (!args.bools.has("yes")) {
|
|
119
136
|
fail("'pane taste clear' deletes YOUR agent's taste notes — it is destructive. Pass --yes to confirm.", "confirmation_required");
|
|
120
137
|
}
|
package/dist/commands/watch.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
// `pane watch <id>` — long-lived: hold a WebSocket and stream events as
|
|
1
|
+
// `pane session watch <id>` — long-lived: hold a WebSocket and stream events as
|
|
2
2
|
// JSON-lines on stdout. This harness-agnostic stdout is the core contract:
|
|
3
3
|
// one compact JSON object per line, flushed after every event, so any
|
|
4
4
|
// pipe-reader (Claude Code's Monitor tool, `while read line`, jq -c, ...)
|
|
5
5
|
// sees each event the instant it lands.
|
|
6
6
|
import { openStream } from "@paneui/core";
|
|
7
|
+
import { assertKnownFlags } from "../argv.js";
|
|
7
8
|
import { resolveConfig } from "../config.js";
|
|
8
9
|
import { PaneClient } from "@paneui/core";
|
|
9
10
|
import { printJsonLine, fail } from "../output.js";
|
|
10
11
|
import { VERSION } from "../version.js";
|
|
11
|
-
|
|
12
|
+
const KNOWN_FLAGS = ["since", "type", "filter-type", "timeout"];
|
|
13
|
+
const KNOWN_BOOLS = ["once"];
|
|
14
|
+
export const watchHelp = `pane session watch — stream a session's events as JSON-lines
|
|
12
15
|
|
|
13
16
|
Usage:
|
|
14
|
-
pane watch <session-id> [options]
|
|
17
|
+
pane session watch <session-id> [options]
|
|
15
18
|
|
|
16
19
|
Holds a WebSocket to WS /v1/sessions/:id/stream. Prints ONE compact JSON
|
|
17
20
|
object per line to stdout, flushing after each — designed to be piped into a
|
|
@@ -52,14 +55,14 @@ Options:
|
|
|
52
55
|
Each line is one event envelope: { id, session_id, author, ts, type, data,
|
|
53
56
|
causation_id, idempotency_key }. The terminal line is {"type":"_closed"}.
|
|
54
57
|
|
|
55
|
-
Pattern — Claude Code Monitor tool: run \`pane watch <id> --type form.submitted\`
|
|
58
|
+
Pattern — Claude Code Monitor tool: run \`pane session watch <id> --type form.submitted\`
|
|
56
59
|
as a monitored process; the harness re-invokes the model when the line lands.
|
|
57
60
|
|
|
58
61
|
Wait for any of several events:
|
|
59
|
-
pane watch <id> --type form.submitted,form.cancelled --timeout 60
|
|
62
|
+
pane session watch <id> --type form.submitted,form.cancelled --timeout 60
|
|
60
63
|
|
|
61
64
|
Stream only matching events to stdout, exit on the first:
|
|
62
|
-
pane watch <id> --type form.submitted --filter-type form.submitted`;
|
|
65
|
+
pane session watch <id> --type form.submitted --filter-type form.submitted`;
|
|
63
66
|
// Parse a comma-separated event-type list (e.g. "form.submitted,form.cancelled")
|
|
64
67
|
// into a Set. Empty/whitespace entries are dropped. Returns null when the flag
|
|
65
68
|
// wasn't given (so callers can distinguish "no filter" from "empty filter").
|
|
@@ -88,6 +91,7 @@ export function shouldPrintEvent(eventType, filterTypes) {
|
|
|
88
91
|
return filterTypes.has(eventType);
|
|
89
92
|
}
|
|
90
93
|
export async function runWatch(args) {
|
|
94
|
+
assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane session watch");
|
|
91
95
|
const sessionId = args.positionals[0];
|
|
92
96
|
if (!sessionId)
|
|
93
97
|
fail("missing <session-id>", "invalid_args");
|
package/dist/config.js
CHANGED
|
@@ -49,15 +49,15 @@ export function describeConfig(args) {
|
|
|
49
49
|
}
|
|
50
50
|
/**
|
|
51
51
|
* The hosted Pane relay. Used as the relay-URL fallback so a fresh user only
|
|
52
|
-
* needs an API key — `pane register` against the hosted relay, then go. A
|
|
53
|
-
* self-hoster overrides it with `--url` / `PANE_URL` / `pane register --url`.
|
|
52
|
+
* needs an API key — `pane agent register` against the hosted relay, then go. A
|
|
53
|
+
* self-hoster overrides it with `--url` / `PANE_URL` / `pane agent register --url`.
|
|
54
54
|
*/
|
|
55
55
|
export const DEFAULT_RELAY_URL = "https://relay.paneui.com";
|
|
56
56
|
/**
|
|
57
57
|
* Resolve relay URL + API key. Precedence (highest first):
|
|
58
58
|
* url: --url flag → PANE_URL env → store.url → DEFAULT_RELAY_URL
|
|
59
59
|
* apiKey: --api-key → PANE_API_KEY env → store.apiKey
|
|
60
|
-
* The store is written by `pane register`, so later commands need no env vars.
|
|
60
|
+
* The store is written by `pane agent register`, so later commands need no env vars.
|
|
61
61
|
*/
|
|
62
62
|
export function resolveConfig(args) {
|
|
63
63
|
const store = readStore();
|
|
@@ -67,7 +67,7 @@ export function resolveConfig(args) {
|
|
|
67
67
|
DEFAULT_RELAY_URL;
|
|
68
68
|
const apiKey = args.flags.get("api-key") ?? process.env.PANE_API_KEY ?? store.apiKey ?? "";
|
|
69
69
|
if (!apiKey) {
|
|
70
|
-
fail("missing API key: set PANE_API_KEY, pass --api-key <key>, or run 'pane register'", "config_error");
|
|
70
|
+
fail("missing API key: set PANE_API_KEY, pass --api-key <key>, or run 'pane agent register'", "config_error");
|
|
71
71
|
}
|
|
72
72
|
return { url: url.replace(/\/$/, ""), apiKey };
|
|
73
73
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,21 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// pane — command-line client for the Pane relay.
|
|
3
3
|
//
|
|
4
|
+
// Shape: uniform `pane <noun> <verb> [options]`. Every command lives under a
|
|
5
|
+
// noun; nothing is a bare top-level verb. See issue #163 for the rationale
|
|
6
|
+
// behind the shape and the rename from the older flat layout.
|
|
7
|
+
//
|
|
4
8
|
// Config: PANE_URL and PANE_API_KEY (env), overridable with --url / --api-key.
|
|
5
|
-
// Output is JSON by default. Every
|
|
9
|
+
// Output is JSON by default. Every noun self-documents via --help.
|
|
6
10
|
import { parseArgs, ArgvError } from "./argv.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Translate an ArgvError into the canonical `invalid_args` envelope and exit
|
|
13
|
+
* non-zero. The parser throws ArgvError up-front; assertKnownFlags throws it
|
|
14
|
+
* from inside a runner. Both paths funnel here so the on-wire shape is one.
|
|
15
|
+
*/
|
|
16
|
+
function failArgvError(e) {
|
|
17
|
+
const error = {
|
|
18
|
+
code: "invalid_args",
|
|
19
|
+
message: e.message,
|
|
20
|
+
};
|
|
21
|
+
if (e.hint !== undefined)
|
|
22
|
+
error["hint"] = e.hint;
|
|
23
|
+
process.stderr.write(JSON.stringify({ error }) + "\n");
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
import { runSession, sessionHelp } from "./commands/session.js";
|
|
12
27
|
import { runArtifact, artifactHelp } from "./commands/artifact.js";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { runKeys, keysHelp } from "./commands/keys.js";
|
|
28
|
+
import { runAgent, agentHelp } from "./commands/agent.js";
|
|
29
|
+
import { runKey, keyHelp } from "./commands/key.js";
|
|
16
30
|
import { runTaste, tasteHelp } from "./commands/taste.js";
|
|
17
31
|
import { runFeedback, feedbackHelp } from "./commands/feedback.js";
|
|
18
|
-
import {
|
|
32
|
+
import { runConfig, configHelp } from "./commands/config.js";
|
|
33
|
+
import { runBlob, blobHelp } from "./commands/blob.js";
|
|
19
34
|
import { runSkill, skillHelp } from "./commands/skill.js";
|
|
20
35
|
import { VERSION } from "./version.js";
|
|
21
36
|
import { PaneApiError } from "@paneui/core";
|
|
@@ -23,39 +38,37 @@ import { failUpgradeRequired } from "./output.js";
|
|
|
23
38
|
const ROOT_HELP = `pane — a round-trip UI channel between agents and humans
|
|
24
39
|
|
|
25
40
|
Usage:
|
|
26
|
-
pane <
|
|
41
|
+
pane <noun> <verb> [options]
|
|
27
42
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
watch <id> Stream a session's events as JSON-lines on stdout
|
|
38
|
-
(long-lived; the building block for pipe-readers).
|
|
39
|
-
delete <id> Close/delete a session (DELETE /v1/sessions/:id).
|
|
40
|
-
keys Inspect or revoke YOUR agent's API key (list / revoke).
|
|
41
|
-
taste Read / write / clear YOUR agent's UI taste notes
|
|
42
|
-
(get / set / clear) — presentation preferences the agent
|
|
43
|
+
Nouns:
|
|
44
|
+
session Open / observe / send to / close sessions
|
|
45
|
+
(create | list | show | send | watch | delete |
|
|
46
|
+
participant <list|new|revoke>).
|
|
47
|
+
artifact Reusable, versioned UI templates
|
|
48
|
+
(create | version | update | search | list | show | delete).
|
|
49
|
+
key YOUR agent's API key (list | revoke).
|
|
50
|
+
taste YOUR agent's freeform UI taste notes
|
|
51
|
+
(get | set | clear) — presentation preferences the agent
|
|
43
52
|
has learned from human feedback and reads before
|
|
44
53
|
generating a pane artifact.
|
|
45
|
-
feedback
|
|
46
|
-
(create
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
feedback One-shot feedback to the relay operator
|
|
55
|
+
(create | list) — bug reports, feature requests, notes.
|
|
56
|
+
blob Binary attachments (upload | download | show | list |
|
|
57
|
+
delete | token <mint|revoke|list>). Blobs are scoped to
|
|
58
|
+
an agent, a session, or an artifact, and can be referenced
|
|
59
|
+
from event payloads + input_data via
|
|
60
|
+
\`format: pane-blob-id\`.
|
|
61
|
+
agent Agent identity on this machine (register | logout).
|
|
62
|
+
config CLI config inspection (show).
|
|
63
|
+
skill The relay's SKILL.md (show | version) — auto-updating;
|
|
64
|
+
no API key required.
|
|
52
65
|
|
|
53
|
-
Run \`pane <
|
|
66
|
+
Run \`pane <noun> --help\` for that noun's verbs.
|
|
54
67
|
|
|
55
68
|
Config:
|
|
56
69
|
PANE_URL Relay base URL. Override: --url <url>
|
|
57
70
|
PANE_API_KEY Agent API key. Override: --api-key <key>
|
|
58
|
-
'pane register' provisions the API key and saves it (with the URL) to
|
|
71
|
+
'pane agent register' provisions the API key and saves it (with the URL) to
|
|
59
72
|
\${XDG_CONFIG_HOME:-~/.config}/pane/config.json — afterwards commands need
|
|
60
73
|
only PANE_URL (or nothing) set.
|
|
61
74
|
|
|
@@ -72,7 +85,7 @@ Output: stdout is machine-readable JSON; errors go to stderr as
|
|
|
72
85
|
//
|
|
73
86
|
// `version` is deliberately NOT here: the top-level `-v` / `--version` is
|
|
74
87
|
// handled from rawArgv[0] before parseArgs runs, so it never needs to be a
|
|
75
|
-
// boolean flag — and keeping it out lets `pane create --version <n>` /
|
|
88
|
+
// boolean flag — and keeping it out lets `pane session create --version <n>` /
|
|
76
89
|
// `pane artifact version` consume a value as a normal value-flag.
|
|
77
90
|
const BOOLEAN_FLAGS = new Set([
|
|
78
91
|
"json",
|
|
@@ -89,12 +102,12 @@ async function main() {
|
|
|
89
102
|
process.stdout.write(VERSION + "\n");
|
|
90
103
|
return;
|
|
91
104
|
}
|
|
92
|
-
const
|
|
105
|
+
const noun = rawArgv[0];
|
|
93
106
|
const rest = rawArgv.slice(1);
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
if (noun === undefined ||
|
|
108
|
+
noun === "-h" ||
|
|
109
|
+
noun === "--help" ||
|
|
110
|
+
noun === "help") {
|
|
98
111
|
process.stdout.write(ROOT_HELP + "\n");
|
|
99
112
|
return;
|
|
100
113
|
}
|
|
@@ -104,65 +117,47 @@ async function main() {
|
|
|
104
117
|
}
|
|
105
118
|
catch (e) {
|
|
106
119
|
if (e instanceof ArgvError) {
|
|
107
|
-
|
|
108
|
-
error: { code: "invalid_args", message: e.message },
|
|
109
|
-
}) + "\n");
|
|
110
|
-
process.exit(1);
|
|
120
|
+
failArgvError(e);
|
|
111
121
|
}
|
|
112
122
|
throw e;
|
|
113
123
|
}
|
|
114
124
|
const helps = {
|
|
115
|
-
|
|
116
|
-
create: createHelp,
|
|
125
|
+
session: sessionHelp,
|
|
117
126
|
artifact: artifactHelp,
|
|
118
|
-
|
|
119
|
-
send: sendHelp,
|
|
120
|
-
watch: watchHelp,
|
|
121
|
-
delete: deleteHelp,
|
|
122
|
-
keys: keysHelp,
|
|
127
|
+
key: keyHelp,
|
|
123
128
|
taste: tasteHelp,
|
|
124
129
|
feedback: feedbackHelp,
|
|
130
|
+
blob: blobHelp,
|
|
131
|
+
agent: agentHelp,
|
|
125
132
|
config: configHelp,
|
|
126
|
-
logout: logoutHelp,
|
|
127
133
|
skill: skillHelp,
|
|
128
134
|
};
|
|
129
|
-
if (!(
|
|
135
|
+
if (!(noun in helps)) {
|
|
130
136
|
process.stderr.write(JSON.stringify({
|
|
131
137
|
error: {
|
|
132
138
|
code: "unknown_command",
|
|
133
|
-
message: `unknown command '${
|
|
139
|
+
message: `unknown command '${noun}' — run 'pane --help'`,
|
|
134
140
|
},
|
|
135
141
|
}) + "\n");
|
|
136
142
|
process.exit(1);
|
|
137
143
|
}
|
|
138
|
-
|
|
139
|
-
|
|
144
|
+
// `pane <noun> --help` with no verb prints the noun-level help. A verb-level
|
|
145
|
+
// --help is the responsibility of each runner (e.g. runSession dispatches to
|
|
146
|
+
// the verb runner which reads its own xxxHelp). This pre-empt only fires
|
|
147
|
+
// when --help is the FIRST positional-equivalent — i.e. no verb given.
|
|
148
|
+
if (args.bools.has("help") && args.positionals.length === 0) {
|
|
149
|
+
process.stdout.write(helps[noun] + "\n");
|
|
140
150
|
return;
|
|
141
151
|
}
|
|
142
|
-
switch (
|
|
143
|
-
case "
|
|
144
|
-
await
|
|
145
|
-
break;
|
|
146
|
-
case "create":
|
|
147
|
-
await runCreate(args);
|
|
152
|
+
switch (noun) {
|
|
153
|
+
case "session":
|
|
154
|
+
await runSession(args);
|
|
148
155
|
break;
|
|
149
156
|
case "artifact":
|
|
150
157
|
await runArtifact(args);
|
|
151
158
|
break;
|
|
152
|
-
case "
|
|
153
|
-
await
|
|
154
|
-
break;
|
|
155
|
-
case "send":
|
|
156
|
-
await runSend(args);
|
|
157
|
-
break;
|
|
158
|
-
case "watch":
|
|
159
|
-
await runWatch(args);
|
|
160
|
-
break;
|
|
161
|
-
case "delete":
|
|
162
|
-
await runDelete(args);
|
|
163
|
-
break;
|
|
164
|
-
case "keys":
|
|
165
|
-
await runKeys(args);
|
|
159
|
+
case "key":
|
|
160
|
+
await runKey(args);
|
|
166
161
|
break;
|
|
167
162
|
case "taste":
|
|
168
163
|
await runTaste(args);
|
|
@@ -170,18 +165,28 @@ async function main() {
|
|
|
170
165
|
case "feedback":
|
|
171
166
|
await runFeedback(args);
|
|
172
167
|
break;
|
|
168
|
+
case "blob":
|
|
169
|
+
await runBlob(args);
|
|
170
|
+
break;
|
|
171
|
+
case "agent":
|
|
172
|
+
await runAgent(args);
|
|
173
|
+
break;
|
|
173
174
|
case "config":
|
|
174
175
|
await runConfig(args);
|
|
175
176
|
break;
|
|
176
|
-
case "logout":
|
|
177
|
-
await runLogout();
|
|
178
|
-
break;
|
|
179
177
|
case "skill":
|
|
180
178
|
await runSkill(args);
|
|
181
179
|
break;
|
|
182
180
|
}
|
|
183
181
|
}
|
|
184
182
|
main().catch((err) => {
|
|
183
|
+
// ArgvError thrown from a runner (e.g. assertKnownFlags) reaches here —
|
|
184
|
+
// funnel it through the same invalid_args envelope as the parse-time path
|
|
185
|
+
// so unknown-flag rejection looks identical no matter which layer caught
|
|
186
|
+
// the user error.
|
|
187
|
+
if (err instanceof ArgvError) {
|
|
188
|
+
failArgvError(err);
|
|
189
|
+
}
|
|
185
190
|
// Funnel 426 cli_upgrade_required through the dedicated upgrade-message
|
|
186
191
|
// path so a command that throws raw (instead of going through
|
|
187
192
|
// failFromError) still produces the exact stderr block + exit 75 the
|
package/dist/input.js
CHANGED
|
@@ -17,7 +17,7 @@ function isFilePath(value) {
|
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
19
|
const code = e && typeof e === "object" ? e.code : undefined;
|
|
20
|
-
throw new Error(`cannot stat '${value}'${code ? ` (${code})` : ""}: ${e instanceof Error ? e.message : String(e)}
|
|
20
|
+
throw new Error(`cannot stat '${value}'${code ? ` (${code})` : ""}: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
@@ -30,7 +30,7 @@ export function resolveJson(value, label) {
|
|
|
30
30
|
return JSON.parse(raw);
|
|
31
31
|
}
|
|
32
32
|
catch (e) {
|
|
33
|
-
throw new Error(`${label}: not valid JSON (${e instanceof Error ? e.message : String(e)})
|
|
33
|
+
throw new Error(`${label}: not valid JSON (${e instanceof Error ? e.message : String(e)})`, { cause: e });
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
/**
|
package/dist/output.js
CHANGED
|
@@ -8,7 +8,7 @@ export function printJson(value) {
|
|
|
8
8
|
process.stdout.write(JSON.stringify(value, null, 2) + "\n");
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Print a single compact JSON line to stdout and flush. Used by `pane watch`
|
|
11
|
+
* Print a single compact JSON line to stdout and flush. Used by `pane session watch`
|
|
12
12
|
* so a pipe-reader (e.g. Claude Code's Monitor tool) sees each event
|
|
13
13
|
* immediately, one event per line.
|
|
14
14
|
*/
|
package/dist/store.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Persisted CLI config: ${XDG_CONFIG_HOME or ~/.config}/pane/config.json.
|
|
2
2
|
//
|
|
3
|
-
// Holds the relay URL and the agent API key obtained via `pane register`, so
|
|
3
|
+
// Holds the relay URL and the agent API key obtained via `pane agent register`, so
|
|
4
4
|
// later commands need no env vars. The file holds a secret — it is written
|
|
5
5
|
// 0600. Tiny and synchronous; no deps.
|
|
6
6
|
import { readFileSync, writeFileSync, mkdirSync, chmodSync, rmSync, } from "node:fs";
|
|
@@ -55,7 +55,7 @@ export function writeStore(patch) {
|
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
57
|
* Delete the persisted config file (URL + API key). Idempotent — no error if
|
|
58
|
-
* the file never existed. Returns the path it targeted. Used by `pane logout`.
|
|
58
|
+
* the file never existed. Returns the path it targeted. Used by `pane agent logout`.
|
|
59
59
|
*/
|
|
60
60
|
export function clearStore() {
|
|
61
61
|
const path = storePath();
|
package/dist/version.js
CHANGED
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
// Keep this in lockstep with packages/cli/package.json's `version` field;
|
|
9
9
|
// they're consulted in different places (here for the runtime header,
|
|
10
10
|
// package.json for npm publish + dependency resolution).
|
|
11
|
-
export const VERSION = "0.0.
|
|
11
|
+
export const VERSION = "0.0.6";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paneui/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Command-line client for the Pane relay: create sessions, inspect state, send and watch events.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -41,11 +41,11 @@
|
|
|
41
41
|
"test:unit": "vitest run"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@paneui/core": "^0.0.
|
|
44
|
+
"@paneui/core": "^0.0.6"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@types/node": "^
|
|
48
|
-
"typescript": "^
|
|
47
|
+
"@types/node": "^25.9.1",
|
|
48
|
+
"typescript": "^6.0.3",
|
|
49
49
|
"vitest": "^4.1.6"
|
|
50
50
|
}
|
|
51
51
|
}
|