@skrr-ai/cli 0.1.36 → 0.1.38
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 +17 -4
- package/bin/dev-fallback.js +167 -4
- package/dist/base-command.js +46 -2
- package/dist/commands/agents/actions/create.d.ts +5 -0
- package/dist/commands/agents/actions/create.js +42 -5
- package/dist/commands/agents/actions/delete.d.ts +1 -0
- package/dist/commands/agents/actions/delete.js +7 -0
- package/dist/commands/agents/actions/update.d.ts +5 -0
- package/dist/commands/agents/actions/update.js +27 -1
- package/dist/commands/agents/api-actions/add.d.ts +41 -0
- package/dist/commands/agents/api-actions/add.js +205 -0
- package/dist/commands/agents/api-actions/index.d.ts +39 -0
- package/dist/commands/agents/api-actions/index.js +103 -0
- package/dist/commands/agents/api-actions/remove.d.ts +14 -0
- package/dist/commands/agents/api-actions/remove.js +36 -0
- package/dist/commands/agents/avatar/default/apply.d.ts +25 -0
- package/dist/commands/agents/avatar/default/apply.js +56 -0
- package/dist/commands/agents/avatar/default/index.d.ts +29 -0
- package/dist/commands/agents/avatar/default/index.js +61 -0
- package/dist/commands/agents/avatar/default/set.d.ts +24 -0
- package/dist/commands/agents/avatar/default/set.js +120 -0
- package/dist/commands/agents/avatar/library/delete.d.ts +20 -0
- package/dist/commands/agents/avatar/library/delete.js +47 -0
- package/dist/commands/agents/avatar/library/index.d.ts +16 -0
- package/dist/commands/agents/avatar/library/index.js +56 -0
- package/dist/commands/agents/avatar/presets.d.ts +19 -0
- package/dist/commands/agents/avatar/presets.js +56 -0
- package/dist/commands/agents/avatar/upload.js +7 -1
- package/dist/commands/agents/categories/create.d.ts +14 -0
- package/dist/commands/agents/categories/create.js +46 -0
- package/dist/commands/agents/categories/delete.d.ts +13 -0
- package/dist/commands/agents/categories/delete.js +41 -0
- package/dist/commands/agents/categories/index.d.ts +36 -0
- package/dist/commands/agents/categories/index.js +135 -0
- package/dist/commands/agents/categories/update.d.ts +22 -0
- package/dist/commands/agents/categories/update.js +59 -0
- package/dist/commands/agents/chat.d.ts +21 -0
- package/dist/commands/agents/chat.js +94 -7
- package/dist/commands/agents/create.d.ts +10 -0
- package/dist/commands/agents/create.js +64 -3
- package/dist/commands/agents/ensure-default.d.ts +27 -0
- package/dist/commands/agents/ensure-default.js +65 -0
- package/dist/commands/agents/list.d.ts +15 -0
- package/dist/commands/agents/list.js +31 -1
- package/dist/commands/agents/mute.d.ts +16 -0
- package/dist/commands/agents/mute.js +38 -0
- package/dist/commands/agents/pin.d.ts +16 -0
- package/dist/commands/agents/pin.js +38 -0
- package/dist/commands/agents/scene-background/upload.d.ts +30 -0
- package/dist/commands/agents/scene-background/upload.js +97 -0
- package/dist/commands/agents/show.js +13 -0
- package/dist/commands/agents/tools/auth.d.ts +19 -0
- package/dist/commands/agents/tools/auth.js +41 -0
- package/dist/commands/agents/tools/calls.d.ts +36 -0
- package/dist/commands/agents/tools/calls.js +117 -0
- package/dist/commands/agents/tools/index.d.ts +20 -0
- package/dist/commands/agents/tools/index.js +77 -0
- package/dist/commands/agents/unmute.d.ts +16 -0
- package/dist/commands/agents/unmute.js +38 -0
- package/dist/commands/agents/unpin.d.ts +16 -0
- package/dist/commands/agents/unpin.js +38 -0
- package/dist/commands/agents/update.d.ts +12 -0
- package/dist/commands/agents/update.js +74 -3
- package/dist/commands/code/{oversky-agent.d.ts → skrr-agent.d.ts} +3 -3
- package/dist/commands/code/{oversky-agent.js → skrr-agent.js} +11 -8
- package/dist/commands/convos/messages.d.ts +13 -0
- package/dist/commands/convos/messages.js +40 -16
- package/dist/commands/daemon/index.js +8 -1
- package/dist/commands/daemon/logs.d.ts +26 -0
- package/dist/commands/daemon/logs.js +56 -0
- package/dist/commands/daemon/uninstall.js +1 -1
- package/dist/commands/followups/act.d.ts +22 -0
- package/dist/commands/followups/act.js +103 -0
- package/dist/commands/followups/cancel.d.ts +20 -0
- package/dist/commands/followups/cancel.js +50 -0
- package/dist/commands/followups/checkin.d.ts +27 -0
- package/dist/commands/followups/checkin.js +107 -0
- package/dist/commands/followups/list.d.ts +24 -0
- package/dist/commands/followups/list.js +90 -0
- package/dist/commands/followups/observability.d.ts +23 -0
- package/dist/commands/followups/observability.js +114 -0
- package/dist/commands/followups/remind.d.ts +26 -0
- package/dist/commands/followups/remind.js +106 -0
- package/dist/commands/followups/reschedule.d.ts +15 -0
- package/dist/commands/followups/reschedule.js +48 -0
- package/dist/commands/followups/resolve.d.ts +23 -0
- package/dist/commands/followups/resolve.js +54 -0
- package/dist/commands/followups/show.d.ts +12 -0
- package/dist/commands/followups/show.js +46 -0
- package/dist/commands/followups/watch.d.ts +51 -0
- package/dist/commands/followups/watch.js +211 -0
- package/dist/commands/goals/labels/add.js +19 -2
- package/dist/commands/goals/labels/remove.js +22 -2
- package/dist/commands/harnesses/forget.js +28 -0
- package/dist/commands/harnesses/install.d.ts +41 -0
- package/dist/commands/harnesses/install.js +165 -0
- package/dist/commands/harnesses/installers.d.ts +45 -0
- package/dist/commands/harnesses/installers.js +155 -0
- package/dist/commands/harnesses/list.d.ts +82 -1
- package/dist/commands/harnesses/list.js +104 -12
- package/dist/commands/harnesses/models.js +10 -1
- package/dist/commands/harnesses/show.d.ts +15 -0
- package/dist/commands/harnesses/show.js +44 -3
- package/dist/commands/harnesses/update.js +1 -1
- package/dist/commands/harnesses/usage.d.ts +25 -0
- package/dist/commands/harnesses/usage.js +24 -2
- package/dist/commands/instructions/status.js +13 -1
- package/dist/commands/labels/list.d.ts +24 -1
- package/dist/commands/labels/list.js +62 -19
- package/dist/commands/machines/dedicated/catalog.js +4 -15
- package/dist/commands/machines/dedicated/create.d.ts +8 -0
- package/dist/commands/machines/dedicated/create.js +58 -1
- package/dist/commands/machines/dedicated/destroy.js +18 -4
- package/dist/commands/machines/dedicated/list.js +9 -6
- package/dist/commands/machines/hosted/list.js +12 -0
- package/dist/commands/machines/list.js +11 -0
- package/dist/commands/machines/show.d.ts +1 -0
- package/dist/commands/machines/show.js +40 -11
- package/dist/commands/memory/governance/index.d.ts +21 -0
- package/dist/commands/memory/governance/index.js +64 -0
- package/dist/commands/memory/governance/set.d.ts +24 -0
- package/dist/commands/memory/governance/set.js +95 -0
- package/dist/commands/memory/provenance.d.ts +18 -0
- package/dist/commands/memory/provenance.js +66 -0
- package/dist/commands/profiles/list.d.ts +23 -0
- package/dist/commands/profiles/list.js +96 -0
- package/dist/commands/search/skills.d.ts +11 -1
- package/dist/commands/search/skills.js +26 -8
- package/dist/commands/skills/details.d.ts +2 -0
- package/dist/commands/skills/details.js +24 -1
- package/dist/commands/skills/import-as-actions.d.ts +32 -0
- package/dist/commands/skills/import-as-actions.js +175 -0
- package/dist/commands/skills/install.d.ts +2 -0
- package/dist/commands/skills/install.js +24 -1
- package/dist/commands/skills/invocable.js +6 -2
- package/dist/commands/skills/local.d.ts +40 -0
- package/dist/commands/skills/local.js +160 -0
- package/dist/commands/skills/search.d.ts +11 -1
- package/dist/commands/skills/search.js +29 -8
- package/dist/commands/spaces/actions/add.js +23 -5
- package/dist/commands/spaces/actions/available.js +3 -0
- package/dist/commands/spaces/actions/list.d.ts +5 -0
- package/dist/commands/spaces/actions/list.js +49 -3
- package/dist/commands/spaces/actions/run.d.ts +28 -0
- package/dist/commands/spaces/actions/run.js +146 -0
- package/dist/commands/spaces/actions/update.js +27 -5
- package/dist/commands/spaces/create.d.ts +3 -0
- package/dist/commands/spaces/create.js +32 -2
- package/dist/commands/spaces/label-summaries.d.ts +27 -0
- package/dist/commands/spaces/label-summaries.js +64 -0
- package/dist/commands/spaces/labels/add.js +19 -2
- package/dist/commands/spaces/labels/remove.js +22 -2
- package/dist/commands/spaces/show.js +2 -0
- package/dist/commands/spaces/task-rollups.d.ts +5 -0
- package/dist/commands/spaces/task-rollups.js +15 -4
- package/dist/commands/spaces/update.d.ts +5 -0
- package/dist/commands/spaces/update.js +41 -4
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +11 -0
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +105 -0
- package/dist/commands/tasks/actions/attach.js +32 -7
- package/dist/commands/tasks/complete.d.ts +1 -0
- package/dist/commands/tasks/complete.js +21 -1
- package/dist/commands/tasks/create.d.ts +3 -0
- package/dist/commands/tasks/create.js +34 -2
- package/dist/commands/tasks/events/append.js +29 -6
- package/dist/commands/tasks/expectations/assess.d.ts +12 -0
- package/dist/commands/tasks/expectations/assess.js +123 -14
- package/dist/commands/tasks/expectations.js +95 -17
- package/dist/commands/tasks/follow-up.js +2 -2
- package/dist/commands/tasks/labels/attach.js +20 -3
- package/dist/commands/tasks/labels/detach.js +21 -3
- package/dist/commands/tasks/lifecycle/attach.d.ts +14 -0
- package/dist/commands/tasks/lifecycle/attach.js +47 -0
- package/dist/commands/tasks/lifecycle/definitions.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/definitions.js +59 -0
- package/dist/commands/tasks/lifecycle/detach.d.ts +19 -0
- package/dist/commands/tasks/lifecycle/detach.js +72 -0
- package/dist/commands/tasks/lifecycle/history.d.ts +13 -0
- package/dist/commands/tasks/lifecycle/history.js +38 -0
- package/dist/commands/tasks/lifecycle/migrate.d.ts +14 -0
- package/dist/commands/tasks/lifecycle/migrate.js +68 -0
- package/dist/commands/tasks/lifecycle/reconcile.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/reconcile.js +27 -0
- package/dist/commands/tasks/lifecycle/reopen.d.ts +15 -0
- package/dist/commands/tasks/lifecycle/reopen.js +71 -0
- package/dist/commands/tasks/lifecycle/show.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/show.js +27 -0
- package/dist/commands/tasks/lifecycle/start.d.ts +12 -0
- package/dist/commands/tasks/lifecycle/start.js +30 -0
- package/dist/commands/tasks/lifecycle/transition.d.ts +15 -0
- package/dist/commands/tasks/lifecycle/transition.js +109 -0
- package/dist/commands/tasks/list.js +16 -9
- package/dist/commands/tasks/move.d.ts +1 -0
- package/dist/commands/tasks/move.js +29 -0
- package/dist/commands/tasks/result/submit.js +11 -1
- package/dist/commands/tasks/review-queue.d.ts +44 -0
- package/dist/commands/tasks/review-queue.js +314 -0
- package/dist/commands/tasks/show.d.ts +11 -0
- package/dist/commands/tasks/show.js +139 -4
- package/dist/commands/tasks/trust.js +7 -2
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +83 -0
- package/dist/commands/tasks/updates/add.js +1 -1
- package/dist/commands/token/list.d.ts +22 -0
- package/dist/commands/token/list.js +68 -0
- package/dist/commands/token/revoke.d.ts +23 -0
- package/dist/commands/token/revoke.js +53 -0
- package/dist/lib/agent-actions.d.ts +92 -11
- package/dist/lib/agent-actions.js +171 -25
- package/dist/lib/agent-config.d.ts +11 -0
- package/dist/lib/agent-config.js +85 -3
- package/dist/lib/agent-pin-mute.d.ts +29 -0
- package/dist/lib/agent-pin-mute.js +30 -0
- package/dist/lib/agent-visual-refs.d.ts +33 -0
- package/dist/lib/agent-visual-refs.js +267 -0
- package/dist/lib/agentic-stream.d.ts +6 -0
- package/dist/lib/agentic-stream.js +34 -3
- package/dist/lib/assignee-resolver.d.ts +1 -1
- package/dist/lib/assignee-resolver.js +8 -0
- package/dist/lib/bulk-task-targets.d.ts +12 -0
- package/dist/lib/bulk-task-targets.js +34 -1
- package/dist/lib/cli-installers.d.ts +130 -0
- package/dist/lib/cli-installers.js +145 -0
- package/dist/lib/command-miss.js +55 -7
- package/dist/lib/dedicated-lease-command.d.ts +13 -0
- package/dist/lib/dedicated-lease-command.js +22 -1
- package/dist/lib/dedicated-machines.d.ts +95 -1
- package/dist/lib/dedicated-machines.js +236 -2
- package/dist/lib/failed-lookup.d.ts +3 -0
- package/dist/lib/failed-lookup.js +40 -0
- package/dist/lib/first-party-harness-agent.js +16 -2
- package/dist/lib/first-party-harness-doctor.d.ts +15 -0
- package/dist/lib/first-party-harness-doctor.js +126 -27
- package/dist/lib/followups.d.ts +115 -0
- package/dist/lib/followups.js +127 -0
- package/dist/lib/harnesses.d.ts +8 -0
- package/dist/lib/instruction-input.d.ts +19 -1
- package/dist/lib/instruction-input.js +52 -1
- package/dist/lib/label-ref.d.ts +95 -0
- package/dist/lib/label-ref.js +163 -0
- package/dist/lib/label-scope.d.ts +17 -2
- package/dist/lib/label-scope.js +27 -7
- package/dist/lib/local-skills.d.ts +98 -0
- package/dist/lib/local-skills.js +195 -0
- package/dist/lib/machines.d.ts +10 -10
- package/dist/lib/machines.js +23 -1
- package/dist/lib/search-query.d.ts +19 -0
- package/dist/lib/search-query.js +35 -0
- package/dist/lib/space-custom-actions.d.ts +72 -0
- package/dist/lib/space-custom-actions.js +117 -0
- package/dist/lib/space-resolver.d.ts +1 -21
- package/dist/lib/space-resolver.js +19 -10
- package/dist/lib/task-closure.d.ts +33 -0
- package/dist/lib/task-closure.js +104 -0
- package/dist/lib/task-lifecycle-output.d.ts +14 -0
- package/dist/lib/task-lifecycle-output.js +209 -0
- package/dist/lib/task-ref-resolver.d.ts +1 -17
- package/dist/lib/task-ref-resolver.js +18 -8
- package/dist/lib/tasks.d.ts +3 -0
- package/dist/lib/tasks.js +40 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +5559 -4897
- package/oclif.manifest.json +33890 -28690
- package/package.json +24 -6
|
@@ -38,7 +38,16 @@ class HarnessesModels extends base_command_1.BaseCommand {
|
|
|
38
38
|
const report = payload;
|
|
39
39
|
const models = report?.models ?? [];
|
|
40
40
|
if (models.length === 0) {
|
|
41
|
-
|
|
41
|
+
// "This harness advertises no models." is true and answers none of the
|
|
42
|
+
// three questions a reader has: is this a product gap, my machine's
|
|
43
|
+
// fault, or a broken command? Saying which provider was resolved and
|
|
44
|
+
// where the list comes from picks one — and, in the bug this replaced,
|
|
45
|
+
// would have shown `provider` as null on a Claude harness and named the
|
|
46
|
+
// defect on sight.
|
|
47
|
+
const resolved = report?.provider;
|
|
48
|
+
this.log(resolved
|
|
49
|
+
? `No models are listed for ${resolved}. skrr keeps a curated list per provider and ${resolved} has no entries in it, so pick a model on the agent instead — \`skrr agents update <agent> --model <id>\` accepts an id this list does not name.`
|
|
50
|
+
: 'This harness resolved to no provider, so no model list could be built. That is a defect, not a configuration problem — report it with the harness id.');
|
|
42
51
|
return;
|
|
43
52
|
}
|
|
44
53
|
if (report?.provider || report?.source) {
|
|
@@ -10,3 +10,18 @@ export default class HarnessesShow extends BaseCommand {
|
|
|
10
10
|
};
|
|
11
11
|
run(): Promise<void>;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Say what the caller DID pass, not only what they did not.
|
|
15
|
+
*
|
|
16
|
+
* Every id in this product is a bare string, and three of them are printed side
|
|
17
|
+
* by side: `machines show` takes a machine or daemon id, `harnesses show` takes
|
|
18
|
+
* a Harness id. `machines show <daemon-id>` succeeds, so a user who learns that
|
|
19
|
+
* reasonably tries the same id here — and got back only a restatement of the
|
|
20
|
+
* rule they had just broken, plus the Mongo field name `_id`, which names an
|
|
21
|
+
* implementation detail rather than anything they can see.
|
|
22
|
+
*
|
|
23
|
+
* The shapes below are the ones our own output prints, so recognising them
|
|
24
|
+
* costs nothing and turns a refusal into a redirect. Anything unrecognised
|
|
25
|
+
* still falls through to the general answer rather than being guessed at.
|
|
26
|
+
*/
|
|
27
|
+
export declare function describeWrongHarnessRef(ref: string): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.describeWrongHarnessRef = describeWrongHarnessRef;
|
|
3
4
|
const core_1 = require("@oclif/core");
|
|
4
5
|
const base_command_1 = require("../../base-command");
|
|
5
6
|
const harness_provider_input_1 = require("../../lib/harness-provider-input");
|
|
@@ -35,9 +36,9 @@ class HarnessesShow extends base_command_1.BaseCommand {
|
|
|
35
36
|
// "HTTP 400 Bad Request — GET /api/harnesses/<id>". Any 400 on this
|
|
36
37
|
// lookup is the id being wrong, so branch on the status.
|
|
37
38
|
if (err instanceof api_fetch_1.ApiFetchError && err.status === 400) {
|
|
38
|
-
this.error(`Not a harness id: ${args.harness}\n
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
this.error(`Not a harness id: ${args.harness}\n${describeWrongHarnessRef(args.harness)}`, {
|
|
40
|
+
exit: 1,
|
|
41
|
+
});
|
|
41
42
|
return;
|
|
42
43
|
}
|
|
43
44
|
this.handleApiError(err);
|
|
@@ -61,6 +62,14 @@ class HarnessesShow extends base_command_1.BaseCommand {
|
|
|
61
62
|
this.log(` provider ${harness.provider}`);
|
|
62
63
|
// `harnessLocation` is the difference between "your laptop" and "a cloud row",
|
|
63
64
|
// and it decides which verbs apply: ping and claudeEngine are local-only.
|
|
65
|
+
// When YOUR alias is covering the shared name, say so and show both. The
|
|
66
|
+
// header prints the effective name, which is the alias — without this the
|
|
67
|
+
// value `harnesses update --name` just wrote appears on no surface at all,
|
|
68
|
+
// and you cannot tell you are reading your own label rather than the one
|
|
69
|
+
// everyone else sees.
|
|
70
|
+
if (harness.aliased && harness.sharedName && harness.sharedName !== harness.name) {
|
|
71
|
+
this.log(` shared name ${harness.sharedName} (your alias is showing instead)`);
|
|
72
|
+
}
|
|
64
73
|
this.log(` mode ${harness.harnessLocation ?? 'unknown'}`);
|
|
65
74
|
this.log(` status ${harness.status ?? 'unknown'}`);
|
|
66
75
|
// Only for the claude provider. The daemon stamps `claudeEngine` on every
|
|
@@ -77,3 +86,35 @@ class HarnessesShow extends base_command_1.BaseCommand {
|
|
|
77
86
|
}
|
|
78
87
|
}
|
|
79
88
|
exports.default = HarnessesShow;
|
|
89
|
+
/**
|
|
90
|
+
* Say what the caller DID pass, not only what they did not.
|
|
91
|
+
*
|
|
92
|
+
* Every id in this product is a bare string, and three of them are printed side
|
|
93
|
+
* by side: `machines show` takes a machine or daemon id, `harnesses show` takes
|
|
94
|
+
* a Harness id. `machines show <daemon-id>` succeeds, so a user who learns that
|
|
95
|
+
* reasonably tries the same id here — and got back only a restatement of the
|
|
96
|
+
* rule they had just broken, plus the Mongo field name `_id`, which names an
|
|
97
|
+
* implementation detail rather than anything they can see.
|
|
98
|
+
*
|
|
99
|
+
* The shapes below are the ones our own output prints, so recognising them
|
|
100
|
+
* costs nothing and turns a refusal into a redirect. Anything unrecognised
|
|
101
|
+
* still falls through to the general answer rather than being guessed at.
|
|
102
|
+
*/
|
|
103
|
+
function describeWrongHarnessRef(ref) {
|
|
104
|
+
const seeIds = 'Run `skrr harnesses list --all` to see the harness ids on this account.';
|
|
105
|
+
if (/^daemon_/.test(ref)) {
|
|
106
|
+
return `That is a daemon id. \`skrr machines show ${ref}\` takes those. ${seeIds}`;
|
|
107
|
+
}
|
|
108
|
+
if (/^machine:/.test(ref)) {
|
|
109
|
+
return `That is a machine id. \`skrr machines show ${ref}\` takes those. ${seeIds}`;
|
|
110
|
+
}
|
|
111
|
+
if (/^(lease:|dedicated-runtime:|hosted-machine:)/.test(ref)) {
|
|
112
|
+
return ('That is a machine id for a rented runtime. `skrr machines show` takes it as printed; ' +
|
|
113
|
+
`\`skrr machines dedicated show\` takes the part after the colon. ${seeIds}`);
|
|
114
|
+
}
|
|
115
|
+
if (/^[0-9a-f]{24}$/i.test(ref)) {
|
|
116
|
+
// Right shape, wrong row — so the id is not the thing to explain.
|
|
117
|
+
return `No harness on this account has that id. ${seeIds}`;
|
|
118
|
+
}
|
|
119
|
+
return `A harness id is 24 hexadecimal characters. ${seeIds}`;
|
|
120
|
+
}
|
|
@@ -29,7 +29,7 @@ class HarnessesUpdate extends base_command_1.BaseCommand {
|
|
|
29
29
|
}),
|
|
30
30
|
description: core_1.Flags.string({ description: 'New description' }),
|
|
31
31
|
'claude-engine': core_1.Flags.string({
|
|
32
|
-
description: 'How Claude Code runs on this machine: `sdk` in-process (needed for AskUserQuestion), `cli` as a child process. Local harnesses only.',
|
|
32
|
+
description: 'How Claude Code runs on this machine: `sdk` in-process (needed for AskUserQuestion), `cli` as a child process. Local CLAUDE harnesses only — the server refuses it on any other provider, because nothing would ever read it.',
|
|
33
33
|
options: ['cli', 'sdk'],
|
|
34
34
|
}),
|
|
35
35
|
};
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
2
|
export type UsageRow = {
|
|
3
3
|
/** Fleet rollup only — one row per harness. */
|
|
4
|
+
harnessId?: string;
|
|
5
|
+
/**
|
|
6
|
+
* The pre-rename spelling of `harnessId`. The server stopped sending it at
|
|
7
|
+
* the harness rename; reading it alone left the HARNESS column printing `-`
|
|
8
|
+
* on every row of the rollup. Kept as a fallback for an older deployment.
|
|
9
|
+
*/
|
|
4
10
|
runtimeId?: string;
|
|
5
11
|
name?: string;
|
|
6
12
|
/** Single-harness report only — one row per hour. */
|
|
@@ -12,6 +18,25 @@ export type UsageRow = {
|
|
|
12
18
|
outputTokens?: number;
|
|
13
19
|
cachedInputTokens?: number;
|
|
14
20
|
};
|
|
21
|
+
/**
|
|
22
|
+
* The rows to render, whichever spelling the server used.
|
|
23
|
+
*
|
|
24
|
+
* `byHarness` is what it sends today. This reader asked only for `byRuntime` —
|
|
25
|
+
* the pre-rename spelling — so the fleet rollup was ALWAYS empty and the
|
|
26
|
+
* command always printed "No usage recorded.", while `--json` on the same call
|
|
27
|
+
* showed $24.93 across 46 sessions. A rollup cannot be empty while its own
|
|
28
|
+
* members are not, which is what made it findable.
|
|
29
|
+
*
|
|
30
|
+
* The old spellings stay as fallbacks, after the current one, so an older
|
|
31
|
+
* deployment still renders. They are not the primary, which is the whole bug.
|
|
32
|
+
*/
|
|
33
|
+
export declare function selectUsageRows(payload: {
|
|
34
|
+
byHarness?: UsageRow[];
|
|
35
|
+
byRuntime?: UsageRow[];
|
|
36
|
+
usage?: UsageRow[];
|
|
37
|
+
} | undefined): UsageRow[];
|
|
38
|
+
/** The HARNESS cell, under either spelling of the id. */
|
|
39
|
+
export declare function usageRowHarnessCell(row: UsageRow): string;
|
|
15
40
|
export interface UsageTable {
|
|
16
41
|
rows: Record<string, string>[];
|
|
17
42
|
columns: {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.selectUsageRows = selectUsageRows;
|
|
4
|
+
exports.usageRowHarnessCell = usageRowHarnessCell;
|
|
3
5
|
exports.buildUsageTable = buildUsageTable;
|
|
4
6
|
const core_1 = require("@oclif/core");
|
|
5
7
|
const base_command_1 = require("../../base-command");
|
|
@@ -22,6 +24,26 @@ function count(value) {
|
|
|
22
24
|
const n = Number(value);
|
|
23
25
|
return Number.isFinite(n) ? n.toLocaleString('en-US') : '-';
|
|
24
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* The rows to render, whichever spelling the server used.
|
|
29
|
+
*
|
|
30
|
+
* `byHarness` is what it sends today. This reader asked only for `byRuntime` —
|
|
31
|
+
* the pre-rename spelling — so the fleet rollup was ALWAYS empty and the
|
|
32
|
+
* command always printed "No usage recorded.", while `--json` on the same call
|
|
33
|
+
* showed $24.93 across 46 sessions. A rollup cannot be empty while its own
|
|
34
|
+
* members are not, which is what made it findable.
|
|
35
|
+
*
|
|
36
|
+
* The old spellings stay as fallbacks, after the current one, so an older
|
|
37
|
+
* deployment still renders. They are not the primary, which is the whole bug.
|
|
38
|
+
*/
|
|
39
|
+
function selectUsageRows(payload) {
|
|
40
|
+
return payload?.byHarness ?? payload?.byRuntime ?? payload?.usage ?? [];
|
|
41
|
+
}
|
|
42
|
+
/** The HARNESS cell, under either spelling of the id. */
|
|
43
|
+
function usageRowHarnessCell(row) {
|
|
44
|
+
const id = row.harnessId ?? row.runtimeId;
|
|
45
|
+
return id ? String(id).slice(0, 12) : '-';
|
|
46
|
+
}
|
|
25
47
|
const SHARED_COLUMNS = [
|
|
26
48
|
{ key: 'provider', header: 'PROVIDER' },
|
|
27
49
|
{ key: 'sessions', header: 'SESSIONS' },
|
|
@@ -66,7 +88,7 @@ function buildUsageTable(rows, perHarness) {
|
|
|
66
88
|
...SHARED_COLUMNS,
|
|
67
89
|
],
|
|
68
90
|
rows: rows.map((r) => ({
|
|
69
|
-
harness:
|
|
91
|
+
harness: usageRowHarnessCell(r),
|
|
70
92
|
name: (0, format_1.formatCell)(r.name),
|
|
71
93
|
...shared(r),
|
|
72
94
|
})),
|
|
@@ -105,7 +127,7 @@ class HarnessesUsage extends base_command_1.BaseCommand {
|
|
|
105
127
|
// `{usage, totals}`. Neither is a superset, so read both rather than
|
|
106
128
|
// assuming one and rendering a table of dashes for the other.
|
|
107
129
|
const payload = report;
|
|
108
|
-
const rows = payload
|
|
130
|
+
const rows = selectUsageRows(payload);
|
|
109
131
|
const totals = payload?.grandTotals ?? payload?.totals;
|
|
110
132
|
if (rows.length === 0) {
|
|
111
133
|
this.log(args.harness ? 'No usage recorded for this harness.' : 'No usage recorded.');
|
|
@@ -29,6 +29,18 @@ class InstructionsStatus extends base_command_1.BaseCommand {
|
|
|
29
29
|
// only `bundleId`, so join to the bundle list — including archived/deleted,
|
|
30
30
|
// since a target can outlive its bundle. A failed lookup is non-fatal: the
|
|
31
31
|
// column falls back to the full bundle id.
|
|
32
|
+
// The live daemons, so a stalled row can tell "this machine now starts its
|
|
33
|
+
// daemon a different way" from "the daemon is gone" — and only the second
|
|
34
|
+
// earns a destructive remedy. Non-fatal: an empty list degrades to the old
|
|
35
|
+
// wording, which is a guess, not a wrong claim about a daemon we checked.
|
|
36
|
+
let liveDaemonIds = [];
|
|
37
|
+
try {
|
|
38
|
+
const daemons = await data_provider_1.dataService.getDaemons();
|
|
39
|
+
liveDaemonIds = (daemons.active || []).map((d) => d.daemonId);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Leave it empty.
|
|
43
|
+
}
|
|
32
44
|
let bundleNames = new Map();
|
|
33
45
|
try {
|
|
34
46
|
const bundleResponse = await data_provider_1.dataService.listManagedInstructionBundles({
|
|
@@ -62,7 +74,7 @@ class InstructionsStatus extends base_command_1.BaseCommand {
|
|
|
62
74
|
(target.scope === 'global' ? 'global' : target.projectPath || 'project'),
|
|
63
75
|
desired: target.desiredState,
|
|
64
76
|
applied: target.appliedVersionNumber ? `v${target.appliedVersionNumber}` : '-',
|
|
65
|
-
status: (0, instruction_input_1.describeTargetSync)(target),
|
|
77
|
+
status: (0, instruction_input_1.describeTargetSync)(target, Date.now(), liveDaemonIds),
|
|
66
78
|
})), [
|
|
67
79
|
{ key: 'id', header: 'TARGET ID' },
|
|
68
80
|
// Wide enough for a prompt name (matches `instructions list`'s NAME
|
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `labels list` — every label you can actually USE, by default.
|
|
4
|
+
*
|
|
5
|
+
* This used to default to `--scope user` and show one scope at a time, which
|
|
6
|
+
* is a faithful rendering of `GET /api/labels` and a poor answer to the
|
|
7
|
+
* question people ask. `scope` is an OWNERSHIP boundary, not a filter anyone
|
|
8
|
+
* browses by: a workspace-scoped label is attachable by every member, so
|
|
9
|
+
* leaving it out of the default view means the vocabulary you are told about
|
|
10
|
+
* is smaller than the one you have.
|
|
11
|
+
*
|
|
12
|
+
* It had a measurable cost. Three workspace-scoped labels existed and were
|
|
13
|
+
* invisible to the bare command, so nobody knew they were there — which is
|
|
14
|
+
* part of why the label system shipped complete and went unused, and why a
|
|
15
|
+
* second `dogfood` nearly got created beside one that already existed.
|
|
16
|
+
*
|
|
17
|
+
* `--scope` still narrows to exactly one scope, so every explicit invocation
|
|
18
|
+
* behaves as it always did. Only the bare command changed, and it changed to
|
|
19
|
+
* a superset.
|
|
20
|
+
*
|
|
21
|
+
* The merge itself is `lib/label-ref.collectLabelVocabulary` — the same
|
|
22
|
+
* function `--label <name>` resolves through. A separate copy here is how the
|
|
23
|
+
* name you can type and the name you can see start to disagree.
|
|
24
|
+
*/
|
|
2
25
|
export default class LabelsList extends BaseCommand {
|
|
3
26
|
static description: string;
|
|
4
27
|
static examples: string[];
|
|
5
28
|
static flags: {
|
|
29
|
+
scope: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
6
30
|
'applicable-to': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
31
|
'include-archived': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
-
scope: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
32
|
'scope-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
33
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
34
|
};
|
|
@@ -5,17 +5,48 @@ const data_provider_1 = require("@skrr-ai/data-provider");
|
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
6
|
const format_1 = require("../../lib/format");
|
|
7
7
|
const label_scope_1 = require("../../lib/label-scope");
|
|
8
|
+
const label_ref_1 = require("../../lib/label-ref");
|
|
9
|
+
/**
|
|
10
|
+
* `labels list` — every label you can actually USE, by default.
|
|
11
|
+
*
|
|
12
|
+
* This used to default to `--scope user` and show one scope at a time, which
|
|
13
|
+
* is a faithful rendering of `GET /api/labels` and a poor answer to the
|
|
14
|
+
* question people ask. `scope` is an OWNERSHIP boundary, not a filter anyone
|
|
15
|
+
* browses by: a workspace-scoped label is attachable by every member, so
|
|
16
|
+
* leaving it out of the default view means the vocabulary you are told about
|
|
17
|
+
* is smaller than the one you have.
|
|
18
|
+
*
|
|
19
|
+
* It had a measurable cost. Three workspace-scoped labels existed and were
|
|
20
|
+
* invisible to the bare command, so nobody knew they were there — which is
|
|
21
|
+
* part of why the label system shipped complete and went unused, and why a
|
|
22
|
+
* second `dogfood` nearly got created beside one that already existed.
|
|
23
|
+
*
|
|
24
|
+
* `--scope` still narrows to exactly one scope, so every explicit invocation
|
|
25
|
+
* behaves as it always did. Only the bare command changed, and it changed to
|
|
26
|
+
* a superset.
|
|
27
|
+
*
|
|
28
|
+
* The merge itself is `lib/label-ref.collectLabelVocabulary` — the same
|
|
29
|
+
* function `--label <name>` resolves through. A separate copy here is how the
|
|
30
|
+
* name you can type and the name you can see start to disagree.
|
|
31
|
+
*/
|
|
8
32
|
class LabelsList extends base_command_1.BaseCommand {
|
|
9
|
-
static description = 'List labels
|
|
33
|
+
static description = 'List labels — every scope you can use, unless --scope narrows it';
|
|
10
34
|
static examples = [
|
|
11
35
|
'<%= config.bin %> labels list',
|
|
12
36
|
'<%= config.bin %> labels list --applicable-to space',
|
|
37
|
+
'<%= config.bin %> labels list --scope user',
|
|
13
38
|
'<%= config.bin %> labels list --scope workspace --scope-id <workspace-id>',
|
|
14
39
|
'<%= config.bin %> labels list --include-archived --json',
|
|
15
40
|
];
|
|
16
41
|
static flags = {
|
|
17
42
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
18
43
|
...label_scope_1.labelScopeFlags,
|
|
44
|
+
// No default, unlike the shared flag: its absence is what selects the
|
|
45
|
+
// merged view, so "not passed" and "passed user" must stay distinguishable.
|
|
46
|
+
scope: core_1.Flags.string({
|
|
47
|
+
description: 'Narrow to ONE scope. Omit to list every scope you can use.',
|
|
48
|
+
options: ['user', 'workspace'],
|
|
49
|
+
}),
|
|
19
50
|
'applicable-to': core_1.Flags.string({
|
|
20
51
|
description: 'Only labels applicable to this entity type',
|
|
21
52
|
options: [...label_scope_1.LABEL_APPLICABLE],
|
|
@@ -25,38 +56,49 @@ class LabelsList extends base_command_1.BaseCommand {
|
|
|
25
56
|
async run() {
|
|
26
57
|
this.requireAuth();
|
|
27
58
|
const { flags } = await this.parse(LabelsList);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
scope = (0, label_scope_1.resolveLabelScope)(flags);
|
|
31
|
-
}
|
|
32
|
-
catch (err) {
|
|
33
|
-
this.error(err.message, { exit: 1 });
|
|
34
|
-
}
|
|
35
|
-
let response;
|
|
59
|
+
const applicableTo = flags['applicable-to'];
|
|
60
|
+
let items = [];
|
|
36
61
|
try {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
: {}),
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
if (flags.scope) {
|
|
63
|
+
const scope = (0, label_scope_1.resolveLabelScope)(flags);
|
|
64
|
+
const response = (await data_provider_1.dataService.getLabels({
|
|
65
|
+
...scope,
|
|
66
|
+
...(applicableTo ? { applicableTo } : {}),
|
|
67
|
+
...(flags['include-archived'] ? { includeArchived: true } : {}),
|
|
68
|
+
}));
|
|
69
|
+
items = response?.data ?? [];
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
items = await (0, label_ref_1.collectLabelVocabulary)({
|
|
73
|
+
...(applicableTo ? { applicableTo } : {}),
|
|
74
|
+
...(process.env.OVERSKY_WORKSPACE_ID
|
|
75
|
+
? { workspaceId: process.env.OVERSKY_WORKSPACE_ID }
|
|
76
|
+
: {}),
|
|
77
|
+
...(flags['include-archived'] ? { includeArchived: true } : {}),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
44
80
|
}
|
|
45
81
|
catch (err) {
|
|
82
|
+
if (err instanceof Error && !('status' in err))
|
|
83
|
+
this.error(err.message, { exit: 1 });
|
|
46
84
|
this.handleApiError(err);
|
|
47
85
|
}
|
|
48
86
|
if (flags.json) {
|
|
49
|
-
this.log(JSON.stringify(
|
|
87
|
+
this.log(JSON.stringify({ data: items }, null, 2));
|
|
50
88
|
return;
|
|
51
89
|
}
|
|
52
|
-
const items = response?.data ?? [];
|
|
53
90
|
if (items.length === 0) {
|
|
54
|
-
this.log(
|
|
91
|
+
this.log(flags.scope
|
|
92
|
+
? 'No labels in this scope.'
|
|
93
|
+
: 'No labels you can use. Create one with `labels create --name <name> --applicable-to <entity>`.');
|
|
55
94
|
return;
|
|
56
95
|
}
|
|
57
96
|
const rows = items.map((l) => ({
|
|
58
97
|
id: String(l.id ?? '-'),
|
|
59
98
|
name: String(l.name ?? '-'),
|
|
99
|
+
// Where it lives decides who else sees it, and it is the one column the
|
|
100
|
+
// old single-scope view never had to show.
|
|
101
|
+
scope: String(l.scope ?? '-'),
|
|
60
102
|
color: String(l.color ?? '-'),
|
|
61
103
|
appliesTo: Array.isArray(l.applicableTo) ? l.applicableTo.join(',') : '-',
|
|
62
104
|
used: String(l.usageCount ?? 0),
|
|
@@ -65,6 +107,7 @@ class LabelsList extends base_command_1.BaseCommand {
|
|
|
65
107
|
(0, format_1.renderTable)(rows, [
|
|
66
108
|
{ key: 'id', header: 'ID' },
|
|
67
109
|
{ key: 'name', header: 'NAME', maxWidth: 32 },
|
|
110
|
+
{ key: 'scope', header: 'SCOPE' },
|
|
68
111
|
{ key: 'color', header: 'COLOR' },
|
|
69
112
|
{ key: 'appliesTo', header: 'APPLIES TO' },
|
|
70
113
|
{ key: 'used', header: 'USED' },
|
|
@@ -41,16 +41,8 @@ class DedicatedMachinesCatalog extends dedicated_lease_command_1.DedicatedLeaseC
|
|
|
41
41
|
this.log('\nSizes (--size-preset)');
|
|
42
42
|
if (catalog.sizes.length === 0)
|
|
43
43
|
this.log(' none offered right now');
|
|
44
|
-
for (const
|
|
45
|
-
|
|
46
|
-
size.vcpus ? `${size.vcpus} vCPU` : '',
|
|
47
|
-
size.memoryGiB ? `${size.memoryGiB} GiB RAM` : '',
|
|
48
|
-
size.accelerator || '',
|
|
49
|
-
]
|
|
50
|
-
.filter(Boolean)
|
|
51
|
-
.join(' · ');
|
|
52
|
-
this.log(` ${String(size.id).padEnd(14)}${spec}`);
|
|
53
|
-
}
|
|
44
|
+
for (const line of (0, dedicated_machines_1.dedicatedCatalogSizeLines)(catalog))
|
|
45
|
+
this.log(line);
|
|
54
46
|
if (catalog.storage) {
|
|
55
47
|
const { minGb, defaultGb, maxGb } = catalog.storage;
|
|
56
48
|
this.log(`\nWorkspace (--storage-gb)\n ${minGb}–${maxGb} GiB, default ${defaultGb}; grow later, never shrink`);
|
|
@@ -64,11 +56,8 @@ class DedicatedMachinesCatalog extends dedicated_lease_command_1.DedicatedLeaseC
|
|
|
64
56
|
if (catalog.regionClasses.length) {
|
|
65
57
|
this.log(`\nRegion (--region-class)\n ${catalog.regionClasses.join(', ')}`);
|
|
66
58
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.log(' not published by this server');
|
|
70
|
-
for (const line of catalog.priceLines) {
|
|
71
|
-
this.log(` ${line.display || `${(0, dedicated_machines_1.formatUsdCents)(line.amountCents)} ${line.label || ''}`}`);
|
|
59
|
+
for (const line of (0, dedicated_machines_1.dedicatedCatalogPriceLineOutput)(catalog.priceLines, catalog.priceBookVersion)) {
|
|
60
|
+
this.log(line);
|
|
72
61
|
}
|
|
73
62
|
}
|
|
74
63
|
}
|
|
@@ -17,6 +17,14 @@ export default class DedicatedMachinesCreate extends DedicatedLeaseCommand {
|
|
|
17
17
|
workspace: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
18
|
'request-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
19
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
20
|
+
yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
21
|
+
'dry-run': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
20
22
|
};
|
|
21
23
|
run(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* The catalog for the summary, or null. Not through `callDedicated`, which
|
|
26
|
+
* exits on an API error: an unreachable catalog must cost the summary its
|
|
27
|
+
* detail, not stop a create the user is about to confirm anyway.
|
|
28
|
+
*/
|
|
29
|
+
private readCatalogForSummary;
|
|
22
30
|
}
|
|
@@ -4,12 +4,14 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const node_crypto_1 = require("node:crypto");
|
|
5
5
|
const dedicated_lease_command_1 = require("../../../lib/dedicated-lease-command");
|
|
6
6
|
const dedicated_machines_1 = require("../../../lib/dedicated-machines");
|
|
7
|
+
const harnesses_1 = require("../../../lib/harnesses");
|
|
7
8
|
class DedicatedMachinesCreate extends dedicated_lease_command_1.DedicatedLeaseCommand {
|
|
8
9
|
static description = 'Request a Dedicated Runtime lease. See `machines dedicated catalog` for sizes, storage bounds and prices.';
|
|
9
10
|
static examples = [
|
|
10
11
|
'<%= config.bin %> machines dedicated create --name dev-box --size-preset standard',
|
|
11
12
|
'<%= config.bin %> machines dedicated create --name dev-box --size-preset standard --spending-limit-cents 20000',
|
|
12
|
-
'<%= config.bin %> machines dedicated create --name dev-box --size-preset standard --
|
|
13
|
+
'<%= config.bin %> machines dedicated create --name dev-box --size-preset standard --dry-run',
|
|
14
|
+
'<%= config.bin %> machines dedicated create --name dev-box --size-preset standard --spending-limit-cents 20000 --repository acme/app --yes --wait --json',
|
|
13
15
|
];
|
|
14
16
|
static flags = {
|
|
15
17
|
name: core_1.Flags.string({ description: 'Display name for the dedicated machine', required: true }),
|
|
@@ -55,6 +57,13 @@ class DedicatedMachinesCreate extends dedicated_lease_command_1.DedicatedLeaseCo
|
|
|
55
57
|
description: 'Idempotency key. Reuse it to safely retry the same create request.',
|
|
56
58
|
}),
|
|
57
59
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
60
|
+
yes: core_1.Flags.boolean({
|
|
61
|
+
char: 'y',
|
|
62
|
+
description: 'Skip the confirmation. A create starts billing, so it asks first; required when not at a terminal.',
|
|
63
|
+
}),
|
|
64
|
+
'dry-run': core_1.Flags.boolean({
|
|
65
|
+
description: 'Show the size, price, storage, retention and cap this create would use, and create nothing',
|
|
66
|
+
}),
|
|
58
67
|
...dedicated_lease_command_1.dedicatedWaitFlags,
|
|
59
68
|
};
|
|
60
69
|
async run() {
|
|
@@ -76,6 +85,40 @@ class DedicatedMachinesCreate extends dedicated_lease_command_1.DedicatedLeaseCo
|
|
|
76
85
|
repositoryRef: flags.repository,
|
|
77
86
|
workspaceId: flags.workspace,
|
|
78
87
|
});
|
|
88
|
+
// Say what is about to be bought before it is, in the catalog's own numbers.
|
|
89
|
+
// `destroy` has always asked first; the command that starts a meter did not
|
|
90
|
+
// (OSK-9592). A catalog read that fails only loses the summary's detail,
|
|
91
|
+
// never the confirmation itself.
|
|
92
|
+
if (flags['dry-run'] || !flags.yes) {
|
|
93
|
+
const catalog = await this.readCatalogForSummary();
|
|
94
|
+
const summary = (0, dedicated_machines_1.dedicatedCreateSummary)(catalog, {
|
|
95
|
+
name: flags.name,
|
|
96
|
+
sizePreset: flags['size-preset'],
|
|
97
|
+
storageGb: flags['storage-gb'],
|
|
98
|
+
retentionClass: flags['retention-class'],
|
|
99
|
+
spendingLimitCents: flags['spending-limit-cents'],
|
|
100
|
+
});
|
|
101
|
+
if (flags['dry-run']) {
|
|
102
|
+
if (flags.json) {
|
|
103
|
+
this.log(JSON.stringify({ dryRun: true, request: body, summary }, null, 2));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
for (const line of summary)
|
|
107
|
+
this.log(line);
|
|
108
|
+
this.log('Dry run: nothing was created.');
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (!process.stdin.isTTY) {
|
|
113
|
+
this.error('Creating a Dedicated Runtime starts billing. Pass --yes to confirm when not at a terminal, or --dry-run to see what it would create.', { exit: 2 });
|
|
114
|
+
}
|
|
115
|
+
for (const line of summary)
|
|
116
|
+
this.log(line);
|
|
117
|
+
if (!(await this.confirm('Create it? [y/N] '))) {
|
|
118
|
+
this.log('Aborted. Nothing was created.');
|
|
119
|
+
this.exit(1);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
79
122
|
const response = await this.callDedicated(() => (0, dedicated_machines_1.createDedicatedRuntime)(body));
|
|
80
123
|
const lease = response?.lease;
|
|
81
124
|
const id = (0, dedicated_machines_1.dedicatedLeaseId)(lease);
|
|
@@ -97,6 +140,20 @@ class DedicatedMachinesCreate extends dedicated_lease_command_1.DedicatedLeaseCo
|
|
|
97
140
|
this.log(`Poll: ${this.config.bin} machines dedicated show ${id} (or pass --wait)`);
|
|
98
141
|
}
|
|
99
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* The catalog for the summary, or null. Not through `callDedicated`, which
|
|
145
|
+
* exits on an API error: an unreachable catalog must cost the summary its
|
|
146
|
+
* detail, not stop a create the user is about to confirm anyway.
|
|
147
|
+
*/
|
|
148
|
+
async readCatalogForSummary() {
|
|
149
|
+
try {
|
|
150
|
+
return (0, dedicated_machines_1.dedicatedCatalogFromProducts)(await (0, harnesses_1.listHarnessProducts)());
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
process.stderr.write(`Could not read the catalog for the summary (${error?.message || 'unknown error'}); showing what was passed.\n`);
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
100
157
|
}
|
|
101
158
|
exports.default = DedicatedMachinesCreate;
|
|
102
159
|
function newRequestId() {
|
|
@@ -45,12 +45,17 @@ class DedicatedMachinesDestroy extends dedicated_lease_command_1.DedicatedLeaseC
|
|
|
45
45
|
// so it does not ask. This mirrors the server's rule only to decide whether
|
|
46
46
|
// to PROMPT; the server still decides what happens.
|
|
47
47
|
let willPurge = Boolean(flags['purge-storage']);
|
|
48
|
+
// Read even under --yes when the workspace may be kept: whether a destroy
|
|
49
|
+
// keeps billing storage is worth saying afterwards, and only the lease as it
|
|
50
|
+
// stood before the destroy can say it.
|
|
51
|
+
const prior = willPurge
|
|
52
|
+
? undefined
|
|
53
|
+
: (await this.callDedicated(() => (0, dedicated_machines_1.getDedicatedRuntime)(leaseId, this.scopeFrom(flags))))
|
|
54
|
+
?.lease;
|
|
48
55
|
if (!willPurge && !flags.yes) {
|
|
49
|
-
const current = await this.callDedicated(() => (0, dedicated_machines_1.getDedicatedRuntime)(leaseId, this.scopeFrom(flags)));
|
|
50
|
-
const lease = current?.lease;
|
|
51
56
|
willPurge =
|
|
52
|
-
|
|
53
|
-
(!flags['retain-storage'] && (
|
|
57
|
+
prior?.state === 'archived' ||
|
|
58
|
+
(!flags['retain-storage'] && (prior?.storage?.retentionClass || 'none') === 'none');
|
|
54
59
|
}
|
|
55
60
|
if (willPurge && !flags.yes) {
|
|
56
61
|
if (!process.stdin.isTTY) {
|
|
@@ -69,6 +74,15 @@ class DedicatedMachinesDestroy extends dedicated_lease_command_1.DedicatedLeaseC
|
|
|
69
74
|
retentionIntent = 'retain';
|
|
70
75
|
const response = await this.callDedicated(() => (0, dedicated_machines_1.destroyDedicatedRuntime)(leaseId, { ...this.scopeFrom(flags), retentionIntent }));
|
|
71
76
|
await this.reportLeaseAction(response, flags, { kind: 'destroyed' }, 'Destroying');
|
|
77
|
+
if (!flags.json) {
|
|
78
|
+
const note = (0, dedicated_machines_1.dedicatedDestroyRetentionNote)(prior, {
|
|
79
|
+
purge: Boolean(flags['purge-storage']),
|
|
80
|
+
retain: Boolean(flags['retain-storage']),
|
|
81
|
+
bin: this.config.bin,
|
|
82
|
+
});
|
|
83
|
+
if (note)
|
|
84
|
+
this.log(note);
|
|
85
|
+
}
|
|
72
86
|
}
|
|
73
87
|
}
|
|
74
88
|
exports.default = DedicatedMachinesDestroy;
|
|
@@ -40,9 +40,14 @@ class DedicatedMachinesList extends dedicated_lease_command_1.DedicatedLeaseComm
|
|
|
40
40
|
}
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
|
+
const scopeSpendCents = (0, dedicated_machines_1.dedicatedScopeMonthSpendCents)(leases);
|
|
44
|
+
if (scopeSpendCents !== null) {
|
|
45
|
+
this.log(`Dedicated Runtime spend this month, across every machine listed: ${(0, dedicated_machines_1.formatUsdCents)(scopeSpendCents)}`);
|
|
46
|
+
this.log('');
|
|
47
|
+
}
|
|
43
48
|
(0, format_1.renderTable)(leases.map((lease) => ({
|
|
44
49
|
id: (0, format_1.formatCell)((0, dedicated_machines_1.dedicatedLeaseId)(lease)),
|
|
45
|
-
status: (0, format_1.formatCell)((0, dedicated_machines_1.
|
|
50
|
+
status: (0, format_1.formatCell)((0, dedicated_machines_1.dedicatedLeaseStatusCell)(lease)),
|
|
46
51
|
name: (0, format_1.formatCell)((0, dedicated_machines_1.dedicatedLeaseDisplayName)(lease)),
|
|
47
52
|
size: (0, format_1.formatCell)([
|
|
48
53
|
lease.resources?.sizePreset,
|
|
@@ -50,17 +55,15 @@ class DedicatedMachinesList extends dedicated_lease_command_1.DedicatedLeaseComm
|
|
|
50
55
|
]
|
|
51
56
|
.filter(Boolean)
|
|
52
57
|
.join(' ') || '-'),
|
|
53
|
-
|
|
54
|
-
? `${(0, dedicated_machines_1.formatUsdCents)(lease.billing.currentMonthSpendCents)}/${(0, dedicated_machines_1.formatUsdCents)(lease.billing.monthlySpendLimitCents)}${lease.billing.spendingLimitExceeded ? ' OVER' : ''}`
|
|
55
|
-
: '-'),
|
|
58
|
+
cap: (0, format_1.formatCell)((0, dedicated_machines_1.dedicatedLeaseCapCell)(lease)),
|
|
56
59
|
retention: (0, format_1.formatCell)(lease.storage?.retentionClass || '-'),
|
|
57
60
|
backup: (0, format_1.formatCell)(lease.storage?.lastBackupAt || '-'),
|
|
58
61
|
})), [
|
|
59
62
|
{ key: 'id', header: 'ID' },
|
|
60
|
-
{ key: 'status', header: 'STATUS' },
|
|
63
|
+
{ key: 'status', header: 'STATUS', maxWidth: 28 },
|
|
61
64
|
{ key: 'name', header: 'NAME', maxWidth: 28 },
|
|
62
65
|
{ key: 'size', header: 'SIZE', maxWidth: 18 },
|
|
63
|
-
{ key: '
|
|
66
|
+
{ key: 'cap', header: 'MONTHLY CAP', maxWidth: 24 },
|
|
64
67
|
{ key: 'retention', header: 'RETENTION', maxWidth: 14 },
|
|
65
68
|
{ key: 'backup', header: 'LAST BACKUP', maxWidth: 24 },
|
|
66
69
|
], (line) => this.log(line));
|
|
@@ -61,6 +61,18 @@ class HostedMachinesList extends base_command_1.BaseCommand {
|
|
|
61
61
|
{ key: 'repos', header: 'REPOS', maxWidth: 36 },
|
|
62
62
|
{ key: 'preview', header: 'PREVIEW', maxWidth: 48 },
|
|
63
63
|
], (line) => this.log(line));
|
|
64
|
+
// How to find the same box in the other list. `machines list` identifies a
|
|
65
|
+
// hosted machine by `lease:<leaseId>` — a different random string from the
|
|
66
|
+
// `sbs_` id in the ID column above — so side by side the two commands read
|
|
67
|
+
// as two unrelated machines. Saying the mapping once, where both values are
|
|
68
|
+
// already on screen, is cheaper than a column nobody can interpret.
|
|
69
|
+
const withLease = sessions.filter((session) => session.machineLeaseId);
|
|
70
|
+
if (withLease.length > 0) {
|
|
71
|
+
this.log('');
|
|
72
|
+
this.log(`In \`${this.config.bin} machines list\` these appear under their LEASE id as ` +
|
|
73
|
+
`\`lease:<lease>\` — e.g. \`lease:${String(withLease[0].machineLeaseId)}\`. ` +
|
|
74
|
+
`\`machines show\` takes either.`);
|
|
75
|
+
}
|
|
64
76
|
}
|
|
65
77
|
/**
|
|
66
78
|
* OSK-2045 — this command lists Hosted Machine *sessions* and nothing else,
|