@paneui/cli 0.0.5 → 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.
@@ -1,21 +1,24 @@
1
- // `pane watch <id>` — long-lived: hold a WebSocket and stream events as
1
+ // `pane surface 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
- export const watchHelp = `pane watch stream a session's events as JSON-lines
12
+ const KNOWN_FLAGS = ["since", "type", "filter-type", "timeout"];
13
+ const KNOWN_BOOLS = ["once"];
14
+ export const watchHelp = `pane surface watch — stream a surface's events as JSON-lines
12
15
 
13
16
  Usage:
14
- pane watch <session-id> [options]
17
+ pane surface watch <surface-id> [options]
15
18
 
16
- Holds a WebSocket to WS /v1/sessions/:id/stream. Prints ONE compact JSON
19
+ Holds a WebSocket to WS /v1/surfaces/:id/stream. Prints ONE compact JSON
17
20
  object per line to stdout, flushing after each — designed to be piped into a
18
- line-reader. On session close, prints a final {"type":"_closed"} line and
21
+ line-reader. On surface close, prints a final {"type":"_closed"} line and
19
22
  exits 0.
20
23
 
21
24
  Modes:
@@ -31,7 +34,7 @@ Options:
31
34
  --filter-type <t[,t2,…]>
32
35
  Print only events whose type is in this set.
33
36
  system.* events (lifecycle: participant.joined,
34
- session.expired, …) and the terminal {"type":
37
+ surface.expired, …) and the terminal {"type":
35
38
  "_closed"} line always pass through, so the
36
39
  harness still sees them. Combine with --type X
37
40
  --filter-type X for "stream only X events and
@@ -39,7 +42,7 @@ Options:
39
42
  --type alone that agents often expect.
40
43
  --since <cursor> Replay only events after this opaque cursor.
41
44
  --timeout <secs> Wall-clock max wait. Fail with code ws_timeout if
