@shardflux/cli 0.9.0 → 0.11.0

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/dist/args.js CHANGED
@@ -12,7 +12,7 @@
12
12
  import { parseArgs } from 'node:util';
13
13
  import { ACCOUNT_COMMANDS } from "./account-args.js";
14
14
  import { UsageError } from "./errors.js";
15
- export const CLI_VERSION = '0.9.0';
15
+ export const CLI_VERSION = '0.11.0';
16
16
  export const GLOBAL_OPTIONS = {
17
17
  'api-url': { type: 'string', value: '<url>', description: 'API base URL (default $SHARDFLUX_API_URL, else https://api.shardflux.dev).' },
18
18
  json: { type: 'boolean', description: 'Print machine-readable JSON on stdout (errors as JSON on stderr).' },
@@ -64,6 +64,13 @@ const REF = { name: 'id|key', required: true };
64
64
  /** A TCP port inside the workspace (1-65535). */
65
65
  const PORT = { name: 'port', required: true };
66
66
  const SLUG = { name: 'slug', required: true };
67
+ /** The screenshot after a computer action or batch (0.10.0+). */
68
+ const COMPUTER_LOOK = {
69
+ screenshot: { type: 'string', value: '<file>', description: 'Take a screenshot after it and write it here.' },
70
+ settle: { type: 'string', value: '<ms>', description: 'Wait this long before that screenshot when the screen may change (0-10000, default 250).' },
71
+ format: { type: 'string', value: '<png|jpeg>', description: 'Screenshot format (default png).' },
72
+ quality: { type: 'string', value: '<1-100>', description: 'JPEG quality (default 80).' },
73
+ };
67
74
  const PAGE = {
68
75
  all: { type: 'boolean', description: 'Fetch every page.' },
69
76
  limit: { type: 'string', value: '<n>', description: 'Page size.' },
@@ -193,6 +200,17 @@ const KEY_COMMANDS = [
193
200
  },
194
201
  examples: ['shard usage', 'shard usage --estimate', 'shard usage --series --granularity day', 'shard usage --workspace acme/demo --meter cpu_seconds'],
195
202
  },
203
+ {
204
+ path: ['workspaces', 'retention'], summary: 'Set or clear persistent workspace idle deletion',
205
+ positionals: [{ name: 'key', required: true }, { name: 'policy', required: true }], options: {},
206
+ examples: ['shard ws retention acme/thread-42 14d', 'shard ws retention acme/thread-42 off'],
207
+ },
208
+ {
209
+ path: ['projects', 'retention'], summary: 'Read or set the project default idle deletion policy (project key)',
210
+ positionals: [{ name: 'project-id', required: true }, { name: 'policy', required: false }],
211
+ options: { labels: { type: 'string', value: '<json>', description: 'Exact-match label selectors.' } },
212
+ examples: ["shard projects retention <project-id> 14d --labels '{\"app\":\"chat\"}'"],
213
+ },
196
214
  {
197
215
  path: ['workspaces', 'open'],
198
216
  summary: 'Open a workspace by key (create on first use, reconnect or resume afterwards)',
@@ -201,6 +219,7 @@ const KEY_COMMANDS = [
201
219
  options: {
202
220
  template: { type: 'string', value: '<slug>', description: 'Template slug (required), e.g. python-node-browser.' },
203
221
  labels: { type: 'string', value: '<json>', description: 'Replace workspace labels with a JSON object of strings.' },
222
+ 'delete-after-idle': { type: 'string', value: '<days>d', description: 'Delete this persistent workspace after 1..3650 idle days (e.g. 14d).' },
204
223
  'idle-policy': { type: 'string', value: '<policy>', description: 'adaptive, never or fixed:<seconds>.' },
205
224
  secret: {
206
225
  type: 'string',
@@ -218,6 +237,11 @@ const KEY_COMMANDS = [
218
237
  value: '<processful|file-first>',
219
238
  description: 'file-first: the workspace is a versioned file tree with no VM between commands; each "shard ws exec" runs in a fresh VM and keeps the files it changed under /home/user as the next tree revision. Ready at once, never suspended, persistent, needs a layered template version. Default: processful for a new key, the stored mode for an existing one (a mode never changes).',
220
239
  },
240
+ 'computer-use': {
241
+ type: 'string',
242
+ value: '<on|off|inherit>',
243
+ description: 'Computer use (0.10.0+): on gives the workspace a desktop agents drive (shard ws computer); inherit follows the template. Default: unchanged (off for a new key unless its template turns it on).',
244
+ },
221
245
  ...INPUTS,
222
246
  ...CAPS,
223
247
  ...MEMORY_ALLOCATION,
@@ -265,6 +289,11 @@ const KEY_COMMANDS = [
265
289
  description: 'Runs argv directly (no shell; use `-- bash -lc "..."` for shell syntax) and returns the session at once (JSON on stdout). Read it with "shard ws exec-read", stop it with "shard ws exec-cancel".',
266
290
  positionals: [REF, { name: 'command', required: true, variadic: true }],
267
291
  options: {
292
+ template: {
293
+ type: 'string',
294
+ value: '<slug>',
295
+ description: 'Open the key first (0.10.0+): the workspace is created from this template on first use (stderr says so) and resumed if suspended; "default" is the platform default template. Without it the key must already have a workspace.',
296
+ },
268
297
  'stdin-open': { type: 'boolean', description: 'Keep pipe stdin open for exec-input.' },
269
298
  'session-id': { type: 'string', value: '<id>', description: 'Caller-chosen id to deduplicate starts.' },
270
299
  cwd: { type: 'string', value: '<dir>', description: 'Absolute working directory.' },
@@ -277,6 +306,17 @@ const KEY_COMMANDS = [
277
306
  },
278
307
  examples: ['shard ws exec-start acme/demo --session-id build-1 --timeout 2h -- bash -lc "make -C /home/user/app"', 'shard ws exec-read acme/demo build-1 --follow'],
279
308
  },
309
+ {
310
+ path: ['workspaces', 'tunnel'], summary: 'Reach this machine from a workspace TCP port',
311
+ description: 'Runs in the foreground. The guest listener defaults to loopback; --to is dialed on this machine. Ctrl-C closes the tunnel. An open tunnel keeps the workspace awake.',
312
+ positionals: [REF], options: {
313
+ transport: { type: 'string', value: '<auto|pty|exec>', description: 'Tunnel transport (default auto).' },
314
+ remote: { type: 'string', value: '<port>', description: 'Required guest listener port (1..65535).' },
315
+ to: { type: 'string', value: '<host:port>', description: 'Required TCP target on this machine (host:port or [IPv6]:port).' },
316
+ bind: { type: 'string', value: '<127.0.0.1|0.0.0.0>', description: 'Guest bind address (default 127.0.0.1).' },
317
+ },
318
+ examples: ['shard ws tunnel acme/demo --remote 8081 --to localhost:8081'],
319
+ },
280
320
  {
281
321
  path: ['workspaces', 'exec-read'],
282
322
  summary: 'Print a background exec session’s output and state; --follow streams it until the command exits',
@@ -305,9 +345,14 @@ const KEY_COMMANDS = [
305
345
  {
306
346
  path: ['workspaces', 'exec'],
307
347
  summary: 'Run a command in a workspace; prints its output and exits with its exit code',
308
- description: 'Runs argv directly (no shell; use `-- bash -lc "..."` for shell syntax). Processful workspaces: output is streamed as it arrives and resumes from byte offsets after dropped connections; Ctrl-C stops waiting and cancels the command. File-first workspaces: the command runs as an execution in a fresh VM on the latest tree revision; its output is printed when it ended, and the files it changed under /home/user become the next tree revision (-v lists them). An execution runs to completion: Ctrl-C stops waiting and names the command that fetches its result later. A failed or lost execution (nothing published) exits 6, as does a command that could not start (a --cwd that is not a directory, a program not on PATH), with the workspace’s reason.',
348
+ description: 'Also `shard exec` (0.10.0+). With --template the key is opened first, so one command creates the workspace on first use: `shard exec acme/demo --template default -- python3 -V`. Runs argv directly (no shell; use `-- bash -lc "..."` for shell syntax). Processful workspaces: output is streamed as it arrives and resumes from byte offsets after dropped connections; Ctrl-C stops waiting and cancels the command. File-first workspaces: the command runs as an execution in a fresh VM on the latest tree revision; its output is printed when it ended, and the files it changed under /home/user become the next tree revision (-v lists them). An execution runs to completion: Ctrl-C stops waiting and names the command that fetches its result later. A failed or lost execution (nothing published) exits 6, as does a command that could not start (a --cwd that is not a directory, a program not on PATH), with the workspace’s reason.',
309
349
  positionals: [REF, { name: 'command', required: true, variadic: true }],
310
350
  options: {
351
+ template: {
352
+ type: 'string',
353
+ value: '<slug>',
354
+ description: 'Open the key first (0.10.0+): the workspace is created from this template on first use (stderr says so) and resumed if suspended; "default" is the platform default template. Without it the key must already have a workspace.',
355
+ },
311
356
  cwd: { type: 'string', value: '<dir>', description: 'Working directory, an absolute path (default /home/user; under /home/user on a file-first workspace). A relative path is refused (invalid_cwd).' },
312
357
  env: { type: 'string', multiple: true, value: '<K=V>', description: 'Environment variable (repeatable).' },
313
358
  timeout: { type: 'string', value: '<duration>', description: 'Kill the command after this long (exit code 124).' },
@@ -365,6 +410,11 @@ const KEY_COMMANDS = [
365
410
  positionals: [REF, { name: 'new-key', required: true }],
366
411
  options: { ...CAPS, ...MEMORY_ALLOCATION, ...WAIT },
367
412
  },
413
+ {
414
+ path: ['workspaces', 'upgrade'], summary: 'Upgrade in place, keeping files and installed packages',
415
+ description: 'One cold start drops memory and processes. --at next-resume schedules it without stopping the VM.',
416
+ positionals: [REF], options: { ...WAIT, at: { type: 'string', value: '<now|next-resume>', description: 'When to cold start (default now).' } },
417
+ },
368
418
  {
369
419
  path: ['workspaces', 'resize'],
370
420
  summary: 'Change a workspace’s memory, CPU or disk, running or suspended, without a restart (0.9.0+)',
@@ -377,6 +427,8 @@ const KEY_COMMANDS = [
377
427
  elastic: { type: 'boolean', description: 'Switch to elastic memory: the workspace holds what its commands use and grows up to the memory size.' },
378
428
  cpu: { type: 'string', value: '<millis>', description: 'CPU in millicores (1000 = one vCPU).' },
379
429
  disk: { type: 'string', value: '<gib>', description: 'Disk in GiB (disks grow only).' },
430
+ 'at-least': { type: 'boolean', description: 'Only grow each named resource; smaller or equal values stay unchanged.' },
431
+ wait: { type: 'boolean', description: 'Wait for the operation (default); --no-wait returns the held server answer.' },
380
432
  timeout: { type: 'string', value: '<duration>', description: 'Give up waiting after this long (default 5m); the resize continues server side.' },
381
433
  ...TIMING,
382
434
  },
@@ -471,6 +523,7 @@ const KEY_COMMANDS = [
471
523
  description: 'Opening the link starts a browser session for the port (until it expires) and lands on --path. Anyone with the link can open the port until then: share it like a password. --json prints {url, expires_at}.',
472
524
  positionals: [REF, PORT],
473
525
  options: {
526
+ 'embed-origin': { type: 'string', multiple: true, value: '<https-origin>', description: 'Allow this HTTPS origin to embed the viewer (repeatable, 1–10 distinct origins).' },
474
527
  ttl: { type: 'string', value: '<duration>', description: 'Lifetime of the link and its browser session, 1m to 7d (default 24h).' },
475
528
  path: { type: 'string', value: '<path>', description: 'Where the link lands: a path starting with one / (query allowed; default /).' },
476
529
  },
@@ -484,6 +537,190 @@ const KEY_COMMANDS = [
484
537
  options: { revoke: { type: 'boolean', description: 'Revoke the port’s callback URL instead (idempotent).' } },
485
538
  examples: ['shard ws port callback acme/demo 3000', 'shard ws port callback acme/demo 3000 --revoke'],
486
539
  },
540
+ // ---- computer use (0.10.0; contracts §45) ----
541
+ {
542
+ path: ['workspaces', 'computer', 'status'],
543
+ summary: 'Show whether the workspace desktop runs, its size and its viewers (0.10.0+)',
544
+ description: 'Never starts the desktop. Needs computer use on for the workspace (shard ws computer enable). --json prints {running, display, width, height, started_at, session, streams}.',
545
+ positionals: [REF],
546
+ options: {},
547
+ },
548
+ {
549
+ path: ['workspaces', 'computer', 'screenshot'],
550
+ summary: 'Save a screenshot of the workspace desktop (0.10.0+)',
551
+ description: 'Starts the desktop when it does not run. Writes the image to --out (default screenshot.png, or screenshot.jpg with --format jpeg). --json prints {out, format, width, height, bytes}.',
552
+ positionals: [REF],
553
+ options: {
554
+ out: { type: 'string', value: '<file>', description: 'Where to write the image (default screenshot.png).' },
555
+ format: { type: 'string', value: '<png|jpeg>', description: 'Image format (default png).' },
556
+ quality: { type: 'string', value: '<1-100>', description: 'JPEG quality (default 80).' },
557
+ },
558
+ examples: ['shard ws computer screenshot acme/demo --out desktop.png', 'shard ws computer screenshot acme/demo --format jpeg --quality 60'],
559
+ },
560
+ {
561
+ path: ['workspaces', 'computer', 'act'],
562
+ summary: 'Run a batch of computer actions on the workspace desktop (0.10.0+)',
563
+ description: 'The actions are a JSON array of Claude computer toolset members with their parameters, e.g. [{"action":"left_click","coordinate":[640,400]},{"action":"type","text":"hello"}]; - reads it from standard input. They run in order; the first failure stops the batch and the rest are reported skipped. --screenshot saves a screenshot taken after the last action. --json prints the full result (images base64).',
564
+ positionals: [REF, { name: 'actions-json', required: true }],
565
+ options: { ...COMPUTER_LOOK },
566
+ examples: [
567
+ `shard ws computer act acme/demo '[{"action":"key","text":"ctrl+l"},{"action":"type","text":"example.com\\n"}]' --screenshot after.png`,
568
+ 'echo \'[{"action":"cursor_position"}]\' | shard ws computer act acme/demo -',
569
+ ],
570
+ },
571
+ {
572
+ path: ['workspaces', 'computer', 'click'],
573
+ summary: 'Click on the workspace desktop (0.10.0+)',
574
+ description: 'At <x> <y> (screen pixels from the top-left of a screenshot), or at the pointer without them. --button right|middle, --count 2|3 for a double or triple click (left button), --mods holds modifier keys (e.g. shift, ctrl+shift).',
575
+ positionals: [REF, { name: 'x' }, { name: 'y' }],
576
+ options: {
577
+ button: { type: 'string', value: '<left|right|middle>', description: 'Mouse button (default left).' },
578
+ count: { type: 'string', value: '<1|2|3>', description: 'Clicks: 2 is a double click, 3 a triple click (left button; default 1).' },
579
+ mods: { type: 'string', value: '<keys>', description: 'Modifier keys held during the click, e.g. shift or ctrl+shift.' },
580
+ ...COMPUTER_LOOK,
581
+ },
582
+ examples: ['shard ws computer click acme/demo 640 400 --screenshot after.png', 'shard ws computer click acme/demo 200 120 --count 2'],
583
+ },
584
+ {
585
+ path: ['workspaces', 'computer', 'type'],
586
+ summary: 'Type text on the workspace desktop (0.10.0+)',
587
+ description: 'Types into the focused window, Unicode included (up to 20,000 characters); - reads the text from standard input. A newline presses Return.',
588
+ positionals: [REF, { name: 'text|-', required: true }],
589
+ options: { ...COMPUTER_LOOK },
590
+ examples: ['shard ws computer type acme/demo "hello world"', 'cat notes.txt | shard ws computer type acme/demo -'],
591
+ },
592
+ {
593
+ path: ['workspaces', 'computer', 'key'],
594
+ summary: 'Press keys on the workspace desktop (0.10.0+)',
595
+ description: 'One key or combination, or several separated by spaces: Return, Escape, ctrl+s, alt+Tab, ctrl+shift+t, F5, Page_Down.',
596
+ positionals: [REF, { name: 'keys', required: true }],
597
+ options: {
598
+ repeat: { type: 'string', value: '<n>', description: 'Press it n times (1-100).' },
599
+ ...COMPUTER_LOOK,
600
+ },
601
+ examples: ['shard ws computer key acme/demo ctrl+l', 'shard ws computer key acme/demo Tab --repeat 3 --screenshot form.png'],
602
+ },
603
+ {
604
+ path: ['workspaces', 'computer', 'scroll'],
605
+ summary: 'Scroll on the workspace desktop (0.10.0+)',
606
+ description: 'Scrolls up, down, left or right by --amount wheel clicks (default 3), at <x> <y> or at the pointer.',
607
+ positionals: [REF, { name: 'up|down|left|right', required: true }, { name: 'x' }, { name: 'y' }],
608
+ options: {
609
+ amount: { type: 'string', value: '<n>', description: 'Wheel clicks (1-100, default 3).' },
610
+ mods: { type: 'string', value: '<keys>', description: 'Modifier keys held while scrolling, e.g. shift.' },
611
+ ...COMPUTER_LOOK,
612
+ },
613
+ examples: ['shard ws computer scroll acme/demo down 640 400 --amount 5'],
614
+ },
615
+ {
616
+ path: ['workspaces', 'computer', 'move'],
617
+ summary: 'Move the pointer on the workspace desktop (0.10.0+)',
618
+ positionals: [REF, { name: 'x', required: true }, { name: 'y', required: true }],
619
+ options: { ...COMPUTER_LOOK },
620
+ },
621
+ {
622
+ path: ['workspaces', 'computer', 'drag'],
623
+ summary: 'Drag with the left button on the workspace desktop (0.10.0+)',
624
+ description: 'Presses at <x1> <y1>, moves to <x2> <y2> and releases.',
625
+ positionals: [REF, { name: 'x1', required: true }, { name: 'y1', required: true }, { name: 'x2', required: true }, { name: 'y2', required: true }],
626
+ options: {
627
+ mods: { type: 'string', value: '<keys>', description: 'Modifier keys held during the drag, e.g. alt.' },
628
+ ...COMPUTER_LOOK,
629
+ },
630
+ examples: ['shard ws computer drag acme/demo 100 200 500 200'],
631
+ },
632
+ {
633
+ path: ['workspaces', 'computer', 'mouse-down'],
634
+ summary: 'Press the left mouse button and keep it down (0.10.0+)',
635
+ description: 'At the pointer (shard ws computer move first); shard ws computer mouse-up releases it.',
636
+ positionals: [REF],
637
+ options: { ...COMPUTER_LOOK },
638
+ },
639
+ {
640
+ path: ['workspaces', 'computer', 'mouse-up'],
641
+ summary: 'Release the left mouse button (0.10.0+)',
642
+ positionals: [REF],
643
+ options: { ...COMPUTER_LOOK },
644
+ },
645
+ {
646
+ path: ['workspaces', 'computer', 'hold-key'],
647
+ summary: 'Hold keys down for some seconds on the workspace desktop (0.10.0+)',
648
+ positionals: [REF, { name: 'keys', required: true }, { name: 'seconds', required: true }],
649
+ options: { ...COMPUTER_LOOK },
650
+ examples: ['shard ws computer hold-key acme/demo shift 2'],
651
+ },
652
+ {
653
+ path: ['workspaces', 'computer', 'zoom'],
654
+ summary: 'Save an enlarged view of part of the workspace desktop (0.10.0+)',
655
+ description: 'The region <x0> <y0> <x1> <y1> (screen pixels, x0 < x1, y0 < y1), scaled up to the screen width. --json prints {out, format, width, height, bytes}.',
656
+ positionals: [REF, { name: 'x0', required: true }, { name: 'y0', required: true }, { name: 'x1', required: true }, { name: 'y1', required: true }],
657
+ options: {
658
+ out: { type: 'string', value: '<file>', description: 'Where to write the image (default zoom.png).' },
659
+ format: { type: 'string', value: '<png|jpeg>', description: 'Image format (default png).' },
660
+ quality: { type: 'string', value: '<1-100>', description: 'JPEG quality (default 80).' },
661
+ },
662
+ examples: ['shard ws computer zoom acme/demo 0 0 640 200 --out toolbar.png'],
663
+ },
664
+ {
665
+ path: ['workspaces', 'computer', 'cursor'],
666
+ summary: 'Print where the pointer is on the workspace desktop (0.10.0+)',
667
+ positionals: [REF],
668
+ options: {},
669
+ },
670
+ {
671
+ path: ['workspaces', 'computer', 'wait'],
672
+ summary: 'Wait on the workspace desktop, then optionally take a screenshot (0.10.0+)',
673
+ description: 'For a page or program that is still loading: shard ws computer wait <ws> 2 --screenshot after.png.',
674
+ positionals: [REF, { name: 'seconds', required: true }],
675
+ options: { ...COMPUTER_LOOK },
676
+ },
677
+ {
678
+ path: ['workspaces', 'computer', 'start'],
679
+ summary: 'Start the workspace desktop (0.10.0+)',
680
+ description: 'A no-op while it runs. The size applies to a start: 640x480 to 2560x1600 (default 1280x800).',
681
+ positionals: [REF],
682
+ options: {
683
+ width: { type: 'string', value: '<px>', description: 'Screen width (640-2560).' },
684
+ height: { type: 'string', value: '<px>', description: 'Screen height (480-1600).' },
685
+ },
686
+ },
687
+ { path: ['workspaces', 'computer', 'stop'], summary: 'Stop the workspace desktop; its windows close (0.10.0+)', positionals: [REF], options: {} },
688
+ {
689
+ path: ['workspaces', 'computer', 'stream'],
690
+ summary: 'Print a private link to watch the workspace desktop live (0.10.0+)',
691
+ description: 'Starts the viewer in the workspace, exposes its port and signs a link to it (inbound ports). View only unless --interactive. Anyone with the link can open it until it expires: share it like a password. --stop ends every view instead. --json prints {url, expires_at, port, interactive}.',
692
+ positionals: [REF],
693
+ options: {
694
+ fresh: { type: 'boolean', description: 'Mint a new viewer link instead of reusing a link with more than 60 seconds left.' },
695
+ interactive: { type: 'boolean', description: 'Let the viewer use the mouse and keyboard.' },
696
+ 'embed-origin': { type: 'string', multiple: true, value: '<https-origin>', description: 'Allow this HTTPS origin to embed the viewer (repeatable, 1–10 distinct origins).' },
697
+ ttl: { type: 'string', value: '<duration>', description: 'Lifetime of the link, 1m to 7d (default 24h).' },
698
+ stop: { type: 'boolean', description: 'End every view and close the viewer ports.' },
699
+ },
700
+ examples: ['open "$(shard ws computer stream acme/demo)"', 'shard ws computer stream acme/demo --stop'],
701
+ },
702
+ {
703
+ path: ['workspaces', 'computer', 'enable'],
704
+ summary: 'Switch computer use on for a workspace (0.10.0+)',
705
+ description: 'Tool tokens then carry the computer tool; the platform starts the desktop on the first computer call. --json prints {enabled, workspace, template, available}.',
706
+ positionals: [REF],
707
+ options: {},
708
+ },
709
+ { path: ['workspaces', 'computer', 'disable'], summary: 'Switch computer use off for a workspace (0.10.0+)', positionals: [REF], options: {} },
710
+ {
711
+ path: ['workspaces', 'computer', 'inherit'],
712
+ summary: 'Let a workspace follow its template’s computer use switch (0.10.0+)',
713
+ positionals: [REF],
714
+ options: {},
715
+ },
716
+ {
717
+ path: ['templates', 'computer-use'],
718
+ summary: 'Switch computer use on or off for every workspace of one of your templates (0.10.0+)',
719
+ description: 'A workspace may override it (shard ws computer enable|disable). Platform templates keep it off: switch a workspace on instead.',
720
+ positionals: [SLUG, { name: 'on|off', required: true }],
721
+ options: {},
722
+ examples: ['shard templates computer-use my-desktop-agent on'],
723
+ },
487
724
  {
488
725
  path: ['files', 'read'],
489
726
  summary: 'Print (or save) a file from a workspace',
@@ -891,8 +1128,10 @@ const ALIASES = {
891
1128
  /** Groups also reachable under `workspaces` (`shard workspaces files read ...` == `shard files read ...`). */
892
1129
  const FOLDED = new Set(['files', 'operations', 'executions']);
893
1130
  /** Canonical command words: aliases resolved, `workspaces files|operations|executions` folded to the top-level group. */
1131
+ /** Top-level shortcuts for a whole command path (0.10.0+): `shard exec` is `shard workspaces exec`. */
1132
+ const SHORTCUTS = { exec: ['workspaces', 'exec'] };
894
1133
  export function normalizeWords(words) {
895
- const w = words.map((x) => ALIASES[x] ?? x);
1134
+ const w = words.flatMap((x, i) => (i === 0 ? SHORTCUTS[x] : undefined) ?? [ALIASES[x] ?? x]);
896
1135
  if (w[0] === 'workspaces' && w[1] !== undefined && FOLDED.has(w[1]))
897
1136
  return w.slice(1);
898
1137
  return w;
@@ -96,10 +96,12 @@ export declare function principal(ctx: Ctx): Promise<{
96
96
  id: string;
97
97
  key_id: string;
98
98
  };
99
- tool_permissions: ("git" | "exec" | "files" | "pty" | "process" | "browser")[];
99
+ tool_permissions: ("git" | "exec" | "files" | "pty" | "process" | "browser" | "computer")[];
100
100
  }>;
101
101
  /** The exit code `shard exec` returns for a finished command. */
102
- export declare function execExitCode(r: Pick<RunResult, 'exitCode' | 'termSignal' | 'timedOut'>): number;
102
+ export declare function execExitCode(r: Pick<RunResult, 'exitCode' | 'termSignal' | 'timedOut'> & {
103
+ canceled?: boolean;
104
+ }): number;
103
105
  /**
104
106
  * A lifecycle call a file-first workspace does not have (suspend, resume, fork, reset,
105
107
  * save-as-template), refused before any request as the SDK's workspace handle does: NotSupportedForModeError, printed