@shardflux/cli 0.5.3 → 0.6.1
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/CHANGELOG.md +33 -1
- package/README.md +22 -4
- package/dist/args.d.ts +1 -1
- package/dist/args.js +2 -2
- package/dist/commands.d.ts +1 -1
- package/dist/commands.js +5 -3
- package/dist/format.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/main.js +5 -2
- package/dist/timing.d.ts +11 -0
- package/dist/timing.js +25 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,39 @@
|
|
|
3
3
|
Every command and option the README shows is available from the version named here. Below 1.0, a minor release may
|
|
4
4
|
break compatibility; breaking changes are marked **Breaking**.
|
|
5
5
|
|
|
6
|
-
## 0.
|
|
6
|
+
## 0.6.1
|
|
7
|
+
|
|
8
|
+
Needs `@shardflux/sdk` 0.11.0 or later.
|
|
9
|
+
|
|
10
|
+
### `--when-idle 0`: suspend as soon as the workspace is idle
|
|
11
|
+
|
|
12
|
+
`shard ws suspend <id|key> --when-idle` accepts `0` (also `0s`) up to `1h`; before it refused anything under `30s`.
|
|
13
|
+
The API now takes `after_seconds` from 0: the workspace is suspended as soon as it is idle (a few seconds of activity
|
|
14
|
+
flush grace after its last work), and a running command, an attached stream or a keepalive still postpones it until
|
|
15
|
+
it ends. The human output says `is suspended as soon as it is idle`, and `ws get` shows `as soon as idle`. Out of
|
|
16
|
+
range is still exit 2 before any request: `--when-idle must be between 0s and 1h`.
|
|
17
|
+
|
|
18
|
+
## 0.6.0
|
|
19
|
+
|
|
20
|
+
Needs `@shardflux/sdk` 0.11.0 or later.
|
|
21
|
+
|
|
22
|
+
### A resume that restarted processes says so (cold boot, contracts §12)
|
|
23
|
+
|
|
24
|
+
When the platform's VM runtime changed after a suspend and no host can restore the memory snapshot, the cell resumes
|
|
25
|
+
the workspace by booting its saved disk (a cold boot), automatically, also when a command wakes it. Files are as of the
|
|
26
|
+
suspend; every process was restarted.
|
|
27
|
+
|
|
28
|
+
- After a command whose resume or wake did that (`ws resume --wait`, `operations wait` of that resume, or `ws exec`,
|
|
29
|
+
`files ...` and `ws changes` waking a suspended workspace), `shard` prints one line on stderr after the output, with
|
|
30
|
+
or without `--timing`: `note: workspace <id> resumed from its saved disk; running processes were restarted
|
|
31
|
+
(runtime_changed)`. Also with `--json` (stdout unchanged); not after a `--json` failure, whose stderr is only the
|
|
32
|
+
error document. On a text failure it comes before the error line. The exit code does not change.
|
|
33
|
+
- `--json --timing`: `timing.server` adds `memory_restored` (`false` for a cold boot, `true` for a memory resume,
|
|
34
|
+
`null` when the API did not say) and `cold_boot_reason`. The human `--timing` block says `resume from cold_boot:
|
|
35
|
+
processes restarted (runtime_changed)` (the SDK's `formatTiming()`).
|
|
36
|
+
- `coldBootNotice()` is exported next to `TimingRecorder`, which records the call as `coldBoot`.
|
|
37
|
+
|
|
38
|
+
## 0.5.3
|
|
7
39
|
|
|
8
40
|
Fix: `shard --version`, the User-Agent and the update check reports 0.5.3. 0.5.2 was published reporting 0.5.1, its previous version; the build now
|
|
9
41
|
fails when `CLI_VERSION` differs from package.json.
|
package/README.md
CHANGED
|
@@ -385,7 +385,7 @@ shows the status; `shard version --check` asks now (`--json`: `{"cli", "sdk", "u
|
|
|
385
385
|
| `files search <id\|key> <path> <pattern> [--regex] [-i\|--ignore-case] [--include G]... [--exclude G]... [--max N]` | Search file contents under a directory (or in one file; gitignore-style globs): `path:line:column: text` per match (0.5.0+). |
|
|
386
386
|
| `files patch <id\|key> <path> (--old T --new T)... [--replace-all] \| --content-file F\|- [--expected-revision R] [--if-revision N]` | Replace exact text (each `--old` must occur once unless `--replace-all`), or the whole content, atomically; `R` is a revision from `files stat --revision` or `absent` (0.5.0+). `--if-revision` (0.5.0+): file-first workspaces only. |
|
|
387
387
|
| `workspaces suspend\|resume <id\|key> [--wait] [--timeout T] [--timing]` | Lifecycle operation. Returns immediately unless you pass `--wait`. |
|
|
388
|
-
| `workspaces suspend <id\|key> --when-idle D` / `--cancel-when-idle` | (0.5.1+) Suspend once the workspace has been idle for `D` (
|
|
388
|
+
| `workspaces suspend <id\|key> --when-idle D` / `--cancel-when-idle` | (0.5.1+) Suspend once the workspace has been idle for `D` (0 to 1h; `0` = as soon as it is idle, 0.6.1+), or cancel that. See "Suspend when idle". |
|
|
389
389
|
| `workspaces fork <id\|key> <new-key> [caps] [--wait]` | Fork into a new key. |
|
|
390
390
|
| `workspaces delete <id\|key> --yes [--wait]` | Delete the workspace. Tool access ends at once. The key of a persistent workspace is never reused. |
|
|
391
391
|
| `workspaces close <id\|key> [--wait]` | End a session workspace now: it is deleted, and the key then opens a new workspace. A persistent workspace is refused (`not_session`). |
|
|
@@ -576,17 +576,34 @@ without waking it (the state at suspension); `files search` then notes it on std
|
|
|
576
576
|
`shard operations wait <id>` keeps waiting.
|
|
577
577
|
- A resume or open that fails exits 6.
|
|
578
578
|
|
|
579
|
+
**A resume can restart processes (0.6.0+).** A resume normally restores memory and running processes. When the
|
|
580
|
+
platform's VM runtime changed after the suspend and no host can restore that memory snapshot, the resume boots the
|
|
581
|
+
workspace's saved disk instead (a cold boot), automatically, also when a command wakes the workspace. The command
|
|
582
|
+
still runs, and the files are as of the suspend, but every process was restarted, as after a reboot: start dev
|
|
583
|
+
servers and background jobs again. `shard` then prints one line on stderr after the output (also with `--json`,
|
|
584
|
+
except on a failure, whose stderr is only the error document), whether or not you pass `--timing`:
|
|
585
|
+
|
|
586
|
+
```text
|
|
587
|
+
note: workspace 01a0e5a8-3edd-74ba-b489-d62b8925e342 resumed from its saved disk; running processes were restarted (runtime_changed)
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
`shard ws resume --wait --json` prints the operation with its `result` as the API sent it (`resume_path`
|
|
591
|
+
`cold_boot`, `memory_restored` false, `cold_boot_reason`), and `--timing` shows `resume from cold_boot: processes
|
|
592
|
+
restarted (runtime_changed)`. The same applies to `operations wait` of such a resume.
|
|
593
|
+
|
|
579
594
|
## Suspend when idle (0.5.1+)
|
|
580
595
|
|
|
581
596
|
A running workspace is billed while it is awake. When an agent's turn ends, ask for a suspend once the workspace has
|
|
582
597
|
been idle for a short time, instead of waiting for its idle policy:
|
|
583
598
|
|
|
584
599
|
```sh
|
|
585
|
-
shard ws suspend acme/demo --when-idle 2m #
|
|
600
|
+
shard ws suspend acme/demo --when-idle 2m # 0 to 1h; whole seconds
|
|
586
601
|
shard ws get acme/demo # "suspend when idle after 120 s idle, not before ..."
|
|
587
602
|
shard ws suspend acme/demo --cancel-when-idle
|
|
588
603
|
```
|
|
589
604
|
|
|
605
|
+
- `--when-idle 0` (0.6.1+) suspends the workspace as soon as it is idle (a few seconds after its last work).
|
|
606
|
+
|
|
590
607
|
- The idle time counts from the later of the workspace's last work and the request.
|
|
591
608
|
- A command still running, an attached stream or a keepalive postpones the suspend until the duration after it ends.
|
|
592
609
|
- The next tool call on the workspace (the next turn) or a resume cancels the request. Repeating replaces it.
|
|
@@ -686,8 +703,9 @@ Which call is timed:
|
|
|
686
703
|
|
|
687
704
|
With `--json`, stdout carries the timing as a `timing` field of the command's JSON instead: `action`, `outcome`,
|
|
688
705
|
`workspace_id`, `operation_id`, `total_ms`, `phases` (`phase`, `reason`, `operation_id`, `start_ms`, `duration_ms`),
|
|
689
|
-
`retries`, `server` (`queued_ms`, `run_ms`, `total_ms`, `start_path`, `resume_path`, `
|
|
690
|
-
`
|
|
706
|
+
`retries`, `server` (`queued_ms`, `run_ms`, `total_ms`, `start_path`, `resume_path`, `memory_restored` and
|
|
707
|
+
`cold_boot_reason` (0.6.0+; `memory_restored` is `false` when a resume booted the saved disk, `null` when the API did
|
|
708
|
+
not say), `boot_to_ready_ms`, ...) and `outside_server_ms`. It is `null` when the command made no lifecycle call. On a failure the error document on stderr
|
|
691
709
|
carries it: `{"error": {...}, "timing": {...}}`.
|
|
692
710
|
|
|
693
711
|
`shard` does not stream progress while it waits. For live events, use the SDK's `onProgress`.
|
package/dist/args.d.ts
CHANGED
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.
|
|
15
|
+
export const CLI_VERSION = '0.6.1';
|
|
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).' },
|
|
@@ -274,7 +274,7 @@ const KEY_COMMANDS = [
|
|
|
274
274
|
description: 'Without options the suspend is requested now. --when-idle (0.5.1+) defers it instead: the workspace is suspended once it has been idle for that long, counted from the later of its last work and the request, so call it when an agent turn ends. A command still running, an attached exec or terminal stream, or a keepalive postpones it; the next tool call (the next turn) or a resume cancels it. Repeating replaces the pending request. --cancel-when-idle cancels it.',
|
|
275
275
|
positionals: [REF],
|
|
276
276
|
options: {
|
|
277
|
-
'when-idle': { type: 'string', value: '<duration>', description: 'Suspend once the workspace has been idle this long (
|
|
277
|
+
'when-idle': { type: 'string', value: '<duration>', description: 'Suspend once the workspace has been idle this long (0.5.1+; 0 to 1h, e.g. 0, 30s, 2m; 0 = as soon as it is idle, 0.6.1+). Cannot be combined with --wait.' },
|
|
278
278
|
'cancel-when-idle': { type: 'boolean', description: 'Cancel a pending --when-idle request (0.5.1+; idempotent).' },
|
|
279
279
|
...WAIT,
|
|
280
280
|
},
|
package/dist/commands.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ export type Handler = (ctx: Ctx, values: Values, positionals: string[]) => Promi
|
|
|
70
70
|
export declare const str: (v: Values[string]) => string | undefined;
|
|
71
71
|
export declare const strs: (v: Values[string]) => string[];
|
|
72
72
|
export declare function out(ctx: Ctx, human: string, machine: unknown): void;
|
|
73
|
-
/** `--when-idle <duration>`: whole seconds from
|
|
73
|
+
/** `--when-idle <duration>`: whole seconds from 0 (as soon as it is idle; 0.6.1) to 3600 (the API's after_seconds bounds, contracts §20.6). */
|
|
74
74
|
export declare function whenIdleSeconds(text: string): number;
|
|
75
75
|
export declare function waitTimeout(values: Values): number;
|
|
76
76
|
/**
|
package/dist/commands.js
CHANGED
|
@@ -66,14 +66,16 @@ function caps(values) {
|
|
|
66
66
|
c.disk_gib = parsePositiveInt(disk, 'disk-gib', 1_000_000);
|
|
67
67
|
return Object.keys(c).length ? c : undefined;
|
|
68
68
|
}
|
|
69
|
-
/** `--when-idle <duration>`: whole seconds from
|
|
69
|
+
/** `--when-idle <duration>`: whole seconds from 0 (as soon as it is idle; 0.6.1) to 3600 (the API's after_seconds bounds, contracts §20.6). */
|
|
70
70
|
export function whenIdleSeconds(text) {
|
|
71
|
+
if (/^0+(?:\.0+)?(?:ms|s|m|h)?$/.test(text.trim()))
|
|
72
|
+
return 0;
|
|
71
73
|
const ms = parseDuration(text, 'when-idle');
|
|
72
74
|
if (ms % 1000 !== 0)
|
|
73
75
|
throw new UsageError('--when-idle must be a whole number of seconds (e.g. 30s, 90s, 2m)');
|
|
74
76
|
const s = ms / 1000;
|
|
75
|
-
if (s
|
|
76
|
-
throw new UsageError(`--when-idle must be between
|
|
77
|
+
if (s > 3600)
|
|
78
|
+
throw new UsageError(`--when-idle must be between 0s and 1h (got "${text}")`);
|
|
77
79
|
return s;
|
|
78
80
|
}
|
|
79
81
|
export function waitTimeout(values) {
|
package/dist/format.js
CHANGED
|
@@ -109,13 +109,13 @@ export function startupTail(s) {
|
|
|
109
109
|
}
|
|
110
110
|
/** A pending suspend-when-idle request in one line (0.5.1; contracts §20.6). */
|
|
111
111
|
export function suspendRequestText(r) {
|
|
112
|
-
return `after ${r.after_seconds} s idle, not before ${time(r.not_before)} (requested ${time(r.requested_at)})`;
|
|
112
|
+
return `${r.after_seconds === 0 ? 'as soon as idle' : `after ${r.after_seconds} s idle`}, not before ${time(r.not_before)} (requested ${time(r.requested_at)})`;
|
|
113
113
|
}
|
|
114
114
|
/** `shard ws suspend --when-idle`: the recorded request, or the suspend already in progress. */
|
|
115
115
|
export function suspendWhenIdleText(w, r) {
|
|
116
116
|
if (r.suspend_request) {
|
|
117
117
|
const s = r.suspend_request;
|
|
118
|
-
return (`Suspend when idle: ${w.key} (${w.id}) is suspended once it has been idle for ${s.after_seconds} s, not before ${time(s.not_before)}.\n` +
|
|
118
|
+
return (`Suspend when idle: ${w.key} (${w.id}) is suspended ${s.after_seconds === 0 ? 'as soon as it is idle' : `once it has been idle for ${s.after_seconds} s`}, not before ${time(s.not_before)}.\n` +
|
|
119
119
|
'A running command, an attached stream or a keepalive postpones it; the next tool call or a resume cancels it.\n' +
|
|
120
120
|
`cancel with: shard workspaces suspend ${w.key} --cancel-when-idle\n`);
|
|
121
121
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -22,4 +22,4 @@ export { openUrl, openerFor } from './browser.js';
|
|
|
22
22
|
export { EXIT, AuthConfigError, CheckoutEndedError, ExecutionFailedError, ExecutionPendingError, InterruptedError, MfaPendingError, NotFoundError, UsageError, describeError, exitCodeFor, redact } from './errors.js';
|
|
23
23
|
export type { ErrorInfo } from './errors.js';
|
|
24
24
|
export { changedText, errorText, executionJson, executionSummary, feedbackCommand, json, suspendRequestText, suspendWhenIdleText, table, time, usageText, workspaceDetail, workspaceTable } from './format.js';
|
|
25
|
-
export { TimingRecorder, timingJson, timingText } from './timing.js';
|
|
25
|
+
export { TimingRecorder, coldBootNotice, timingJson, timingText } from './timing.js';
|
package/dist/index.js
CHANGED
|
@@ -14,4 +14,4 @@ export { CHECK_INTERVAL_MS, CLI_DISTRIBUTION, NOTICE_WAIT_MS, UPDATE_CHECK_FILE,
|
|
|
14
14
|
export { openUrl, openerFor } from "./browser.js";
|
|
15
15
|
export { EXIT, AuthConfigError, CheckoutEndedError, ExecutionFailedError, ExecutionPendingError, InterruptedError, MfaPendingError, NotFoundError, UsageError, describeError, exitCodeFor, redact } from "./errors.js";
|
|
16
16
|
export { changedText, errorText, executionJson, executionSummary, feedbackCommand, json, suspendRequestText, suspendWhenIdleText, table, time, usageText, workspaceDetail, workspaceTable } from "./format.js";
|
|
17
|
-
export { TimingRecorder, timingJson, timingText } from "./timing.js";
|
|
17
|
+
export { TimingRecorder, coldBootNotice, timingJson, timingText } from "./timing.js";
|
package/dist/main.js
CHANGED
|
@@ -19,7 +19,7 @@ import { errorText, feedbackCommand, json, time } from "./format.js";
|
|
|
19
19
|
import { HANDLERS } from "./handlers.js";
|
|
20
20
|
import { makeFetch } from "./http.js";
|
|
21
21
|
import { Input } from "./input.js";
|
|
22
|
-
import { TimingRecorder, timingJson, timingText } from "./timing.js";
|
|
22
|
+
import { TimingRecorder, coldBootNotice, timingJson, timingText } from "./timing.js";
|
|
23
23
|
import { CLI_DISTRIBUTION, NOTICE_WAIT_MS, UpdateCheck, noticeOf, updateCheckDisabled, updateView } from "./update-check.js";
|
|
24
24
|
const KEY_SHAPE = /^sfk_[a-z2-7]{16}_[A-Za-z0-9]+$/;
|
|
25
25
|
// Printable (no C0 controls or DEL), as the API's AgentLabel pattern.
|
|
@@ -329,7 +329,7 @@ export async function run(argv, io, opts = {}) {
|
|
|
329
329
|
const feedback = nudges(info, command) ? feedbackCommand(info) : undefined;
|
|
330
330
|
const text = wantsJson
|
|
331
331
|
? json({ error: info, ...(showTiming ? { timing: timingJson(timing) } : {}), ...(feedback ? { feedback } : {}) })
|
|
332
|
-
: `${timing ? timingText(timing) : ''}${errorText(info, hint, feedback)}`;
|
|
332
|
+
: `${timing ? timingText(timing) : ''}${traces.coldBoot ? coldBootNotice(traces.coldBoot) : ''}${errorText(info, hint, feedback)}`;
|
|
333
333
|
io.stderr.write(redact(text, ...secrets));
|
|
334
334
|
return code;
|
|
335
335
|
};
|
|
@@ -562,6 +562,9 @@ export async function run(argv, io, opts = {}) {
|
|
|
562
562
|
// With --json the handler put the timing into its output; otherwise it follows the output, on stderr.
|
|
563
563
|
if (showTiming && !ctx.json && traces.last)
|
|
564
564
|
io.stderr.write(timingText(traces.last));
|
|
565
|
+
// A resume that booted the saved disk (0.6.0+): said on stderr with or without --timing, also with --json.
|
|
566
|
+
if (traces.coldBoot)
|
|
567
|
+
io.stderr.write(coldBootNotice(traces.coldBoot));
|
|
565
568
|
code = outcome.code;
|
|
566
569
|
}
|
|
567
570
|
// The update notice: after the output, never after Ctrl-C or a --json failure (stderr then holds only the error).
|
package/dist/timing.d.ts
CHANGED
|
@@ -4,6 +4,12 @@ export declare class TimingRecorder {
|
|
|
4
4
|
last: LifecycleTiming | null;
|
|
5
5
|
/** The operation the command's traced calls last observed: named when Ctrl-C interrupts a wait. */
|
|
6
6
|
operationId: string | null;
|
|
7
|
+
/**
|
|
8
|
+
* (0.6.0+) The last traced call whose resume booted the workspace's saved disk instead of restoring its memory
|
|
9
|
+
* (`resume_path` `cold_boot`, `memory_restored` false): a `ws resume --wait`, an `operations wait` of that resume, or
|
|
10
|
+
* the wake of a command that found the workspace suspended. `coldBootNotice()` says it.
|
|
11
|
+
*/
|
|
12
|
+
coldBoot: LifecycleTiming | null;
|
|
7
13
|
readonly listener: ProgressListener;
|
|
8
14
|
/**
|
|
9
15
|
* The failed call's own timing (`err.timing`) when the SDK attached one, else the last recorded. A refused tool token
|
|
@@ -11,6 +17,11 @@ export declare class TimingRecorder {
|
|
|
11
17
|
*/
|
|
12
18
|
forError(err: unknown): LifecycleTiming | null;
|
|
13
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* The one-line stderr notice after a command whose resume booted the workspace's saved disk (0.6.0+), with or without
|
|
22
|
+
* `--timing`: the workspace runs and its files are as of the suspend, but running processes were restarted.
|
|
23
|
+
*/
|
|
24
|
+
export declare function coldBootNotice(t: LifecycleTiming): string;
|
|
14
25
|
/** The human form (stderr): formatTiming() of the SDK, one block. */
|
|
15
26
|
export declare function timingText(t: LifecycleTiming): string;
|
|
16
27
|
/** The `--json` form: the SDK's LifecycleTiming with the CLI's snake_case keys (the rest of its JSON is the API's). */
|
package/dist/timing.js
CHANGED
|
@@ -11,13 +11,22 @@ export class TimingRecorder {
|
|
|
11
11
|
last = null;
|
|
12
12
|
/** The operation the command's traced calls last observed: named when Ctrl-C interrupts a wait. */
|
|
13
13
|
operationId = null;
|
|
14
|
+
/**
|
|
15
|
+
* (0.6.0+) The last traced call whose resume booted the workspace's saved disk instead of restoring its memory
|
|
16
|
+
* (`resume_path` `cold_boot`, `memory_restored` false): a `ws resume --wait`, an `operations wait` of that resume, or
|
|
17
|
+
* the wake of a command that found the workspace suspended. `coldBootNotice()` says it.
|
|
18
|
+
*/
|
|
19
|
+
coldBoot = null;
|
|
14
20
|
listener = (e) => {
|
|
15
21
|
if (e.action === 'token' || e.action === 'tool')
|
|
16
22
|
return;
|
|
17
23
|
if (e.operationId)
|
|
18
24
|
this.operationId = e.operationId;
|
|
19
|
-
if (e.type
|
|
20
|
-
|
|
25
|
+
if (e.type !== 'done')
|
|
26
|
+
return;
|
|
27
|
+
this.last = e.timing;
|
|
28
|
+
if (restartedProcesses(e.timing))
|
|
29
|
+
this.coldBoot = e.timing;
|
|
21
30
|
};
|
|
22
31
|
/**
|
|
23
32
|
* The failed call's own timing (`err.timing`) when the SDK attached one, else the last recorded. A refused tool token
|
|
@@ -28,6 +37,18 @@ export class TimingRecorder {
|
|
|
28
37
|
return own && own.action !== 'token' ? own : this.last;
|
|
29
38
|
}
|
|
30
39
|
}
|
|
40
|
+
/** A resume that booted the saved disk: files as of the suspend, every process restarted (never a null memory_restored). */
|
|
41
|
+
function restartedProcesses(t) {
|
|
42
|
+
return t.server?.resumePath === 'cold_boot' && t.server.memoryRestored === false;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The one-line stderr notice after a command whose resume booted the workspace's saved disk (0.6.0+), with or without
|
|
46
|
+
* `--timing`: the workspace runs and its files are as of the suspend, but running processes were restarted.
|
|
47
|
+
*/
|
|
48
|
+
export function coldBootNotice(t) {
|
|
49
|
+
const reason = t.server?.coldBootReason;
|
|
50
|
+
return `note: ${t.workspaceId ? `workspace ${t.workspaceId} ` : ''}resumed from its saved disk; running processes were restarted${reason ? ` (${reason})` : ''}\n`;
|
|
51
|
+
}
|
|
31
52
|
/** The human form (stderr): formatTiming() of the SDK, one block. */
|
|
32
53
|
export function timingText(t) {
|
|
33
54
|
return `${formatTiming(t)}\n`;
|
|
@@ -56,6 +77,8 @@ export function timingJson(t) {
|
|
|
56
77
|
start_path: s.startPath,
|
|
57
78
|
warm_fallback: s.warmFallback,
|
|
58
79
|
resume_path: s.resumePath,
|
|
80
|
+
memory_restored: s.memoryRestored ?? null,
|
|
81
|
+
cold_boot_reason: s.coldBootReason ?? null,
|
|
59
82
|
boot_to_ready_ms: s.bootToReadyMs,
|
|
60
83
|
host_timings_ms: s.hostTimingsMs,
|
|
61
84
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shardflux/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "shard: the Shardflux command line. Create an account, sign in, set up keys and billing, then open, run commands in, move files to, suspend, resume and fork persistent agent workspaces.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"yaml": "2.9.1",
|
|
47
|
-
"@shardflux/sdk": "^0.
|
|
47
|
+
"@shardflux/sdk": "^0.11.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@eslint/js": "10.0.1",
|