42
- the natural exit condition (--once, --type, session
45
+ the natural exit condition (--once, --type, surface
43
46
  close) doesn't happen within this many seconds.
44
47
  Frames arriving DO NOT reset the timer — this is
45
48
  the budget for "give up on the human", not an idle
@@ -49,17 +52,17 @@ Options:
49
52
  --api-key <key> Agent API key (overrides PANE_API_KEY).
50
53
  -h, --help Show this help.
51
54
 
52
- Each line is one event envelope: { id, session_id, author, ts, type, data,
55
+ Each line is one event envelope: { id, surface_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 surface 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 surface 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 surface 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,9 +91,10 @@ export function shouldPrintEvent(eventType, filterTypes) {
88
91
  return filterTypes.has(eventType);
89
92
  }
90
93
  export async function runWatch(args) {
91
- const sessionId = args.positionals[0];
92
- if (!sessionId)
93
- fail("missing <session-id>", "invalid_args");
94
+ assertKnownFlags(args, KNOWN_FLAGS, KNOWN_BOOLS, "pane surface watch");
95
+ const surfaceId = args.positionals[0];
96
+ if (!surfaceId)
97
+ fail("missing <surface-id>", "invalid_args");
94
98
  const cfg = resolveConfig(args);
95
99
  const since = args.flags.get("since") ?? null;
96
100
  // --type controls the EXIT condition (set of types that trigger exit 0
@@ -131,7 +135,7 @@ export async function runWatch(args) {
131
135
  }
132
136
  finish(0);
133
137
  };
134
- // Track whether the relay told us the session expired before the socket
138
+ // Track whether the relay told us the surface expired before the socket
135
139
  // closed — a 1006/1008/1011 close after that is still a clean shutdown.
136
140
  let sawSessionExpired = false;
137
141
  // Wall-clock timeout. The reporter's mental model (#137) and the skill
@@ -141,7 +145,7 @@ export async function runWatch(args) {
141
145
  // useless once any frame arrived, even a system.participant.joined
142
146
  // emitted the moment a human connected. Frames now DO NOT reset the
143
147
  // timer; the only ways `--timeout` doesn't fire are the natural exit
144
- // conditions (--once, --type match, session close) finishing first.
148
+ // conditions (--once, --type match, surface close) finishing first.
145
149
  let timer;
146
150
  if (timeoutSec !== null) {
147
151
  timer = setTimeout(() => {
@@ -150,7 +154,7 @@ export async function runWatch(args) {
150
154
  }
151
155
  const handle = openStream({
152
156
  wsBaseUrl: client.wsBaseUrl,
153
- sessionId: sessionId,
157
+ surfaceId: surfaceId,
154
158
  token: cfg.apiKey,
155
159
  since,
156
160
  }, {
@@ -163,8 +167,8 @@ export async function runWatch(args) {
163
167
  if (shouldPrintEvent(event.type, filterTypes)) {
164
168
  printJsonLine(event);
165
169
  }
166
- // A system.session.expired event means the session is closing.
167
- if (event.type === "system.session.expired") {
170
+ // A system.surface.expired event means the surface is closing.
171
+ if (event.type === "system.surface.expired") {
168
172
  sawSessionExpired = true;
169
173
  emitClosed();
170
174
  return;
@@ -180,8 +184,8 @@ export async function runWatch(args) {
180
184
  onClose: ({ code, reason }) => {
181
185
  // A clean close is 1000 (normal) or 1001 (going away). Any other code
182
186
  // — 1006 abnormal, 1008 policy/auth, 1011 server error — is a failure
183
- // UNLESS we already saw system.session.expired, which means the relay
184
- // closed us on purpose after a clean session end.
187
+ // UNLESS we already saw system.surface.expired, which means the relay
188
+ // closed us on purpose after a clean surface end.
185
189
  if (code === 1000 || code === 1001 || sawSessionExpired) {
186
190
  emitClosed();
187
191
  return;
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 command self-documents via --help.
9
+ // Output is JSON by default. Every noun self-documents via --help.
6
10
  import { parseArgs, ArgvError } from "./argv.js";
7
- import { runCreate, createHelp } from "./commands/create.js";
8
- import { runState, stateHelp } from "./commands/state.js";
9
- import { runSend, sendHelp } from "./commands/send.js";
10
- import { runWatch, watchHelp } from "./commands/watch.js";
11
- import { runRegister, registerHelp } from "./commands/register.js";
12
- import { runArtifact, artifactHelp } from "./commands/artifact.js";
13
- import { runConfig, configHelp } from "./commands/config.js";
14
- import { runLogout, logoutHelp } from "./commands/logout.js";
15
- import { runKeys, keysHelp } from "./commands/keys.js";
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/surface.js";
27
+ import { runArtifact, artifactHelp } from "./commands/template.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 { runDelete, deleteHelp } from "./commands/delete.js";
32
+ import { runConfig, configHelp } from "./commands/config.js";
33
+ import { runBlob, blobHelp } from "./commands/attachment.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 <command> [options]
41
+ pane <noun> <verb> [options]
27
42
 
28
- Commands:
29
- register Provision an agent API key (POST /v1/register) and save it
30
- to the CLI config file. Run this once before other commands.
31
- create Create a session (POST /v1/sessions). Prints session_id,
32
- urls, tokens, expires_at.
33
- artifact Manage reusable, versioned artifacts (create / version /
34
- update / search / list / show / delete).
35
- state <id> Non-blocking snapshot: session metadata + event log.
36
- send <id> Emit an agent event into a session.
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
+ surface Open / observe / send to / close surfaces
45
+ (create | list | show | send | watch | delete |
46
+ participant <list|new|revoke>).
47
+ template 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
- generating a pane artifact.
45
- feedback Submit / list one-shot feedback to the relay operator
46
- (create / list) — bug reports, feature requests, notes.
47
- config Show the resolved relay config (no network call).
48
- logout Clear the locally-saved relay URL + API key.
49
- skill Fetch the relay's SKILL.md to stdout, or just its
50
- version with 'pane skill version'. Used to install
51
- and keep the local skill copy in sync; no API key.
53
+ generating a pane template.
54
+ feedback One-shot feedback to the relay operator
55
+ (create | list) — bug reports, feature requests, notes.
56
+ attachment Binary attachments (upload | download | show | list |
57
+ delete | token <mint|revoke|list>). Blobs are scoped to
58
+ an agent, a surface, or an template, and can be referenced
59
+ from event payloads + input_data via
60
+ \`format: pane-attachment-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 <command> --help\` for command-specific options.
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,8 +85,8 @@ 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>` /
76
- // `pane artifact version` consume a value as a normal value-flag.
88
+ // boolean flag — and keeping it out lets `pane surface create --version <n>` /
89
+ // `pane template version` consume a value as a normal value-flag.
77
90
  const BOOLEAN_FLAGS = new Set([
78
91
  "json",
79
92
  "once",
@@ -89,12 +102,12 @@ async function main() {
89
102
  process.stdout.write(VERSION + "\n");
90
103
  return;
91
104
  }
92
- const command = rawArgv[0];
105
+ const noun = rawArgv[0];
93
106
  const rest = rawArgv.slice(1);
94
- if (command === undefined ||
95
- command === "-h" ||
96
- command === "--help" ||
97
- command === "help") {
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
- process.stderr.write(JSON.stringify({
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
- register: registerHelp,
116
- create: createHelp,
117
- artifact: artifactHelp,
118
- state: stateHelp,
119
- send: sendHelp,
120
- watch: watchHelp,
121
- delete: deleteHelp,
122
- keys: keysHelp,
125
+ surface: sessionHelp,
126
+ template: artifactHelp,
127
+ key: keyHelp,
123
128
  taste: tasteHelp,
124
129
  feedback: feedbackHelp,
130
+ attachment: blobHelp,
131
+ agent: agentHelp,
125
132
  config: configHelp,
126
- logout: logoutHelp,
127
133
  skill: skillHelp,
128
134
  };
129
- if (!(command in helps)) {
135
+ if (!(noun in helps)) {
130
136
  process.stderr.write(JSON.stringify({
131
137
  error: {
132
138
  code: "unknown_command",
133
- message: `unknown command '${command}' — run 'pane --help'`,
139
+ message: `unknown command '${noun}' — run 'pane --help'`,
134
140
  },
135
141
  }) + "\n");
136
142
  process.exit(1);
137
143
  }
138
- if (args.bools.has("help")) {
139
- process.stdout.write(helps[command] + "\n");
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 (command) {
143
- case "register":
144
- await runRegister(args);
152
+ switch (noun) {
153
+ case "surface":
154
+ await runSession(args);
145
155
  break;
146
- case "create":
147
- await runCreate(args);
148
- break;
149
- case "artifact":
156
+ case "template":
150
157
  await runArtifact(args);
151
158
  break;
152
- case "state":
153
- await runState(args);
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 "attachment":
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
@@ -1,5 +1,5 @@
1
1
  // Helpers for reading CLI inputs that may be either a file path or an inline
2
- // literal (JSON, or raw text for an HTML artifact body).
2
+ // literal (JSON, or raw text for an HTML template body).
3
3
  import { readFileSync, statSync } from "node:fs";
4
4
  /**
5
5
  * True if `value` names an existing file. Only a missing path (ENOENT) is
@@ -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,12 +30,12 @@ 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
  /**
37
37
  * Resolve raw text that is either a file path or an inline literal — no JSON
38
- * parsing. Used for an inline HTML artifact body.
38
+ * parsing. Used for an inline HTML template body.
39
39
  */
40
40
  export function resolveText(value) {
41
41
  return isFilePath(value) ? readFileSync(value, "utf8") : value;
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 surface 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.5";
11
+ export const VERSION = "0.0.7";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@paneui/cli",
3
- "version": "0.0.5",
4
- "description": "Command-line client for the Pane relay: create sessions, inspect state, send and watch events.",
3
+ "version": "0.0.7",
4
+ "description": "Command-line client for the Pane relay: create surfaces, inspect state, send and watch events.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "keywords": [
@@ -41,11 +41,11 @@
41
41
  "test:unit": "vitest run"
42
42
  },
43
43
  "dependencies": {
44
- "@paneui/core": "^0.0.5"
44
+ "@paneui/core": "^0.0.7"
45
45
  },
46
46
  "devDependencies": {
47
- "@types/node": "^22.7.0",
48
- "typescript": "^5.6.0",
47
+ "@types/node": "^25.9.1",
48
+ "typescript": "^6.0.3",
49
49
  "vitest": "^4.1.6"
50
50
  }
51
51
  }