@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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.listSpaceTaskTargets = listSpaceTaskTargets;
|
|
4
|
+
exports.bulkFailureMessage = bulkFailureMessage;
|
|
4
5
|
exports.applyToTaskTargets = applyToTaskTargets;
|
|
5
6
|
exports.formatBulkOutcome = formatBulkOutcome;
|
|
6
7
|
exports.parseStatusFilter = parseStatusFilter;
|
|
@@ -34,6 +35,38 @@ async function listSpaceTaskTargets(options) {
|
|
|
34
35
|
* semantics match `skrr tasks bulk-update`). `apply` returns whether the task
|
|
35
36
|
* actually changed (already-satisfied tasks are reported as no-ops).
|
|
36
37
|
*/
|
|
38
|
+
/**
|
|
39
|
+
* The server's reason for a failed per-task write, not the transport's.
|
|
40
|
+
*
|
|
41
|
+
* A bulk run used to record `err.message`, which for a dataService call is the
|
|
42
|
+
* transport line — `HTTP 400 Bad Request — PATCH https://…/api/tasks/<id>` — so
|
|
43
|
+
* `tasks actions attach --all-in-space` printed that once per task and named
|
|
44
|
+
* neither the ref nor the rule that refused it (OSK-9652). The same call made
|
|
45
|
+
* for a single task goes through `handleApiError`, which reads the body. This
|
|
46
|
+
* reads it the same way: `message`, then `error`, plus the first validation
|
|
47
|
+
* detail when the server sent one.
|
|
48
|
+
*/
|
|
49
|
+
function bulkFailureMessage(err) {
|
|
50
|
+
const e = err;
|
|
51
|
+
if (e && typeof e.body === 'string' && e.body.trim()) {
|
|
52
|
+
try {
|
|
53
|
+
const body = JSON.parse(e.body);
|
|
54
|
+
const reason = [body.message, body.error].find((value) => typeof value === 'string' && value.trim().length > 0);
|
|
55
|
+
if (reason) {
|
|
56
|
+
const detail = Array.isArray(body.details) ? body.details[0] : undefined;
|
|
57
|
+
const detailText = detail && typeof detail.message === 'string'
|
|
58
|
+
? ` — ${Array.isArray(detail.path) && detail.path.length ? `${detail.path.join('.')}: ` : ''}${detail.message}`
|
|
59
|
+
: '';
|
|
60
|
+
const status = typeof e.status === 'number' ? ` (HTTP ${e.status})` : '';
|
|
61
|
+
return `${reason}${detailText}${status}`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
/* not JSON: fall back to the transport message below */
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return err instanceof Error ? err.message : String(err);
|
|
69
|
+
}
|
|
37
70
|
async function applyToTaskTargets(targets, apply) {
|
|
38
71
|
const result = { succeeded: [], failed: [] };
|
|
39
72
|
for (const target of targets) {
|
|
@@ -46,7 +79,7 @@ async function applyToTaskTargets(targets, apply) {
|
|
|
46
79
|
result.failed.push({
|
|
47
80
|
id: target.id,
|
|
48
81
|
label,
|
|
49
|
-
error:
|
|
82
|
+
error: bulkFailureMessage(err),
|
|
50
83
|
});
|
|
51
84
|
}
|
|
52
85
|
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/** Matches `ManagedCliAuthenticationState` in `daemon/src/cli-installers.ts`. */
|
|
2
|
+
export interface ManagedCliAuthentication {
|
|
3
|
+
status: 'ready' | 'interactive-required' | 'headless-key-required';
|
|
4
|
+
source: 'environment' | 'browser' | 'none';
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Matches `ManagedCliProviderState` in `daemon/src/cli-installers.ts`.
|
|
9
|
+
*
|
|
10
|
+
* Every field optional on purpose: this crosses a version boundary. The daemon
|
|
11
|
+
* on the other end may be older than this CLI (they ship separately, and this
|
|
12
|
+
* machine routinely runs a daemon bundled inside the desktop app), so a missing
|
|
13
|
+
* field has to read as "this daemon does not say", never as a falsy answer.
|
|
14
|
+
*/
|
|
15
|
+
export interface ManagedCliProviderState {
|
|
16
|
+
provider?: string;
|
|
17
|
+
displayName?: string;
|
|
18
|
+
binaryName?: string;
|
|
19
|
+
installed?: boolean;
|
|
20
|
+
available?: boolean;
|
|
21
|
+
version?: string;
|
|
22
|
+
minVersion?: string;
|
|
23
|
+
meetsMinimum?: boolean;
|
|
24
|
+
resolvedPath?: string | null;
|
|
25
|
+
source?: string;
|
|
26
|
+
installable?: boolean;
|
|
27
|
+
installDisabledReason?: string | null;
|
|
28
|
+
platformSupported?: boolean;
|
|
29
|
+
authentication?: ManagedCliAuthentication | null;
|
|
30
|
+
job?: {
|
|
31
|
+
id?: string;
|
|
32
|
+
status?: string;
|
|
33
|
+
} | null;
|
|
34
|
+
}
|
|
35
|
+
export interface CliInstallersResponse {
|
|
36
|
+
daemonId?: string;
|
|
37
|
+
enabled?: boolean;
|
|
38
|
+
platform?: string;
|
|
39
|
+
/** Absent from a daemon older than the field — render as "not reported". */
|
|
40
|
+
daemonVersion?: string;
|
|
41
|
+
providers?: ManagedCliProviderState[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Providers the platform knows about that this daemon did not offer.
|
|
45
|
+
*
|
|
46
|
+
* The inventory is whatever the CONNECTED daemon supports, and an older daemon
|
|
47
|
+
* legitimately supports fewer: `devin` arrived in daemon 0.8.43, so a machine
|
|
48
|
+
* running 0.8.35 answers with six providers instead of seven. Observed here —
|
|
49
|
+
* the desktop app restarted the daemon from its bundled 0.8.35 copy and Devin
|
|
50
|
+
* disappeared from the install list between two page loads, with nothing on
|
|
51
|
+
* either screen to explain it. A provider that silently stops existing reads as
|
|
52
|
+
* dropped support.
|
|
53
|
+
*
|
|
54
|
+
* This works WITHOUT a daemon update, which is the point: `daemonVersion` only
|
|
55
|
+
* helps once apps ship a daemon that reports it, whereas the shared vocabulary
|
|
56
|
+
* is already on this side of the wire. Naming the gap is what turns "Devin is
|
|
57
|
+
* gone" into "this daemon is older than Devin".
|
|
58
|
+
*/
|
|
59
|
+
export declare function providersNotOffered(offered: readonly ManagedCliProviderState[] | undefined, known: readonly string[]): string[];
|
|
60
|
+
export declare function listCliInstallers(daemonId: string, credential?: unknown): Promise<CliInstallersResponse>;
|
|
61
|
+
/**
|
|
62
|
+
* The one-word readiness verdict for a provider, and whether it is good news.
|
|
63
|
+
*
|
|
64
|
+
* Four states, and the fourth is the one that matters most to get right:
|
|
65
|
+
* `unknown`. A provider whose recipe declares no credential resolver reports
|
|
66
|
+
* `authentication: null`, and that is NOT `ready` — this daemon simply has no
|
|
67
|
+
* way to read that vendor's credential state. Collapsing the two is the exact
|
|
68
|
+
* failure `d878b79581` was written to stop, so the word is different and the
|
|
69
|
+
* detail says why.
|
|
70
|
+
*/
|
|
71
|
+
export declare function readinessOf(provider: ManagedCliProviderState): {
|
|
72
|
+
label: string;
|
|
73
|
+
detail: string;
|
|
74
|
+
ok: boolean;
|
|
75
|
+
};
|
|
76
|
+
/** A job the daemon runs to install one managed provider. */
|
|
77
|
+
export interface ManagedCliInstallJob {
|
|
78
|
+
id: string;
|
|
79
|
+
status: 'queued' | 'running' | 'succeeded' | 'failed';
|
|
80
|
+
error?: string;
|
|
81
|
+
log?: string[];
|
|
82
|
+
}
|
|
83
|
+
export interface StartInstallResponse {
|
|
84
|
+
started?: boolean;
|
|
85
|
+
provider?: ManagedCliProviderState;
|
|
86
|
+
job?: {
|
|
87
|
+
id?: string;
|
|
88
|
+
status?: string;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export declare function startManagedCliInstall(daemonId: string, provider: string, credential?: unknown): Promise<StartInstallResponse>;
|
|
92
|
+
export declare function readManagedCliInstallJob(daemonId: string, jobId: string, credential?: unknown): Promise<{
|
|
93
|
+
job?: ManagedCliInstallJob;
|
|
94
|
+
}>;
|
|
95
|
+
/** A 100 MB download over a hotel connection is the case this has to survive. */
|
|
96
|
+
export declare const INSTALL_MAX_WAIT_MS: number;
|
|
97
|
+
export declare const INSTALL_POLL_INTERVAL_MS = 2000;
|
|
98
|
+
export type FollowJobOutcome = {
|
|
99
|
+
kind: 'settled';
|
|
100
|
+
job: ManagedCliInstallJob;
|
|
101
|
+
}
|
|
102
|
+
/** The daemon is still working. NOT a failure — see below. */
|
|
103
|
+
| {
|
|
104
|
+
kind: 'timeout';
|
|
105
|
+
jobId: string;
|
|
106
|
+
} | {
|
|
107
|
+
kind: 'missing';
|
|
108
|
+
jobId: string;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Poll an install job to completion, printing each new log line once.
|
|
112
|
+
*
|
|
113
|
+
* The daemon writes the only account of a download the user is waiting on
|
|
114
|
+
* ("Fetching the signed release manifest", "Verified and installed …"), so the
|
|
115
|
+
* loop relays it; printing only the unseen tail keeps a poll from repeating the
|
|
116
|
+
* whole log each time.
|
|
117
|
+
*
|
|
118
|
+
* A timeout is returned, never thrown as a failure. Saying "install failed"
|
|
119
|
+
* because this process ran out of patience is a lie that sends someone to debug
|
|
120
|
+
* a download that is going fine — so the caller decides the wording, and both
|
|
121
|
+
* callers say the daemon is still working.
|
|
122
|
+
*/
|
|
123
|
+
export declare function followManagedCliInstallJob(input: {
|
|
124
|
+
daemonId: string;
|
|
125
|
+
jobId: string;
|
|
126
|
+
credential?: unknown;
|
|
127
|
+
onLogLine?: (line: string) => void;
|
|
128
|
+
maxWaitMs?: number;
|
|
129
|
+
pollIntervalMs?: number;
|
|
130
|
+
}): Promise<FollowJobOutcome>;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.INSTALL_POLL_INTERVAL_MS = exports.INSTALL_MAX_WAIT_MS = void 0;
|
|
4
|
+
exports.providersNotOffered = providersNotOffered;
|
|
5
|
+
exports.listCliInstallers = listCliInstallers;
|
|
6
|
+
exports.readinessOf = readinessOf;
|
|
7
|
+
exports.startManagedCliInstall = startManagedCliInstall;
|
|
8
|
+
exports.readManagedCliInstallJob = readManagedCliInstallJob;
|
|
9
|
+
exports.followManagedCliInstallJob = followManagedCliInstallJob;
|
|
10
|
+
/**
|
|
11
|
+
* The daemon's managed-CLI installer inventory, as the CLI reads it.
|
|
12
|
+
*
|
|
13
|
+
* ## Why this file exists
|
|
14
|
+
*
|
|
15
|
+
* `GET /api/daemons/:id/cli-installers` is where `d878b79581` put the answer to
|
|
16
|
+
* "is this harness actually usable" — `installed`, and for providers whose
|
|
17
|
+
* credential state the daemon can read, one of `ready` /
|
|
18
|
+
* `interactive-required` / `headless-key-required`. The whole point of that
|
|
19
|
+
* change was to stop surfaces answering "is the binary there" instead.
|
|
20
|
+
*
|
|
21
|
+
* The CLI called the route from exactly one place (`commands/code/install.ts`),
|
|
22
|
+
* for one provider, to read one field, and showed the user none of it. So from
|
|
23
|
+
* the CLI there was no way to learn that a harness listed as `online` had no
|
|
24
|
+
* binary at all — which is the state this account's `skrr-code` row was in.
|
|
25
|
+
*
|
|
26
|
+
* The shape lives here rather than beside a command because two commands read
|
|
27
|
+
* it now. Root `CLAUDE.md`: a second declaration is how a surface silently
|
|
28
|
+
* drifts from the server that produced it.
|
|
29
|
+
*/
|
|
30
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
31
|
+
const api_fetch_1 = require("./api-fetch");
|
|
32
|
+
/**
|
|
33
|
+
* Providers the platform knows about that this daemon did not offer.
|
|
34
|
+
*
|
|
35
|
+
* The inventory is whatever the CONNECTED daemon supports, and an older daemon
|
|
36
|
+
* legitimately supports fewer: `devin` arrived in daemon 0.8.43, so a machine
|
|
37
|
+
* running 0.8.35 answers with six providers instead of seven. Observed here —
|
|
38
|
+
* the desktop app restarted the daemon from its bundled 0.8.35 copy and Devin
|
|
39
|
+
* disappeared from the install list between two page loads, with nothing on
|
|
40
|
+
* either screen to explain it. A provider that silently stops existing reads as
|
|
41
|
+
* dropped support.
|
|
42
|
+
*
|
|
43
|
+
* This works WITHOUT a daemon update, which is the point: `daemonVersion` only
|
|
44
|
+
* helps once apps ship a daemon that reports it, whereas the shared vocabulary
|
|
45
|
+
* is already on this side of the wire. Naming the gap is what turns "Devin is
|
|
46
|
+
* gone" into "this daemon is older than Devin".
|
|
47
|
+
*/
|
|
48
|
+
function providersNotOffered(offered, known) {
|
|
49
|
+
// Canonicalize BOTH sides. An older daemon answers under the spelling it was
|
|
50
|
+
// built with — the 0.8.35 build reports the first-party harness as
|
|
51
|
+
// `sky-code`, so a raw comparison against `skrr-code` reported it missing on
|
|
52
|
+
// a machine where it is installed and working. Caught by running this against
|
|
53
|
+
// the very daemon the finding was about: the first version of this helper
|
|
54
|
+
// said "Not offered: devin, skrr-code" when only `devin` was true.
|
|
55
|
+
const canonical = (value) => typeof value === 'string' ? String((0, data_provider_1.canonicalHarnessProvider)(value) ?? value) : '';
|
|
56
|
+
const seen = new Set((offered ?? []).map((provider) => canonical(provider.provider)).filter(Boolean));
|
|
57
|
+
return known.filter((provider) => !seen.has(canonical(provider)));
|
|
58
|
+
}
|
|
59
|
+
async function listCliInstallers(daemonId, credential) {
|
|
60
|
+
return (0, api_fetch_1.apiFetch)(`/api/daemons/${encodeURIComponent(daemonId)}/cli-installers`, { credential: credential });
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The one-word readiness verdict for a provider, and whether it is good news.
|
|
64
|
+
*
|
|
65
|
+
* Four states, and the fourth is the one that matters most to get right:
|
|
66
|
+
* `unknown`. A provider whose recipe declares no credential resolver reports
|
|
67
|
+
* `authentication: null`, and that is NOT `ready` — this daemon simply has no
|
|
68
|
+
* way to read that vendor's credential state. Collapsing the two is the exact
|
|
69
|
+
* failure `d878b79581` was written to stop, so the word is different and the
|
|
70
|
+
* detail says why.
|
|
71
|
+
*/
|
|
72
|
+
function readinessOf(provider) {
|
|
73
|
+
if (provider.platformSupported === false) {
|
|
74
|
+
return { label: 'unsupported', detail: 'Not available on this platform.', ok: false };
|
|
75
|
+
}
|
|
76
|
+
if (!provider.installed) {
|
|
77
|
+
// `available` without `meetsMinimum` is a REAL third case and reads very
|
|
78
|
+
// differently from "not installed": the binary is right there and too old.
|
|
79
|
+
if (provider.available && provider.meetsMinimum === false) {
|
|
80
|
+
return {
|
|
81
|
+
label: 'too-old',
|
|
82
|
+
detail: provider.minVersion
|
|
83
|
+
? `Found ${provider.version || 'an older build'}; needs ${provider.minVersion} or newer.`
|
|
84
|
+
: 'The installed build is older than the minimum this harness needs.',
|
|
85
|
+
ok: false,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
label: 'not-installed',
|
|
90
|
+
detail: provider.installDisabledReason || 'No binary for this provider on this machine.',
|
|
91
|
+
ok: false,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const auth = provider.authentication;
|
|
95
|
+
if (!auth) {
|
|
96
|
+
return {
|
|
97
|
+
label: 'unknown',
|
|
98
|
+
detail: 'Installed. This daemon cannot read this provider’s credential state.',
|
|
99
|
+
ok: false,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return { label: auth.status, detail: auth.message, ok: auth.status === 'ready' };
|
|
103
|
+
}
|
|
104
|
+
async function startManagedCliInstall(daemonId, provider, credential) {
|
|
105
|
+
return (0, api_fetch_1.apiFetch)(`/api/daemons/${encodeURIComponent(daemonId)}/cli-installers/${encodeURIComponent(provider)}/install`, { method: 'POST', body: {}, credential: credential });
|
|
106
|
+
}
|
|
107
|
+
async function readManagedCliInstallJob(daemonId, jobId, credential) {
|
|
108
|
+
return (0, api_fetch_1.apiFetch)(`/api/daemons/${encodeURIComponent(daemonId)}/cli-installers/jobs/${encodeURIComponent(jobId)}`, { credential: credential });
|
|
109
|
+
}
|
|
110
|
+
/** A 100 MB download over a hotel connection is the case this has to survive. */
|
|
111
|
+
exports.INSTALL_MAX_WAIT_MS = 10 * 60_000;
|
|
112
|
+
exports.INSTALL_POLL_INTERVAL_MS = 2_000;
|
|
113
|
+
/**
|
|
114
|
+
* Poll an install job to completion, printing each new log line once.
|
|
115
|
+
*
|
|
116
|
+
* The daemon writes the only account of a download the user is waiting on
|
|
117
|
+
* ("Fetching the signed release manifest", "Verified and installed …"), so the
|
|
118
|
+
* loop relays it; printing only the unseen tail keeps a poll from repeating the
|
|
119
|
+
* whole log each time.
|
|
120
|
+
*
|
|
121
|
+
* A timeout is returned, never thrown as a failure. Saying "install failed"
|
|
122
|
+
* because this process ran out of patience is a lie that sends someone to debug
|
|
123
|
+
* a download that is going fine — so the caller decides the wording, and both
|
|
124
|
+
* callers say the daemon is still working.
|
|
125
|
+
*/
|
|
126
|
+
async function followManagedCliInstallJob(input) {
|
|
127
|
+
const deadline = Date.now() + (input.maxWaitMs ?? exports.INSTALL_MAX_WAIT_MS);
|
|
128
|
+
let printed = 0;
|
|
129
|
+
for (;;) {
|
|
130
|
+
const res = await readManagedCliInstallJob(input.daemonId, input.jobId, input.credential);
|
|
131
|
+
const job = res.job;
|
|
132
|
+
if (!job)
|
|
133
|
+
return { kind: 'missing', jobId: input.jobId };
|
|
134
|
+
if (input.onLogLine) {
|
|
135
|
+
for (const line of (job.log ?? []).slice(printed))
|
|
136
|
+
input.onLogLine(line);
|
|
137
|
+
printed = (job.log ?? []).length;
|
|
138
|
+
}
|
|
139
|
+
if (job.status === 'succeeded' || job.status === 'failed')
|
|
140
|
+
return { kind: 'settled', job };
|
|
141
|
+
if (Date.now() > deadline)
|
|
142
|
+
return { kind: 'timeout', jobId: input.jobId };
|
|
143
|
+
await new Promise((resolve) => setTimeout(resolve, input.pollIntervalMs ?? exports.INSTALL_POLL_INTERVAL_MS));
|
|
144
|
+
}
|
|
145
|
+
}
|
package/dist/lib/command-miss.js
CHANGED
|
@@ -104,17 +104,65 @@ function describeCommandMiss(config, id) {
|
|
|
104
104
|
// command id, so a whole-string comparison finds nothing and the reader is
|
|
105
105
|
// told only that they are wrong — when the useful answer is "that topic
|
|
106
106
|
// exists and here is what it does have".
|
|
107
|
+
const typedId = parts.join(':');
|
|
108
|
+
const spokenId = `${config.bin} ${parts.join(' ')}`;
|
|
109
|
+
// The id IS registered and the lookup still could not produce it. That is not
|
|
110
|
+
// a typo, so the "is not a command" wording below would be false — and worse,
|
|
111
|
+
// the suggestion search then finds the id itself and hands the reader their
|
|
112
|
+
// own input back:
|
|
113
|
+
//
|
|
114
|
+
// $ skrr agents list --help
|
|
115
|
+
// Error: `skrr agents list` is not a command.
|
|
116
|
+
// Did you mean: `skrr agents list`?
|
|
117
|
+
//
|
|
118
|
+
// Observed against a real build, for ten commands in a row, and it is actively
|
|
119
|
+
// misleading rather than merely unhelpful: a dogfood run read it as proof that
|
|
120
|
+
// a shipped release had not shipped its commands. The two facts come from two
|
|
121
|
+
// sources — `findCommand` loads, `commandIDs` lists — and when they disagree
|
|
122
|
+
// the honest thing to report is the disagreement, which has a known cause and
|
|
123
|
+
// a next step.
|
|
124
|
+
if (config.commandIDs.includes(typedId) || config.topicNames.includes(typedId)) {
|
|
125
|
+
return (`\`${spokenId}\` is registered but could not be loaded from this build.\n` +
|
|
126
|
+
`Its compiled output is missing or stale — run \`npm --prefix cli run build\` in a ` +
|
|
127
|
+
`development checkout, or reinstall the CLI.`);
|
|
128
|
+
}
|
|
107
129
|
const siblings = config.commandIDs.filter((c) => c.startsWith(`${parts[0]}:`));
|
|
108
|
-
const suggestions = siblings.length
|
|
130
|
+
const suggestions = (siblings.length
|
|
109
131
|
? nearestCommands(parts.slice(0, 2).join(':'), siblings)
|
|
110
|
-
: nearestCommands(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
132
|
+
: nearestCommands(typedId, [...config.commandIDs, ...config.topicNames]))
|
|
133
|
+
// A suggestion identical to what was typed is an echo, not a correction.
|
|
134
|
+
// It can outrank real alternatives too, since nothing is closer to the id
|
|
135
|
+
// than the id, so it costs a suggestion slot as well as the reader's trust.
|
|
136
|
+
.filter((candidate) => candidate !== typedId);
|
|
137
|
+
if (suggestions.length) {
|
|
138
|
+
return (`\`${spokenId}\` is not a command.` +
|
|
139
|
+
`\nDid you mean: ${suggestions
|
|
114
140
|
.map((s) => `\`${config.bin} ${s.split(':').join(' ')}\``)
|
|
115
|
-
.join(', ')}?`
|
|
116
|
-
|
|
141
|
+
.join(', ')}?`);
|
|
142
|
+
}
|
|
143
|
+
// The topic the reader typed is real, and nothing in it is spelled like what
|
|
144
|
+
// they asked for — a different word for it, not a typo. "See the topics"
|
|
145
|
+
// sent them back to the top level to rediscover the topic they had already
|
|
146
|
+
// found; what they need is what THIS topic has (OSK-9723: `skrr dm send`,
|
|
147
|
+
// where `dm` has no `send` at all).
|
|
148
|
+
if (siblings.length) {
|
|
149
|
+
const topic = parts[0];
|
|
150
|
+
const shown = siblings
|
|
151
|
+
.map((id) => id
|
|
152
|
+
.slice(topic.length + 1)
|
|
153
|
+
.split(':')
|
|
154
|
+
.join(' '))
|
|
155
|
+
.sort()
|
|
156
|
+
.slice(0, MAX_TOPIC_LISTING);
|
|
157
|
+
const more = siblings.length > shown.length ? ', …' : '';
|
|
158
|
+
return (`\`${spokenId}\` is not a command.\n` +
|
|
159
|
+
`\`${config.bin} ${topic}\` has: ${shown.map((c) => `\`${c}\``).join(', ')}${more}.\n` +
|
|
160
|
+
`See \`${config.bin} ${topic} --help\`.`);
|
|
161
|
+
}
|
|
162
|
+
return `\`${spokenId}\` is not a command.\nRun \`${config.bin} --help\` to see the topics.`;
|
|
117
163
|
}
|
|
164
|
+
/** Enough to scan at a glance; the topic's own `--help` has the rest. */
|
|
165
|
+
const MAX_TOPIC_LISTING = 10;
|
|
118
166
|
/** Adapt an oclif `Config` to the lookup shape above. */
|
|
119
167
|
function lookupFromConfig(config) {
|
|
120
168
|
return {
|
|
@@ -65,3 +65,16 @@ export declare abstract class DedicatedLeaseCommand extends BaseCommand {
|
|
|
65
65
|
}
|
|
66
66
|
/** The same transient verdict BaseCommand gives an ordinary API call. */
|
|
67
67
|
export declare function dedicatedRuntimeApiErrorRetryable(err: unknown): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Accept the id our own output printed.
|
|
70
|
+
*
|
|
71
|
+
* `skrr machines list --all` renders a Dedicated Runtime's MACHINE identity,
|
|
72
|
+
* which the server builds as `lease:${leaseId}` (`machineIdentityForHarness`).
|
|
73
|
+
* The lease routes want the bare `rtl_…`. Pasting the one you were just shown
|
|
74
|
+
* therefore 404'd, and the refusal blamed workspace scope — sending you to try
|
|
75
|
+
* `--workspace` when the fix was deleting six characters.
|
|
76
|
+
*
|
|
77
|
+
* Only the prefixes this product itself prints are stripped, so a genuinely
|
|
78
|
+
* unknown id still fails as an unknown id rather than being silently reshaped.
|
|
79
|
+
*/
|
|
80
|
+
export declare function stripMachineIdentityPrefix(ref: string): string;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DedicatedLeaseCommand = exports.DEDICATED_LEASE_ARG_DESCRIPTION = exports.DEDICATED_SELF_LEASE = exports.dedicatedWaitFlags = void 0;
|
|
4
4
|
exports.dedicatedRuntimeApiErrorRetryable = dedicatedRuntimeApiErrorRetryable;
|
|
5
|
+
exports.stripMachineIdentityPrefix = stripMachineIdentityPrefix;
|
|
5
6
|
const core_1 = require("@oclif/core");
|
|
6
7
|
const base_command_1 = require("../base-command");
|
|
7
8
|
const api_fetch_1 = require("./api-fetch");
|
|
@@ -51,7 +52,7 @@ class DedicatedLeaseCommand extends base_command_1.BaseCommand {
|
|
|
51
52
|
*/
|
|
52
53
|
async resolveLeaseArg(lease) {
|
|
53
54
|
if (lease !== exports.DEDICATED_SELF_LEASE)
|
|
54
|
-
return lease;
|
|
55
|
+
return stripMachineIdentityPrefix(lease);
|
|
55
56
|
const descriptor = (0, daemonBroker_1.readBootstrap)(daemonBroker_1.DEDICATED_RUNTIME_CLI_HANDOFF_DESCRIPTOR);
|
|
56
57
|
if (!descriptor?.daemonId) {
|
|
57
58
|
this.error('`self` means the Dedicated Runtime this command runs on, and this is not one (or its daemon is not running). Pass a lease id.', { exit: 2 });
|
|
@@ -226,3 +227,23 @@ function dedicatedRuntimeApiErrorRetryable(err) {
|
|
|
226
227
|
}
|
|
227
228
|
return (0, base_command_1.isRetryableFailure)(err.status, body);
|
|
228
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Accept the id our own output printed.
|
|
232
|
+
*
|
|
233
|
+
* `skrr machines list --all` renders a Dedicated Runtime's MACHINE identity,
|
|
234
|
+
* which the server builds as `lease:${leaseId}` (`machineIdentityForHarness`).
|
|
235
|
+
* The lease routes want the bare `rtl_…`. Pasting the one you were just shown
|
|
236
|
+
* therefore 404'd, and the refusal blamed workspace scope — sending you to try
|
|
237
|
+
* `--workspace` when the fix was deleting six characters.
|
|
238
|
+
*
|
|
239
|
+
* Only the prefixes this product itself prints are stripped, so a genuinely
|
|
240
|
+
* unknown id still fails as an unknown id rather than being silently reshaped.
|
|
241
|
+
*/
|
|
242
|
+
function stripMachineIdentityPrefix(ref) {
|
|
243
|
+
const trimmed = ref.trim();
|
|
244
|
+
for (const prefix of ['lease:', 'dedicated-runtime:']) {
|
|
245
|
+
if (trimmed.startsWith(prefix))
|
|
246
|
+
return trimmed.slice(prefix.length);
|
|
247
|
+
}
|
|
248
|
+
return trimmed;
|
|
249
|
+
}
|
|
@@ -389,10 +389,57 @@ export type DedicatedCopyPlan = {
|
|
|
389
389
|
export declare function parseDedicatedCopyEndpoints(source: string, destination: string): DedicatedCopyPlan;
|
|
390
390
|
export declare function dedicatedLeaseId(lease: DedicatedLease | HarnessLease | undefined | null): string;
|
|
391
391
|
export declare function dedicatedLeaseState(lease: DedicatedLease | HarnessLease | undefined | null): string;
|
|
392
|
+
/**
|
|
393
|
+
* What `destroy` should say when it keeps the workspace — or null when it does
|
|
394
|
+
* not.
|
|
395
|
+
*
|
|
396
|
+
* A destroy under retention class standard/extended archives the lease and keeps
|
|
397
|
+
* its workspace volume, which keeps billing storage until it is purged. Nothing
|
|
398
|
+
* said so at the moment it mattered: `destroy` printed the new state and exited,
|
|
399
|
+
* `list` showed `archived` in the same column as `terminated`, and the one way to
|
|
400
|
+
* find out was the bill (OSK-9593).
|
|
401
|
+
*/
|
|
402
|
+
export declare function dedicatedDestroyRetentionNote(priorLease: DedicatedLease | undefined | null, opts: {
|
|
403
|
+
purge: boolean;
|
|
404
|
+
retain: boolean;
|
|
405
|
+
bin: string;
|
|
406
|
+
}): string | null;
|
|
407
|
+
/**
|
|
408
|
+
* Month-to-date Dedicated Runtime spend for the scope a `list` shows.
|
|
409
|
+
*
|
|
410
|
+
* `billing.currentMonthSpendCents` is the SCOPE's spend for the product — the
|
|
411
|
+
* server aggregates by owner scope, not by lease — so every row carried the same
|
|
412
|
+
* figure, and a column headed MONTH/CAP on per-machine rows read as that
|
|
413
|
+
* machine's cost when it was every machine's (OSK-9576). It is said once instead.
|
|
414
|
+
*/
|
|
415
|
+
export declare function dedicatedScopeMonthSpendCents(leases: Array<DedicatedLease | undefined | null>): number | null;
|
|
416
|
+
/**
|
|
417
|
+
* A lease's own cap, marked when the scope's spend has reached it. The mark is
|
|
418
|
+
* left off a terminal lease: its cap can no longer stop anything, and
|
|
419
|
+
* "$11.06/$10.00 OVER" on a machine terminated days ago read as that machine
|
|
420
|
+
* having overrun.
|
|
421
|
+
*/
|
|
422
|
+
export declare function dedicatedLeaseCapCell(lease: DedicatedLease | undefined | null): string;
|
|
423
|
+
/**
|
|
424
|
+
* A lease's STATUS cell. `archived` and `terminated` are both "gone" to read, and
|
|
425
|
+
* only one of them is still charging — so a lease billing retained storage says
|
|
426
|
+
* so (OSK-9593).
|
|
427
|
+
*/
|
|
428
|
+
export declare function dedicatedLeaseStatusCell(lease: DedicatedLease | undefined | null): string;
|
|
392
429
|
export declare function dedicatedLeaseDisplayName(lease: DedicatedLease | HarnessLease | undefined | null): string;
|
|
393
430
|
/** `$12.34` — cents are what the API speaks; dollars are what a person reads. */
|
|
394
431
|
export declare function formatUsdCents(cents: number | null | undefined): string;
|
|
395
|
-
/**
|
|
432
|
+
/**
|
|
433
|
+
* `$1.23 this month for machines of this type · $500.00 cap for this machine`,
|
|
434
|
+
* or why that sentence cannot be written.
|
|
435
|
+
*
|
|
436
|
+
* The two figures are different scopes and the sentence has to say so. The spend
|
|
437
|
+
* is a shared pot the server computes for (owner, team, machineProduct), so every
|
|
438
|
+
* lease of the same product reports the same number — a machine created minutes
|
|
439
|
+
* ago with no active seconds still reports the month's total. The cap is this
|
|
440
|
+
* lease's own. Printed as "$1.23 this month of $500.00 cap" the only available
|
|
441
|
+
* reading was that this machine had spent it.
|
|
442
|
+
*/
|
|
396
443
|
export declare function dedicatedSpendSummary(lease: DedicatedLease): string;
|
|
397
444
|
/**
|
|
398
445
|
* The human rendering of `machines dedicated show`, as lines.
|
|
@@ -461,12 +508,15 @@ interface CatalogSize {
|
|
|
461
508
|
vcpus?: number;
|
|
462
509
|
memoryGiB?: number;
|
|
463
510
|
accelerator?: string;
|
|
511
|
+
rateCentsPerHour?: number | null;
|
|
464
512
|
}
|
|
465
513
|
interface CatalogPriceLine {
|
|
466
514
|
label?: string;
|
|
467
515
|
display?: string;
|
|
468
516
|
amountCents?: number | null;
|
|
469
517
|
cadence?: string;
|
|
518
|
+
/** `charge` is billed, `hold` is reserved at start, `limit` is a cap. Absent means `charge`. */
|
|
519
|
+
kind?: 'charge' | 'hold' | 'limit';
|
|
470
520
|
}
|
|
471
521
|
export interface DedicatedCatalog {
|
|
472
522
|
availability: string;
|
|
@@ -480,9 +530,15 @@ export interface DedicatedCatalog {
|
|
|
480
530
|
};
|
|
481
531
|
retentionClasses: string[];
|
|
482
532
|
backupProfiles: string[];
|
|
533
|
+
/** Server-declared: what create applies when a flag is omitted. */
|
|
534
|
+
defaultSizePreset?: string;
|
|
535
|
+
defaultRetentionClass?: string;
|
|
536
|
+
defaultBackupProfile?: string;
|
|
483
537
|
defaultMonthlySpendingLimitCents?: number | null;
|
|
484
538
|
maxUserMonthlySpendingLimitCents?: number | null;
|
|
485
539
|
priceLines: CatalogPriceLine[];
|
|
540
|
+
/** The price book the quoted prices come from — what a later pricing question cites. */
|
|
541
|
+
priceBookVersion?: string;
|
|
486
542
|
headline?: string;
|
|
487
543
|
}
|
|
488
544
|
/**
|
|
@@ -493,6 +549,44 @@ export interface DedicatedCatalog {
|
|
|
493
549
|
* gated by server flags — so this is where a caller learns which ones exist.
|
|
494
550
|
*/
|
|
495
551
|
export declare function dedicatedCatalogFromProducts(payload: unknown): DedicatedCatalog | null;
|
|
552
|
+
/**
|
|
553
|
+
* The catalog's size rows: spec, the size's own hourly price, and which one
|
|
554
|
+
* `create` uses by default. The rows used to carry spec alone, sorted by name,
|
|
555
|
+
* so the $1.40/hr tier came first with nothing saying what it cost or that
|
|
556
|
+
* $0.65/hr standard was the default; a reader had to join two blocks by name.
|
|
557
|
+
*/
|
|
558
|
+
export declare function dedicatedCatalogSizeLines(catalog: DedicatedCatalog): string[];
|
|
559
|
+
export interface DedicatedCreateChoices {
|
|
560
|
+
name: string;
|
|
561
|
+
sizePreset: string;
|
|
562
|
+
storageGb?: number;
|
|
563
|
+
retentionClass?: string;
|
|
564
|
+
spendingLimitCents?: number;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* What a create is about to buy, in the words and numbers the catalog uses.
|
|
568
|
+
*
|
|
569
|
+
* `create` provisioned a billable machine the moment it ran — no confirmation,
|
|
570
|
+
* no dry run, and every omitted flag silently took a paid default — while
|
|
571
|
+
* `destroy` asked first. A loop probing size validation bought two real
|
|
572
|
+
* machines, one of them $1.40/hr (OSK-9592). This is what `create` now shows
|
|
573
|
+
* before it asks, and what `--dry-run` prints instead of creating.
|
|
574
|
+
*
|
|
575
|
+
* Every default comes from the catalog, never from this file: a CLI that
|
|
576
|
+
* restates a default it does not own is how `--storage-gb` once billed twice the
|
|
577
|
+
* product's disk. A value the catalog does not declare is shown as "server
|
|
578
|
+
* default" rather than guessed.
|
|
579
|
+
*/
|
|
580
|
+
export declare function dedicatedCreateSummary(catalog: DedicatedCatalog | null, choices: DedicatedCreateChoices): string[];
|
|
581
|
+
/**
|
|
582
|
+
* The catalog's money lines, grouped by what each amount IS.
|
|
583
|
+
*
|
|
584
|
+
* A start hold and a monthly cap used to print under "Prices" beside the hourly
|
|
585
|
+
* rates, so starting a machine read as a 33c charge and "$500 default monthly
|
|
586
|
+
* cap" read as a bill (OSK-9536). A line with no `kind` comes from a server that
|
|
587
|
+
* predates it and is shown the way every line used to be: as a charge.
|
|
588
|
+
*/
|
|
589
|
+
export declare function dedicatedCatalogPriceLineOutput(priceLines: CatalogPriceLine[], priceBookVersion?: string): string[];
|
|
496
590
|
/**
|
|
497
591
|
* The product refusal code the server sent (`DEDICATED_RUNTIME_NOT_ASSIGNABLE`,
|
|
498
592
|
* …), for `this.error(message, { code })`. Without it a `--json` caller got the
|