@skrr-ai/cli 0.1.108 → 0.1.110
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 +10 -0
- package/dist/base-command.d.ts +74 -0
- package/dist/base-command.js +182 -24
- package/dist/commands/agents/triggers/create.js +1 -1
- package/dist/commands/agents/triggers/update.js +1 -1
- package/dist/commands/agents/update.d.ts +25 -0
- package/dist/commands/agents/update.js +98 -3
- package/dist/commands/commitments/accounting.js +7 -2
- package/dist/commands/commitments/cost.d.ts +11 -0
- package/dist/commands/commitments/cost.js +26 -3
- package/dist/commands/commitments/create.js +2 -1
- package/dist/commands/commitments/operating-review.d.ts +15 -0
- package/dist/commands/commitments/operating-review.js +103 -50
- package/dist/commands/commitments/update.js +12 -5
- package/dist/commands/daemon/install.js +17 -1
- package/dist/commands/daemon/login.js +14 -0
- package/dist/commands/doctor.js +9 -0
- package/dist/commands/goals/list.js +6 -1
- package/dist/commands/grants/rotate.js +4 -0
- package/dist/commands/harnesses/prune.d.ts +26 -0
- package/dist/commands/harnesses/prune.js +172 -0
- package/dist/commands/login.js +53 -14
- package/dist/commands/machines/list.js +28 -6
- package/dist/commands/projects/show.js +1 -1
- package/dist/commands/revoke-daemon.js +2 -1
- package/dist/commands/spaces/workflows/archive.d.ts +1 -0
- package/dist/commands/spaces/workflows/archive.js +1 -0
- package/dist/commands/spaces/workflows/artifact.d.ts +1 -0
- package/dist/commands/spaces/workflows/artifact.js +1 -0
- package/dist/commands/spaces/workflows/cancel-node.d.ts +1 -0
- package/dist/commands/spaces/workflows/cancel-node.js +1 -0
- package/dist/commands/spaces/workflows/cancel.d.ts +1 -0
- package/dist/commands/spaces/workflows/cancel.js +6 -2
- package/dist/commands/spaces/workflows/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/create.js +7 -1
- package/dist/commands/spaces/workflows/events.d.ts +1 -0
- package/dist/commands/spaces/workflows/events.js +1 -0
- package/dist/commands/spaces/workflows/fixtures/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/fixtures/create.js +1 -0
- package/dist/commands/spaces/workflows/fixtures/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/fixtures/list.js +1 -0
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +1 -0
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +1 -0
- package/dist/commands/spaces/workflows/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/list.js +1 -0
- package/dist/commands/spaces/workflows/node-types.d.ts +2 -0
- package/dist/commands/spaces/workflows/node-types.js +24 -6
- package/dist/commands/spaces/workflows/pause.d.ts +1 -0
- package/dist/commands/spaces/workflows/pause.js +1 -0
- package/dist/commands/spaces/workflows/plan/show.d.ts +1 -0
- package/dist/commands/spaces/workflows/plan/show.js +1 -0
- package/dist/commands/spaces/workflows/plan/update.d.ts +1 -0
- package/dist/commands/spaces/workflows/plan/update.js +1 -0
- package/dist/commands/spaces/workflows/proposals/apply.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/apply.js +1 -0
- package/dist/commands/spaces/workflows/proposals/confirm.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/confirm.js +1 -0
- package/dist/commands/spaces/workflows/proposals/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/create.js +1 -0
- package/dist/commands/spaces/workflows/proposals/dismiss.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/dismiss.js +1 -0
- package/dist/commands/spaces/workflows/proposals/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/proposals/list.js +1 -0
- package/dist/commands/spaces/workflows/publish.d.ts +1 -0
- package/dist/commands/spaces/workflows/publish.js +9 -0
- package/dist/commands/spaces/workflows/reconcile.d.ts +1 -0
- package/dist/commands/spaces/workflows/reconcile.js +1 -0
- package/dist/commands/spaces/workflows/resume.d.ts +1 -0
- package/dist/commands/spaces/workflows/resume.js +1 -0
- package/dist/commands/spaces/workflows/retry.d.ts +1 -0
- package/dist/commands/spaces/workflows/retry.js +1 -0
- package/dist/commands/spaces/workflows/run.d.ts +1 -0
- package/dist/commands/spaces/workflows/run.js +14 -7
- package/dist/commands/spaces/workflows/runs.d.ts +1 -0
- package/dist/commands/spaces/workflows/runs.js +1 -0
- package/dist/commands/spaces/workflows/show.d.ts +25 -0
- package/dist/commands/spaces/workflows/show.js +42 -4
- package/dist/commands/spaces/workflows/signal.d.ts +12 -0
- package/dist/commands/spaces/workflows/signal.js +40 -2
- package/dist/commands/spaces/workflows/start.d.ts +1 -0
- package/dist/commands/spaces/workflows/start.js +4 -1
- package/dist/commands/spaces/workflows/task-execution/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/task-execution/create.js +1 -0
- package/dist/commands/spaces/workflows/test.d.ts +1 -0
- package/dist/commands/spaces/workflows/test.js +1 -0
- package/dist/commands/spaces/workflows/triggers/create.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/create.js +1 -0
- package/dist/commands/spaces/workflows/triggers/fire.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/fire.js +1 -0
- package/dist/commands/spaces/workflows/triggers/list.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/list.js +1 -0
- package/dist/commands/spaces/workflows/triggers/update.d.ts +1 -0
- package/dist/commands/spaces/workflows/triggers/update.js +1 -0
- package/dist/commands/spaces/workflows/update.d.ts +1 -0
- package/dist/commands/spaces/workflows/update.js +4 -0
- package/dist/commands/spaces/workflows/validate.d.ts +1 -0
- package/dist/commands/spaces/workflows/validate.js +27 -2
- package/dist/commands/tasks/activity.js +17 -3
- package/dist/commands/tasks/bulk-update.d.ts +1 -0
- package/dist/commands/tasks/bulk-update.js +7 -0
- package/dist/commands/tasks/complete.js +2 -1
- package/dist/commands/tasks/create-tree.d.ts +69 -0
- package/dist/commands/tasks/create-tree.js +413 -47
- package/dist/commands/tasks/list.d.ts +2 -0
- package/dist/commands/tasks/list.js +25 -3
- package/dist/commands/tasks/rearm-recurrence.d.ts +22 -0
- package/dist/commands/tasks/rearm-recurrence.js +87 -0
- package/dist/commands/tasks/show.d.ts +9 -0
- package/dist/commands/tasks/show.js +79 -33
- package/dist/commands/tasks/timeline.js +4 -0
- package/dist/commands/tasks/unschedule.js +5 -1
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +17 -2
- package/dist/commands/triggers/audit.js +12 -3
- package/dist/commands/triggers/create.js +9 -3
- package/dist/commands/triggers/fire-detail.d.ts +7 -0
- package/dist/commands/triggers/fire-detail.js +30 -12
- package/dist/commands/triggers/fire.js +13 -3
- package/dist/commands/triggers/parse-intent.d.ts +7 -0
- package/dist/commands/triggers/parse-intent.js +31 -9
- package/dist/commands/triggers/update.js +1 -1
- package/dist/commands/workspaces/grants.js +20 -3
- package/dist/commands/workspaces/members.d.ts +20 -0
- package/dist/commands/workspaces/members.js +64 -0
- package/dist/commands/workspaces/stewardship.js +14 -2
- package/dist/help.js +12 -0
- package/dist/hooks/command-not-found.js +27 -1
- package/dist/lib/command-miss.d.ts +52 -2
- package/dist/lib/command-miss.js +187 -18
- package/dist/lib/commitment-loop-status.d.ts +8 -0
- package/dist/lib/commitment-loop-status.js +45 -0
- package/dist/lib/commitment-product.js +5 -2
- package/dist/lib/commitments.d.ts +18 -3
- package/dist/lib/commitments.js +85 -45
- package/dist/lib/daemon-command-hint.d.ts +15 -0
- package/dist/lib/daemon-command-hint.js +21 -0
- package/dist/lib/daemon-machine-identity-copy.d.ts +14 -0
- package/dist/lib/daemon-machine-identity-copy.js +27 -0
- package/dist/lib/daemon-machine-identity.d.ts +27 -0
- package/dist/lib/daemon-machine-identity.js +61 -0
- package/dist/lib/daemon-setup.js +10 -1
- package/dist/lib/daemonBrokerRefusal.js +3 -2
- package/dist/lib/daemonHandoff.d.ts +19 -1
- package/dist/lib/daemonHandoff.js +61 -1
- package/dist/lib/deployed-build.d.ts +43 -0
- package/dist/lib/deployed-build.js +66 -0
- package/dist/lib/grants.d.ts +27 -1
- package/dist/lib/grants.js +39 -21
- package/dist/lib/harnesses.d.ts +71 -0
- package/dist/lib/harnesses.js +70 -0
- package/dist/lib/json-mode.d.ts +11 -0
- package/dist/lib/json-mode.js +19 -0
- package/dist/lib/json-output.d.ts +25 -0
- package/dist/lib/json-output.js +30 -0
- package/dist/lib/list-output.d.ts +10 -1
- package/dist/lib/list-output.js +22 -1
- package/dist/lib/local-daemon-readiness.d.ts +90 -0
- package/dist/lib/local-daemon-readiness.js +143 -0
- package/dist/lib/machines.d.ts +117 -0
- package/dist/lib/machines.js +139 -0
- package/dist/lib/managed-instruction-local.d.ts +2 -0
- package/dist/lib/managed-instruction-local.js +2 -0
- package/dist/lib/profile-machine-identity-guard.d.ts +18 -0
- package/dist/lib/profile-machine-identity-guard.js +39 -0
- package/dist/lib/request-field-flags.d.ts +20 -0
- package/dist/lib/request-field-flags.js +34 -0
- package/dist/lib/stewardship-output.d.ts +1 -1
- package/dist/lib/stewardship-output.js +26 -30
- package/dist/lib/task-batch.d.ts +61 -4
- package/dist/lib/task-batch.js +316 -80
- package/dist/lib/task-economics.d.ts +15 -0
- package/dist/lib/task-economics.js +39 -2
- package/dist/lib/task-recurrence-outcome.d.ts +6 -6
- package/dist/lib/task-recurrence-outcome.js +27 -3
- package/dist/lib/tasks.d.ts +39 -0
- package/dist/lib/tasks.js +132 -0
- package/dist/lib/triggers.d.ts +42 -1
- package/dist/lib/triggers.js +98 -2
- package/dist/lib/workflow-issues.d.ts +14 -0
- package/dist/lib/workflow-issues.js +32 -0
- package/dist/lib/workflow-run-view.d.ts +59 -0
- package/dist/lib/workflow-run-view.js +110 -0
- package/dist/lib/workspaces.d.ts +48 -4
- package/dist/lib/workspaces.js +55 -0
- package/dist/lib/write-target.d.ts +29 -0
- package/dist/lib/write-target.js +72 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +5 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.d.ts +60 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +130 -6
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/workspaceIsolationProbeWire.d.ts +51 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/workspaceIsolationProbeWire.js +50 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.d.ts +60 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +128 -6
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/workspaceIsolationProbeWire.d.ts +51 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/workspaceIsolationProbeWire.js +46 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +7523 -7140
- package/oclif.manifest.json +473 -59
- package/package.json +28 -1
package/dist/lib/harnesses.js
CHANGED
|
@@ -13,6 +13,9 @@ exports.listQuotaAccounts = listQuotaAccounts;
|
|
|
13
13
|
exports.getQuotaHistory = getQuotaHistory;
|
|
14
14
|
exports.updateHarness = updateHarness;
|
|
15
15
|
exports.forgetHarness = forgetHarness;
|
|
16
|
+
exports.pruneHarnesses = pruneHarnesses;
|
|
17
|
+
exports.parseHarnessPruneAge = parseHarnessPruneAge;
|
|
18
|
+
exports.harnessPruneReasonSentence = harnessPruneReasonSentence;
|
|
16
19
|
exports.setHarnessAlias = setHarnessAlias;
|
|
17
20
|
exports.setDefaultHarness = setDefaultHarness;
|
|
18
21
|
exports.mintInstallToken = mintInstallToken;
|
|
@@ -173,6 +176,73 @@ async function updateHarness(id, patch) {
|
|
|
173
176
|
async function forgetHarness(id) {
|
|
174
177
|
return (0, api_fetch_1.apiFetch)(`/api/harnesses/${encodeURIComponent(id)}`, { method: 'DELETE' });
|
|
175
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* Remove the caller's superseded harness rows - or, by default, say which would go.
|
|
181
|
+
*
|
|
182
|
+
* ONE route for both: the server makes the decision once and this only asks for it
|
|
183
|
+
* to be shown (`dryRun: true`, also its own default) or carried out. The caller
|
|
184
|
+
* never lists rows and picks, so there is no client-side rule to drift from the
|
|
185
|
+
* server's. A write, so `apiFetch` gives it an idempotency key and a retried
|
|
186
|
+
* request replays the recorded answer instead of running again.
|
|
187
|
+
*/
|
|
188
|
+
async function pruneHarnesses(options = { dryRun: true }) {
|
|
189
|
+
return (0, api_fetch_1.apiFetch)('/api/harnesses/prune', {
|
|
190
|
+
method: 'POST',
|
|
191
|
+
body: {
|
|
192
|
+
dryRun: options.dryRun,
|
|
193
|
+
...(options.limit !== undefined ? { limit: options.limit } : {}),
|
|
194
|
+
...(options.minUnseenMs !== undefined ? { minUnseenMs: options.minUnseenMs } : {}),
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* `--older-than` takes a whole number with a unit: `90m`, `36h`, `7d`. A bare
|
|
200
|
+
* number is hours. Returns milliseconds. The server never goes below its offline
|
|
201
|
+
* window whatever this says.
|
|
202
|
+
*/
|
|
203
|
+
function parseHarnessPruneAge(value) {
|
|
204
|
+
const match = value.trim().match(/^(\d+)\s*(m|h|d)?$/i);
|
|
205
|
+
if (!match) {
|
|
206
|
+
throw new Error(`Invalid --older-than value "${value}". Use a number with m, h or d, such as 90m, 36h or 7d.`);
|
|
207
|
+
}
|
|
208
|
+
const amount = Number(match[1]);
|
|
209
|
+
const unit = (match[2] || 'h').toLowerCase();
|
|
210
|
+
const perUnit = unit === 'd' ? 86_400_000 : unit === 'h' ? 3_600_000 : 60_000;
|
|
211
|
+
return amount * perUnit;
|
|
212
|
+
}
|
|
213
|
+
/** One sentence per reason a row was kept. The only place they are worded. */
|
|
214
|
+
function harnessPruneReasonSentence(row) {
|
|
215
|
+
switch (row.reason) {
|
|
216
|
+
case 'recent':
|
|
217
|
+
return 'seen too recently to be sure it is gone';
|
|
218
|
+
case 'latest_registration':
|
|
219
|
+
return 'the newest registration of its provider on that machine';
|
|
220
|
+
case 'no_live_sibling':
|
|
221
|
+
return 'nothing has replaced it - no daemon on that machine is online for this provider';
|
|
222
|
+
case 'pinned': {
|
|
223
|
+
const names = (row.detail?.agents ?? []).map((a) => a.name ?? a.id);
|
|
224
|
+
const more = row.detail?.moreAgents ?? 0;
|
|
225
|
+
const others = row.detail?.otherAuthors ?? 0;
|
|
226
|
+
const parts = [];
|
|
227
|
+
if (names.length > 0) {
|
|
228
|
+
parts.push(`${names.join(', ')}${more > 0 ? ` and ${more} more` : ''}`);
|
|
229
|
+
}
|
|
230
|
+
if (others > 0)
|
|
231
|
+
parts.push(`${others} agent${others === 1 ? '' : 's'} of other people`);
|
|
232
|
+
return `agents are pinned to it${parts.length > 0 ? ` (${parts.join('; ')})` : ''}`;
|
|
233
|
+
}
|
|
234
|
+
case 'granted':
|
|
235
|
+
return 'it is lent to a workspace';
|
|
236
|
+
case 'default':
|
|
237
|
+
return 'it is your default harness';
|
|
238
|
+
case 'aliased':
|
|
239
|
+
return 'you gave it a name';
|
|
240
|
+
case 'changed_since_plan':
|
|
241
|
+
return 'it changed while this ran (came back online, or was pinned)';
|
|
242
|
+
default:
|
|
243
|
+
return String(row.reason ?? 'kept');
|
|
244
|
+
}
|
|
245
|
+
}
|
|
176
246
|
/**
|
|
177
247
|
* A per-USER display name. Distinct from `updateHarness({name})`, which renames
|
|
178
248
|
* the harness for everyone it is shared with — this only changes what YOU see,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a `skrr` invocation asked for JSON — ONE definition.
|
|
3
|
+
*
|
|
4
|
+
* `BaseCommand` decides this for a command that is running. A command that was
|
|
5
|
+
* never found has no `BaseCommand`: the `command_not_found` hook runs before one
|
|
6
|
+
* exists, so it asked nothing and printed prose to stderr, and a script that
|
|
7
|
+
* piped `--json` output to `jq` got "parse error: Invalid numeric literal"
|
|
8
|
+
* instead of the refusal (OSK-16434). Both now read the same rule, so a flag
|
|
9
|
+
* added to one cannot be missing from the other.
|
|
10
|
+
*/
|
|
11
|
+
export declare function wantsJsonFromArgv(argv: readonly string[], env?: NodeJS.ProcessEnv): boolean;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wantsJsonFromArgv = wantsJsonFromArgv;
|
|
4
|
+
/**
|
|
5
|
+
* Whether a `skrr` invocation asked for JSON — ONE definition.
|
|
6
|
+
*
|
|
7
|
+
* `BaseCommand` decides this for a command that is running. A command that was
|
|
8
|
+
* never found has no `BaseCommand`: the `command_not_found` hook runs before one
|
|
9
|
+
* exists, so it asked nothing and printed prose to stderr, and a script that
|
|
10
|
+
* piped `--json` output to `jq` got "parse error: Invalid numeric literal"
|
|
11
|
+
* instead of the refusal (OSK-16434). Both now read the same rule, so a flag
|
|
12
|
+
* added to one cannot be missing from the other.
|
|
13
|
+
*/
|
|
14
|
+
function wantsJsonFromArgv(argv, env = process.env) {
|
|
15
|
+
return (argv.includes('--json') ||
|
|
16
|
+
argv.includes('--ndjson') ||
|
|
17
|
+
env.SKY_JSON === '1' ||
|
|
18
|
+
env.OVERSKY_CLI_JSON === '1');
|
|
19
|
+
}
|
|
@@ -28,4 +28,29 @@ export declare function stripStorageFields(value: Json): Json;
|
|
|
28
28
|
* untouched, as is JSON with nothing to strip, so existing formatting survives.
|
|
29
29
|
*/
|
|
30
30
|
export declare function stripStorageFieldsFromText(text: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* The outcome marker for a `--json` RESULT document (OSK-16425).
|
|
33
|
+
*
|
|
34
|
+
* A failure prints `{ok:false, error:{...}}` on stdout, so that agents get the
|
|
35
|
+
* refusal structured. A success printed whatever the server sent, with no `ok`
|
|
36
|
+
* at all — so a script could not test one field for both, and a projection such
|
|
37
|
+
* as `jq '{id, title}'` turned the error document into `{"id":null,"title":null}`,
|
|
38
|
+
* which reads as an empty success. The reporter's own diagnosis of a failed
|
|
39
|
+
* command was wrong for exactly that reason.
|
|
40
|
+
*
|
|
41
|
+
* Adding `ok` here, to a document a command already holds, is truthful by
|
|
42
|
+
* construction: the caller knows whether the command succeeded when it prints.
|
|
43
|
+
* It is NOT done to text in `BaseCommand.log`, the way storage fields are
|
|
44
|
+
* stripped, because `log` cannot see the exit status to come: `doctor`,
|
|
45
|
+
* `tasks wait`, `outbox retry` and `code install` print a document and then
|
|
46
|
+
* exit non-zero, and stamping `ok:true` on those would assert a success the
|
|
47
|
+
* exit code denies.
|
|
48
|
+
*
|
|
49
|
+
* Only an object can carry it. An array is returned as it is, and so is an
|
|
50
|
+
* object that already says `ok` — that command's own meaning wins. `ok` is put
|
|
51
|
+
* first so it is the first thing read.
|
|
52
|
+
*/
|
|
53
|
+
export declare function withOk<T>(value: T, ok?: boolean): T | ({
|
|
54
|
+
ok: boolean;
|
|
55
|
+
} & Record<string, unknown>);
|
|
31
56
|
export {};
|
package/dist/lib/json-output.js
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
exports.stripStorageFields = stripStorageFields;
|
|
22
22
|
exports.stripStorageFieldsFromText = stripStorageFieldsFromText;
|
|
23
|
+
exports.withOk = withOk;
|
|
23
24
|
function usableId(value) {
|
|
24
25
|
return (typeof value === 'string' && value.length > 0) || typeof value === 'number';
|
|
25
26
|
}
|
|
@@ -76,3 +77,32 @@ function stripStorageFieldsFromText(text) {
|
|
|
76
77
|
return text;
|
|
77
78
|
return JSON.stringify(stripped, null, text.includes('\n') ? 2 : undefined);
|
|
78
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* The outcome marker for a `--json` RESULT document (OSK-16425).
|
|
82
|
+
*
|
|
83
|
+
* A failure prints `{ok:false, error:{...}}` on stdout, so that agents get the
|
|
84
|
+
* refusal structured. A success printed whatever the server sent, with no `ok`
|
|
85
|
+
* at all — so a script could not test one field for both, and a projection such
|
|
86
|
+
* as `jq '{id, title}'` turned the error document into `{"id":null,"title":null}`,
|
|
87
|
+
* which reads as an empty success. The reporter's own diagnosis of a failed
|
|
88
|
+
* command was wrong for exactly that reason.
|
|
89
|
+
*
|
|
90
|
+
* Adding `ok` here, to a document a command already holds, is truthful by
|
|
91
|
+
* construction: the caller knows whether the command succeeded when it prints.
|
|
92
|
+
* It is NOT done to text in `BaseCommand.log`, the way storage fields are
|
|
93
|
+
* stripped, because `log` cannot see the exit status to come: `doctor`,
|
|
94
|
+
* `tasks wait`, `outbox retry` and `code install` print a document and then
|
|
95
|
+
* exit non-zero, and stamping `ok:true` on those would assert a success the
|
|
96
|
+
* exit code denies.
|
|
97
|
+
*
|
|
98
|
+
* Only an object can carry it. An array is returned as it is, and so is an
|
|
99
|
+
* object that already says `ok` — that command's own meaning wins. `ok` is put
|
|
100
|
+
* first so it is the first thing read.
|
|
101
|
+
*/
|
|
102
|
+
function withOk(value, ok = true) {
|
|
103
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
104
|
+
return value;
|
|
105
|
+
if (Object.prototype.hasOwnProperty.call(value, 'ok'))
|
|
106
|
+
return value;
|
|
107
|
+
return { ok, ...value };
|
|
108
|
+
}
|
|
@@ -18,7 +18,7 @@ export type ListEnvelope = {
|
|
|
18
18
|
* Documented in docs/cli/SKRR_TASKS.md (List output for agents).
|
|
19
19
|
*/
|
|
20
20
|
export declare const COMPACT_FIELDS: {
|
|
21
|
-
readonly task: readonly ["id", "identifier", "ref", "title", "status", "statusType", "priority", "estimate", "assigneeAgentIds", "assigneeUserIds", "parentId", "spaceId", "projectId", "goalId", "dueDate", "scheduledFor", "labelIds", "tags", "externalKey", "version", "executionMode", "nextAction", "createdAt", "updatedAt", "url"];
|
|
21
|
+
readonly task: readonly ["id", "identifier", "ref", "title", "status", "statusType", "priority", "estimate", "assigneeAgentIds", "assigneeUserIds", "parentId", "spaceId", "projectId", "goalId", "dueDate", "scheduledFor", "labelIds", "tags", "externalKey", "version", "executionMode", "nextAction", "economicsRank", "createdAt", "updatedAt", "url"];
|
|
22
22
|
readonly space: readonly ["id", "identifier", "title", "status", "parentSpaceId", "leadAgentId", "labelIds", "archivedAt", "createdAt", "updatedAt", "url"];
|
|
23
23
|
readonly project: readonly ["id", "identifier", "title", "spaceId", "externalKey", "taskCounts", "archivedAt", "createdAt", "updatedAt", "url"];
|
|
24
24
|
};
|
|
@@ -64,6 +64,15 @@ export declare function limitNote(requested: number | undefined, rowCount: numbe
|
|
|
64
64
|
};
|
|
65
65
|
/** The text-mode twin of a warning: one `Note:` line a person can act on. */
|
|
66
66
|
export declare function warningLines(warnings: readonly ListWarning[] | undefined): string[];
|
|
67
|
+
/**
|
|
68
|
+
* The note a TABLE prints when it was given a JSON-only projection flag. `--compact` and
|
|
69
|
+
* `--fields` shape JSON output; on the table they did nothing and said nothing, so `--compact`
|
|
70
|
+
* looked broken (OSK-15374). Empty when neither flag was given.
|
|
71
|
+
*/
|
|
72
|
+
export declare function textModeProjectionNotes(flags: {
|
|
73
|
+
fields?: string;
|
|
74
|
+
compact?: boolean;
|
|
75
|
+
}): string[];
|
|
67
76
|
export type ListOutput = {
|
|
68
77
|
stdout: string[];
|
|
69
78
|
stderr: string[];
|
package/dist/lib/list-output.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.toListEnvelope = toListEnvelope;
|
|
|
7
7
|
exports.shapeListResponse = shapeListResponse;
|
|
8
8
|
exports.limitNote = limitNote;
|
|
9
9
|
exports.warningLines = warningLines;
|
|
10
|
+
exports.textModeProjectionNotes = textModeProjectionNotes;
|
|
10
11
|
exports.renderListOutput = renderListOutput;
|
|
11
12
|
/**
|
|
12
13
|
* Shared output shaping for `skrr` LIST commands (agent-surface audit
|
|
@@ -29,6 +30,7 @@ exports.renderListOutput = renderListOutput;
|
|
|
29
30
|
* Pure functions, no oclif: the commands own I/O, this owns the shape.
|
|
30
31
|
*/
|
|
31
32
|
const core_1 = require("@oclif/core");
|
|
33
|
+
const json_output_1 = require("./json-output");
|
|
32
34
|
/**
|
|
33
35
|
* The navigation projection per resource: enough to identify a row, decide
|
|
34
36
|
* whether it matters and fetch it with `show`. Allowlists, not drop-lists, so a
|
|
@@ -59,6 +61,8 @@ exports.COMPACT_FIELDS = {
|
|
|
59
61
|
'version',
|
|
60
62
|
'executionMode',
|
|
61
63
|
'nextAction',
|
|
64
|
+
// Present only on a `--rank economics` page: the score the row was sorted by (OSK-16476).
|
|
65
|
+
'economicsRank',
|
|
62
66
|
'createdAt',
|
|
63
67
|
'updatedAt',
|
|
64
68
|
'url',
|
|
@@ -206,7 +210,11 @@ function shapeListResponse(response, options) {
|
|
|
206
210
|
if (limit.warning)
|
|
207
211
|
warnings.push(limit.warning);
|
|
208
212
|
return {
|
|
209
|
-
|
|
213
|
+
// A list that reached this shaper succeeded; a failure never does, and prints
|
|
214
|
+
// `{ok:false, error}`. Saying so lets a script test one field for both, and
|
|
215
|
+
// keeps a projection of a failure from reading as an empty list (OSK-16425).
|
|
216
|
+
// The server's own `ok`, if it sent one, is kept.
|
|
217
|
+
...(0, json_output_1.withOk)(envelope),
|
|
210
218
|
data,
|
|
211
219
|
...(limit.applied !== undefined ? { limit_applied: limit.applied } : {}),
|
|
212
220
|
...(options.filterApplied ? { filter_applied: options.filterApplied } : {}),
|
|
@@ -247,6 +255,19 @@ function limitNote(requested, rowCount, hasMore) {
|
|
|
247
255
|
function warningLines(warnings) {
|
|
248
256
|
return (warnings ?? []).map((w) => `Note: ${w.hint}`);
|
|
249
257
|
}
|
|
258
|
+
/**
|
|
259
|
+
* The note a TABLE prints when it was given a JSON-only projection flag. `--compact` and
|
|
260
|
+
* `--fields` shape JSON output; on the table they did nothing and said nothing, so `--compact`
|
|
261
|
+
* looked broken (OSK-15374). Empty when neither flag was given.
|
|
262
|
+
*/
|
|
263
|
+
function textModeProjectionNotes(flags) {
|
|
264
|
+
const given = [flags.fields ? '--fields' : null, flags.compact ? '--compact' : null].filter(Boolean);
|
|
265
|
+
if (given.length === 0)
|
|
266
|
+
return [];
|
|
267
|
+
return [
|
|
268
|
+
`Note: ${given.join(' and ')} ${given.length > 1 ? 'shape' : 'shapes'} JSON output only; the table is unchanged. Add --json (or --ndjson) to apply ${given.length > 1 ? 'them' : 'it'}.`,
|
|
269
|
+
];
|
|
270
|
+
}
|
|
250
271
|
/**
|
|
251
272
|
* Render a shaped list for `--json` (pretty envelope) or `--ndjson` (rows one per
|
|
252
273
|
* line, `_meta` on stderr). Pure; the caller writes the lines.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the local daemon is actually signed in and connected — as opposed to
|
|
3
|
+
* having been handed a credential (OSK-16437).
|
|
4
|
+
*
|
|
5
|
+
* `skrr login` used to print "The local daemon was signed in too" the moment
|
|
6
|
+
* `accept-handoff` exited 0. That means the credential was WRITTEN. It says
|
|
7
|
+
* nothing about a daemon using it, and a handoff that wrote a credential for a
|
|
8
|
+
* service that was not running, or that the server then refused, left a login
|
|
9
|
+
* that announced success on one line and failed to verify it on the next, with
|
|
10
|
+
* nothing saying which was true. `skrr daemon start` learned the same lesson
|
|
11
|
+
* ("a supervisor's successful `kickstart` means only that it accepted the
|
|
12
|
+
* request") and asks the daemon itself; this is that question for login.
|
|
13
|
+
*
|
|
14
|
+
* Two probes, in order of how directly they answer:
|
|
15
|
+
*
|
|
16
|
+
* 1. the loopback identity endpoint of THIS profile's daemon, which says it is
|
|
17
|
+
* connected as this account on this server — the only proof;
|
|
18
|
+
* 2. `skrrd status --json`, asked only once the first has not answered, to say
|
|
19
|
+
* WHY: the server refused the credential, the service is not running, or it
|
|
20
|
+
* is running and has not connected yet. Those have different fixes.
|
|
21
|
+
*/
|
|
22
|
+
export type LocalDaemonReadiness = {
|
|
23
|
+
state: 'connected';
|
|
24
|
+
daemonId: string;
|
|
25
|
+
} | {
|
|
26
|
+
state: 'reauth_required';
|
|
27
|
+
profile: string;
|
|
28
|
+
reason: string | null;
|
|
29
|
+
command: string;
|
|
30
|
+
} | {
|
|
31
|
+
state: 'not_running';
|
|
32
|
+
profile: string;
|
|
33
|
+
runtimeStatus: string | null;
|
|
34
|
+
} | {
|
|
35
|
+
state: 'not_connected';
|
|
36
|
+
profile: string;
|
|
37
|
+
} | {
|
|
38
|
+
state: 'unreadable';
|
|
39
|
+
profile: string;
|
|
40
|
+
};
|
|
41
|
+
export interface ReadinessDeps {
|
|
42
|
+
/** One look at the loopback identity endpoint; the daemon id when it is connected as us. */
|
|
43
|
+
inspect: () => Promise<string | null>;
|
|
44
|
+
/** `skrrd status --json` for this profile. */
|
|
45
|
+
status: () => Promise<{
|
|
46
|
+
stdout: string;
|
|
47
|
+
code: number;
|
|
48
|
+
}>;
|
|
49
|
+
now: () => number;
|
|
50
|
+
sleep: (ms: number) => Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
export interface ConfirmOptions {
|
|
53
|
+
/** How long a daemon that is still starting gets. */
|
|
54
|
+
waitMs?: number;
|
|
55
|
+
pollMs?: number;
|
|
56
|
+
/** How long a service that reads `stopped` is given before it is believed. */
|
|
57
|
+
stoppedGraceMs?: number;
|
|
58
|
+
/** Progress, printed once and only when the first look found nothing. */
|
|
59
|
+
log?: (line: string) => void;
|
|
60
|
+
deps?: Partial<ReadinessDeps>;
|
|
61
|
+
}
|
|
62
|
+
export declare function confirmLocalDaemonSignedIn(options?: ConfirmOptions): Promise<LocalDaemonReadiness>;
|
|
63
|
+
/**
|
|
64
|
+
* What `skrr login` prints about a daemon that was handed a credential and did
|
|
65
|
+
* not come up with it: what happened, why, and the one command. Pure, so every
|
|
66
|
+
* state can be read without a daemon.
|
|
67
|
+
*/
|
|
68
|
+
export declare function describeUnreadyLocalDaemon(readiness: Exclude<LocalDaemonReadiness, {
|
|
69
|
+
state: 'connected';
|
|
70
|
+
}>, commands: {
|
|
71
|
+
status: string;
|
|
72
|
+
logs: string;
|
|
73
|
+
start: string;
|
|
74
|
+
}): string[];
|
|
75
|
+
/**
|
|
76
|
+
* The end of `skrr login` for a daemon that was handed a credential: wait for it
|
|
77
|
+
* to connect, then say ONE true thing. "Signed in too" only for a daemon that
|
|
78
|
+
* verified connected as this account; otherwise what happened, why, and the one
|
|
79
|
+
* command — and never both, which is what the login used to do.
|
|
80
|
+
*/
|
|
81
|
+
export declare function reportLocalDaemonAfterHandoff(options: {
|
|
82
|
+
/** `skrr login` may have been handed the daemon's account/deployment line already. */
|
|
83
|
+
deliveredDetail: string;
|
|
84
|
+
bin: string;
|
|
85
|
+
log: (line: string) => void;
|
|
86
|
+
confirm?: typeof confirmLocalDaemonSignedIn;
|
|
87
|
+
}): Promise<{
|
|
88
|
+
daemonId?: string;
|
|
89
|
+
notReady: boolean;
|
|
90
|
+
}>;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.confirmLocalDaemonSignedIn = confirmLocalDaemonSignedIn;
|
|
4
|
+
exports.describeUnreadyLocalDaemon = describeUnreadyLocalDaemon;
|
|
5
|
+
exports.reportLocalDaemonAfterHandoff = reportLocalDaemonAfterHandoff;
|
|
6
|
+
const exec_runtime_binary_1 = require("./exec-runtime-binary");
|
|
7
|
+
const managed_instruction_local_1 = require("./managed-instruction-local");
|
|
8
|
+
const keychain_1 = require("./keychain");
|
|
9
|
+
const config_1 = require("./config");
|
|
10
|
+
const runtime_start_verification_1 = require("./runtime-start-verification");
|
|
11
|
+
const daemon_command_hint_1 = require("./daemon-command-hint");
|
|
12
|
+
/** Each probe reads its inputs when called, so an injected one never touches real state. */
|
|
13
|
+
function defaultDeps() {
|
|
14
|
+
return {
|
|
15
|
+
inspect: () => (0, managed_instruction_local_1.inspectLocalInstructionDaemon)((0, keychain_1.getActiveProfile)(), (0, config_1.loadConfig)().baseURL),
|
|
16
|
+
status: async () => {
|
|
17
|
+
const profile = (0, keychain_1.getActiveProfile)();
|
|
18
|
+
const args = [
|
|
19
|
+
'status',
|
|
20
|
+
'--json',
|
|
21
|
+
...(profile !== keychain_1.DEFAULT_PROFILE ? ['--profile', profile] : []),
|
|
22
|
+
];
|
|
23
|
+
try {
|
|
24
|
+
const out = await (0, exec_runtime_binary_1.execRuntimeBinaryCapture)(args, { timeoutMs: 15_000 });
|
|
25
|
+
return { stdout: out.stdout, code: out.code };
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return { stdout: '', code: 1 };
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
now: () => Date.now(),
|
|
32
|
+
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async function confirmLocalDaemonSignedIn(options = {}) {
|
|
36
|
+
const deps = { ...defaultDeps(), ...options.deps };
|
|
37
|
+
const waitMs = options.waitMs ?? 20_000;
|
|
38
|
+
const pollMs = options.pollMs ?? 500;
|
|
39
|
+
const stoppedGraceMs = options.stoppedGraceMs ?? 6_000;
|
|
40
|
+
const profile = (0, keychain_1.getActiveProfile)();
|
|
41
|
+
const started = deps.now();
|
|
42
|
+
let announced = false;
|
|
43
|
+
let lastDiagnosisAt = -Infinity;
|
|
44
|
+
let verdict = { state: 'not_connected', profile };
|
|
45
|
+
for (;;) {
|
|
46
|
+
const daemonId = await deps.inspect();
|
|
47
|
+
if (daemonId)
|
|
48
|
+
return { state: 'connected', daemonId };
|
|
49
|
+
if (!announced) {
|
|
50
|
+
options.log?.('Waiting for the local daemon to connect...');
|
|
51
|
+
announced = true;
|
|
52
|
+
}
|
|
53
|
+
const elapsed = deps.now() - started;
|
|
54
|
+
// Ask WHY at a measured pace — each look spawns `skrrd` — and stop waiting
|
|
55
|
+
// the moment the answer is one no amount of waiting changes.
|
|
56
|
+
if (deps.now() - lastDiagnosisAt >= 2_000) {
|
|
57
|
+
lastDiagnosisAt = deps.now();
|
|
58
|
+
const status = await deps.status();
|
|
59
|
+
const verification = (0, runtime_start_verification_1.verifyRuntimeStart)(status.stdout, status.code, ['--profile', profile]);
|
|
60
|
+
if (verification.status === 'reauth_required') {
|
|
61
|
+
return {
|
|
62
|
+
state: 'reauth_required',
|
|
63
|
+
profile: verification.profile,
|
|
64
|
+
reason: verification.reason,
|
|
65
|
+
command: verification.recoveryCommand,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (verification.status === 'not_running') {
|
|
69
|
+
verdict = {
|
|
70
|
+
state: 'not_running',
|
|
71
|
+
profile: verification.profile,
|
|
72
|
+
runtimeStatus: verification.runtimeStatus,
|
|
73
|
+
};
|
|
74
|
+
// A service that was just started reads `stopped` for a moment between
|
|
75
|
+
// launchd accepting the request and the process existing; only believe
|
|
76
|
+
// it once it has had that long.
|
|
77
|
+
if (elapsed >= stoppedGraceMs)
|
|
78
|
+
return verdict;
|
|
79
|
+
}
|
|
80
|
+
else if (verification.status === 'unreadable_status') {
|
|
81
|
+
verdict = { state: 'unreadable', profile: verification.profile };
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
verdict = { state: 'not_connected', profile };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (elapsed >= waitMs)
|
|
88
|
+
return verdict;
|
|
89
|
+
await deps.sleep(Math.min(pollMs, Math.max(0, waitMs - elapsed)));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* What `skrr login` prints about a daemon that was handed a credential and did
|
|
94
|
+
* not come up with it: what happened, why, and the one command. Pure, so every
|
|
95
|
+
* state can be read without a daemon.
|
|
96
|
+
*/
|
|
97
|
+
function describeUnreadyLocalDaemon(readiness, commands) {
|
|
98
|
+
switch (readiness.state) {
|
|
99
|
+
case 'reauth_required':
|
|
100
|
+
return [
|
|
101
|
+
`The local daemon received its sign-in but cannot use it: ${readiness.reason === 'TOKEN_MISSING'
|
|
102
|
+
? 'it started without a credential'
|
|
103
|
+
: `the server refused it (${readiness.reason ?? 'UNKNOWN'})`}.`,
|
|
104
|
+
` Sign it in with: ${readiness.command}`,
|
|
105
|
+
];
|
|
106
|
+
case 'not_running':
|
|
107
|
+
return [
|
|
108
|
+
`The local daemon received its sign-in but is not running (service status: ${readiness.runtimeStatus ?? 'unknown'}).`,
|
|
109
|
+
` See why with \`${commands.logs}\`, then start it with \`${commands.start}\`.`,
|
|
110
|
+
];
|
|
111
|
+
case 'not_connected':
|
|
112
|
+
return [
|
|
113
|
+
'The local daemon received its sign-in and is running, but has not connected yet.',
|
|
114
|
+
` Check it with \`${commands.status}\`.`,
|
|
115
|
+
];
|
|
116
|
+
case 'unreadable':
|
|
117
|
+
return [
|
|
118
|
+
'The local daemon received its sign-in, but its status could not be read to confirm it.',
|
|
119
|
+
` Check it with \`${commands.status}\`.`,
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The end of `skrr login` for a daemon that was handed a credential: wait for it
|
|
125
|
+
* to connect, then say ONE true thing. "Signed in too" only for a daemon that
|
|
126
|
+
* verified connected as this account; otherwise what happened, why, and the one
|
|
127
|
+
* command — and never both, which is what the login used to do.
|
|
128
|
+
*/
|
|
129
|
+
async function reportLocalDaemonAfterHandoff(options) {
|
|
130
|
+
const readiness = await (options.confirm ?? confirmLocalDaemonSignedIn)({ log: options.log });
|
|
131
|
+
if (readiness.state === 'connected') {
|
|
132
|
+
options.log(`The local daemon was signed in too — ${options.deliveredDetail}.`);
|
|
133
|
+
return { daemonId: readiness.daemonId, notReady: false };
|
|
134
|
+
}
|
|
135
|
+
for (const line of describeUnreadyLocalDaemon(readiness, {
|
|
136
|
+
status: (0, daemon_command_hint_1.daemonCommandHint)('status', { bin: options.bin }),
|
|
137
|
+
logs: (0, daemon_command_hint_1.daemonCommandHint)('logs', { bin: options.bin }),
|
|
138
|
+
start: (0, daemon_command_hint_1.daemonCommandHint)('start', { bin: options.bin }),
|
|
139
|
+
})) {
|
|
140
|
+
options.log(line);
|
|
141
|
+
}
|
|
142
|
+
return { notReady: true };
|
|
143
|
+
}
|
package/dist/lib/machines.d.ts
CHANGED
|
@@ -53,6 +53,35 @@ export interface MachineHarnessRow {
|
|
|
53
53
|
* them.
|
|
54
54
|
*/
|
|
55
55
|
superseded?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Recorded `online`, but no heartbeat for longer than the server's stale
|
|
58
|
+
* threshold (`MachineContact.staleAfterMs`). Present only when true. The server
|
|
59
|
+
* decides this once; a row's own `status` stays what was recorded
|
|
60
|
+
* (OSK-16442).
|
|
61
|
+
*/
|
|
62
|
+
stale?: boolean;
|
|
63
|
+
/** How long that row has been silent, in ms. Present with `stale`. */
|
|
64
|
+
staleForMs?: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* What a machine's heartbeats say, apart from what its rows are recorded as
|
|
68
|
+
* (OSK-16442). A daemon that was stopped or frozen stays recorded `online` for a
|
|
69
|
+
* minute or more before the server gives up on it, so `status` alone said
|
|
70
|
+
* `online` for a process that had not been heard from in a minute.
|
|
71
|
+
*
|
|
72
|
+
* - `live`: a row is online and heard from recently.
|
|
73
|
+
* - `stale`: rows are recorded online, but none has been heard from for
|
|
74
|
+
* `staleAfterMs`. The machine's `status` is `degraded` meanwhile.
|
|
75
|
+
* - `offline`: nothing is recorded online.
|
|
76
|
+
*
|
|
77
|
+
* The thresholds are the server's, sent so this CLI never restates them. Absent
|
|
78
|
+
* on a server older than this field and on a lease-backed machine.
|
|
79
|
+
*/
|
|
80
|
+
export interface MachineContact {
|
|
81
|
+
state: 'live' | 'stale' | 'offline';
|
|
82
|
+
staleForMs: number | null;
|
|
83
|
+
staleAfterMs: number;
|
|
84
|
+
offlineAfterMs: number;
|
|
56
85
|
}
|
|
57
86
|
export interface Machine {
|
|
58
87
|
id: string;
|
|
@@ -69,6 +98,7 @@ export interface Machine {
|
|
|
69
98
|
* none will ever arrive.
|
|
70
99
|
*/
|
|
71
100
|
statusReason?: string | null;
|
|
101
|
+
contact?: MachineContact | null;
|
|
72
102
|
machineUuid: string | null;
|
|
73
103
|
stableDaemonId: string | null;
|
|
74
104
|
daemonId: string | null;
|
|
@@ -120,6 +150,93 @@ export declare function machineStateLabel(machine: Machine): string;
|
|
|
120
150
|
export declare function hiddenMachinesSummary(hidden: readonly Machine[]): string;
|
|
121
151
|
/** Is this a machine a user could still use, or bring back? */
|
|
122
152
|
export declare function isReachableMachine(machine: Machine): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* A computer somebody installed a daemon on, as opposed to a hosted sandbox.
|
|
155
|
+
*
|
|
156
|
+
* A daemon launched on a person's own computer registers as
|
|
157
|
+
* `daemon_<hash>_<source>[_<profile>]` (`parseDaemonId`); a hosted or cloud
|
|
158
|
+
* machine's daemon carries an id minted by the control plane
|
|
159
|
+
* (`hosted-machine-…`, `cloud-coding-…`) that names no launch source. A lease
|
|
160
|
+
* decides a managed machine's own state, so it is never one of these.
|
|
161
|
+
*/
|
|
162
|
+
export declare function isOwnComputer(machine: Machine): boolean;
|
|
163
|
+
/**
|
|
164
|
+
* What the default `machines list` keeps: everything reachable, and every one of
|
|
165
|
+
* the person's own computers while it is offline (OSK-16442).
|
|
166
|
+
*
|
|
167
|
+
* The default hides offline machines because hosted sandboxes accumulate by the
|
|
168
|
+
* hundreds and buried the one that was usable (OSK-7639). Applied to a computer
|
|
169
|
+
* it did something else: the moment its last daemon stopped, the whole row left
|
|
170
|
+
* the list, in text and in `--json`, so "my computer is offline" and "my computer
|
|
171
|
+
* is gone" read the same. A computer is a handful of rows however long it is
|
|
172
|
+
* kept, and `offline` with its last-seen time is the answer a person asks the
|
|
173
|
+
* list for, so it stays; only what can no longer be used is left behind `--all`.
|
|
174
|
+
*/
|
|
175
|
+
export declare function isListedByDefault(machine: Machine): boolean;
|
|
176
|
+
/**
|
|
177
|
+
* One daemon registration on a machine, as its own record (OSK-16440).
|
|
178
|
+
*
|
|
179
|
+
* A machine row aggregates every harness registration ever made under one
|
|
180
|
+
* hardware identity. The daemon that made each is only a string on a harness
|
|
181
|
+
* row, and the profile it ran as is a suffix of that string — so a script that
|
|
182
|
+
* wanted "the daemon that just registered" had to take the first unfamiliar
|
|
183
|
+
* `daemonId` out of a flat list that, depending on whether anything on the
|
|
184
|
+
* computer happened to be online, held 4 rows or 98 of them.
|
|
185
|
+
*/
|
|
186
|
+
export interface MachineDaemonSummary {
|
|
187
|
+
daemonId: string;
|
|
188
|
+
/** The profile the daemon ran as, read from its id; null for an id that names none (a hosted box). */
|
|
189
|
+
profile: string | null;
|
|
190
|
+
/** How it was launched (`cli`, `launchd`, …); null when the id does not say. */
|
|
191
|
+
source: string | null;
|
|
192
|
+
/**
|
|
193
|
+
* `online` when any registration is online and heard from recently, `stale`
|
|
194
|
+
* when some are recorded online but none has been heard from lately, `offline`
|
|
195
|
+
* otherwise.
|
|
196
|
+
*/
|
|
197
|
+
status: 'online' | 'stale' | 'offline';
|
|
198
|
+
lastSeenAt: string | null;
|
|
199
|
+
harnessCount: number;
|
|
200
|
+
/** Of those, how many a newer registration of the same provider replaced. */
|
|
201
|
+
supersededCount: number;
|
|
202
|
+
/** The profile this CLI is running as. */
|
|
203
|
+
activeProfile: boolean;
|
|
204
|
+
}
|
|
205
|
+
export declare function parseDaemonId(daemonId: string): {
|
|
206
|
+
source: string;
|
|
207
|
+
profile: string;
|
|
208
|
+
} | null;
|
|
209
|
+
export declare function summarizeDaemons(harnesses: readonly MachineHarnessRow[], activeProfile: string): MachineDaemonSummary[];
|
|
210
|
+
/** Whether the machine's identity is THIS computer's (the default profile's, or a profile qualified from it). */
|
|
211
|
+
export declare function isThisComputer(machine: Machine, hardwareMachineUuid: string): boolean;
|
|
212
|
+
export interface MachineListView extends Machine {
|
|
213
|
+
/** This machine is the computer the CLI is running on. */
|
|
214
|
+
thisComputer: boolean;
|
|
215
|
+
/** One record per daemon registration; see {@link MachineDaemonSummary}. */
|
|
216
|
+
daemons: MachineDaemonSummary[];
|
|
217
|
+
/**
|
|
218
|
+
* Harness rows left out of `harnesses` because a newer registration replaced
|
|
219
|
+
* them (default view only). `supersededHarnessCount` still reports the
|
|
220
|
+
* server's own total, so nothing is silently subtracted.
|
|
221
|
+
*/
|
|
222
|
+
hiddenHarnessCount?: number;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* What `machines list` shows of one machine (OSK-16440).
|
|
226
|
+
*
|
|
227
|
+
* The default list is "what is reachable now", and a machine's own history is
|
|
228
|
+
* not part of that. A machine row carries every harness registration it ever
|
|
229
|
+
* had; one of them being online made the whole 98-row history appear in a list
|
|
230
|
+
* that, a minute earlier, had held four rows — the same command, a different
|
|
231
|
+
* answer, for no reason a reader could see. So the default view keeps the
|
|
232
|
+
* registrations that still stand and says how many it left out; `--all` keeps
|
|
233
|
+
* everything.
|
|
234
|
+
*/
|
|
235
|
+
export declare function machineListView(machine: Machine, options: {
|
|
236
|
+
all: boolean;
|
|
237
|
+
hardwareMachineUuid: string;
|
|
238
|
+
activeProfile: string;
|
|
239
|
+
}): MachineListView;
|
|
123
240
|
/** The user-editable slice. Identities, capabilities and lifecycle are not. */
|
|
124
241
|
export interface MachinePreferencesPatch {
|
|
125
242
|
name?: string;
|