@skrr-ai/cli 0.1.37 → 0.1.39
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/bin/dev-fallback.js +175 -4
- package/dist/base-command.js +46 -2
- package/dist/commands/agents/actions/create.js +18 -7
- 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.js +5 -3
- package/dist/commands/agents/api-actions/add.js +5 -2
- package/dist/commands/agents/api-actions/index.d.ts +11 -0
- package/dist/commands/agents/api-actions/index.js +27 -1
- package/dist/commands/agents/avatar/default/index.d.ts +11 -0
- package/dist/commands/agents/avatar/default/index.js +17 -0
- package/dist/commands/agents/avatar/default/set.d.ts +2 -1
- package/dist/commands/agents/avatar/default/set.js +32 -7
- package/dist/commands/agents/avatar/upload.js +7 -1
- package/dist/commands/agents/categories/delete.js +8 -0
- package/dist/commands/agents/categories/index.d.ts +21 -5
- package/dist/commands/agents/categories/index.js +68 -15
- package/dist/commands/agents/chat.d.ts +21 -0
- package/dist/commands/agents/chat.js +94 -7
- package/dist/commands/agents/create.js +11 -4
- package/dist/commands/agents/list.d.ts +15 -0
- package/dist/commands/agents/list.js +31 -1
- 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/calls.d.ts +23 -5
- package/dist/commands/agents/tools/calls.js +81 -18
- package/dist/commands/agents/update.js +15 -5
- 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.js +3 -2
- package/dist/commands/followups/cancel.d.ts +6 -3
- package/dist/commands/followups/cancel.js +16 -6
- package/dist/commands/followups/observability.d.ts +23 -0
- package/dist/commands/followups/observability.js +114 -0
- package/dist/commands/followups/reschedule.js +1 -1
- package/dist/commands/followups/resolve.js +3 -3
- package/dist/commands/followups/show.js +2 -1
- package/dist/commands/followups/watch.js +9 -5
- 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/machines/dedicated/catalog.js +4 -15
- package/dist/commands/machines/dedicated/create.d.ts +8 -0
- package/dist/commands/machines/dedicated/create.js +63 -2
- package/dist/commands/machines/dedicated/destroy.js +19 -5
- package/dist/commands/machines/dedicated/exec.js +3 -1
- package/dist/commands/machines/dedicated/list.js +9 -6
- package/dist/commands/machines/dedicated/price-book.d.ts +17 -0
- package/dist/commands/machines/dedicated/price-book.js +35 -0
- 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/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/label-summaries.d.ts +27 -0
- package/dist/commands/spaces/label-summaries.js +64 -0
- package/dist/commands/spaces/task-rollups.d.ts +5 -0
- package/dist/commands/spaces/task-rollups.js +15 -4
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +63 -3
- package/dist/commands/tasks/actions/attach.js +32 -7
- package/dist/commands/tasks/complete.js +13 -0
- package/dist/commands/tasks/create.js +1 -1
- package/dist/commands/tasks/events/append.js +29 -6
- package/dist/commands/tasks/expectations/assess.d.ts +1 -0
- package/dist/commands/tasks/expectations/assess.js +43 -5
- package/dist/commands/tasks/expectations.js +77 -16
- package/dist/commands/tasks/follow-up.js +2 -2
- package/dist/commands/tasks/lifecycle/definitions.js +21 -2
- package/dist/commands/tasks/lifecycle/detach.d.ts +7 -0
- package/dist/commands/tasks/lifecycle/detach.js +43 -3
- package/dist/commands/tasks/lifecycle/migrate.d.ts +2 -0
- package/dist/commands/tasks/lifecycle/migrate.js +42 -3
- package/dist/commands/tasks/lifecycle/reopen.d.ts +2 -0
- package/dist/commands/tasks/lifecycle/reopen.js +40 -3
- package/dist/commands/tasks/lifecycle/transition.js +33 -2
- package/dist/commands/tasks/list.js +16 -9
- package/dist/commands/tasks/move.js +11 -13
- package/dist/commands/tasks/review-queue.d.ts +15 -0
- package/dist/commands/tasks/review-queue.js +180 -31
- package/dist/commands/tasks/show.d.ts +11 -0
- package/dist/commands/tasks/show.js +105 -12
- package/dist/commands/tasks/trust.js +7 -2
- package/dist/commands/tasks/update.js +46 -10
- 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 +57 -2
- package/dist/lib/agent-actions.js +113 -21
- package/dist/lib/agent-pin-mute.d.ts +10 -5
- package/dist/lib/agent-pin-mute.js +17 -4
- package/dist/lib/agent-visual-refs.d.ts +27 -0
- package/dist/lib/agent-visual-refs.js +127 -2
- 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 +16 -1
- package/dist/lib/dedicated-lease-command.js +26 -3
- package/dist/lib/dedicated-machines.d.ts +135 -1
- package/dist/lib/dedicated-machines.js +307 -3
- 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 +9 -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 +14 -6
- package/dist/lib/followups.js +31 -6
- 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-scope.d.ts +15 -0
- package/dist/lib/label-scope.js +25 -5
- 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 +3 -2
- package/dist/lib/task-closure.js +18 -20
- package/dist/lib/task-lifecycle-output.js +117 -9
- package/dist/lib/task-ref-resolver.d.ts +1 -17
- package/dist/lib/task-ref-resolver.js +18 -8
- package/dist/lib/tasks.js +9 -3
- package/dist/node_modules/@skrr-ai/data-provider/index.js +5076 -4947
- package/oclif.manifest.json +15505 -14460
- package/package.json +9 -3
|
@@ -221,6 +221,46 @@ export declare function dedicatedRuntimeCreateInput(input: {
|
|
|
221
221
|
*/
|
|
222
222
|
export declare function isDedicatedRepositoryRef(value: string): boolean;
|
|
223
223
|
export declare function createDedicatedRuntime(input: CreateDedicatedRuntimeInput): Promise<DedicatedRuntimeResponse>;
|
|
224
|
+
/** One offered tier as the operator price book checks it. */
|
|
225
|
+
export interface DedicatedPriceBookPresetCheck {
|
|
226
|
+
sizePreset: string;
|
|
227
|
+
customerRateCentsPerHour: number | null;
|
|
228
|
+
providerCostCentsPerHour: number | null;
|
|
229
|
+
grossMarginBps: number | null;
|
|
230
|
+
priced: boolean;
|
|
231
|
+
providerCostRecorded: boolean;
|
|
232
|
+
marginTargetMet: boolean;
|
|
233
|
+
}
|
|
234
|
+
/** `GET /api/machines/dedicated/price-book` — admin only. */
|
|
235
|
+
export interface DedicatedOperatorPriceBook {
|
|
236
|
+
timestamp?: string;
|
|
237
|
+
availability: 'available' | 'disabled';
|
|
238
|
+
disabledReason: string | null;
|
|
239
|
+
configError: string | null;
|
|
240
|
+
priceBook: {
|
|
241
|
+
required: boolean;
|
|
242
|
+
approved: boolean;
|
|
243
|
+
version: string | null;
|
|
244
|
+
pricingPolicyRef: string | null;
|
|
245
|
+
targetGrossMarginBps: number | null;
|
|
246
|
+
missingReason: string | null;
|
|
247
|
+
presetChecks: DedicatedPriceBookPresetCheck[];
|
|
248
|
+
};
|
|
249
|
+
sizeAvailability: Array<{
|
|
250
|
+
id: string;
|
|
251
|
+
offered: boolean;
|
|
252
|
+
withheldReason: string | null;
|
|
253
|
+
}>;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* The Dedicated Runtime price book as an operator reads it: which version and
|
|
257
|
+
* which pricing policy, and each tier's rate, cost and margin. The customer
|
|
258
|
+
* catalog carries none of the policy or cost facts, and the admin plane that
|
|
259
|
+
* also serves this is not deployed in production (OSK-9562).
|
|
260
|
+
*/
|
|
261
|
+
export declare function getDedicatedOperatorPriceBook(): Promise<DedicatedOperatorPriceBook>;
|
|
262
|
+
/** Human lines for `machines dedicated price-book`. Pure, so it can be pinned. */
|
|
263
|
+
export declare function dedicatedOperatorPriceBookLines(read: DedicatedOperatorPriceBook): string[];
|
|
224
264
|
export declare function listDedicatedRuntimes(options?: {
|
|
225
265
|
limit?: number;
|
|
226
266
|
state?: string;
|
|
@@ -389,10 +429,57 @@ export type DedicatedCopyPlan = {
|
|
|
389
429
|
export declare function parseDedicatedCopyEndpoints(source: string, destination: string): DedicatedCopyPlan;
|
|
390
430
|
export declare function dedicatedLeaseId(lease: DedicatedLease | HarnessLease | undefined | null): string;
|
|
391
431
|
export declare function dedicatedLeaseState(lease: DedicatedLease | HarnessLease | undefined | null): string;
|
|
432
|
+
/**
|
|
433
|
+
* What `destroy` should say when it keeps the workspace — or null when it does
|
|
434
|
+
* not.
|
|
435
|
+
*
|
|
436
|
+
* A destroy under retention class standard/extended archives the lease and keeps
|
|
437
|
+
* its workspace volume, which keeps billing storage until it is purged. Nothing
|
|
438
|
+
* said so at the moment it mattered: `destroy` printed the new state and exited,
|
|
439
|
+
* `list` showed `archived` in the same column as `terminated`, and the one way to
|
|
440
|
+
* find out was the bill (OSK-9593).
|
|
441
|
+
*/
|
|
442
|
+
export declare function dedicatedDestroyRetentionNote(priorLease: DedicatedLease | undefined | null, opts: {
|
|
443
|
+
purge: boolean;
|
|
444
|
+
retain: boolean;
|
|
445
|
+
bin: string;
|
|
446
|
+
}): string | null;
|
|
447
|
+
/**
|
|
448
|
+
* Month-to-date Dedicated Runtime spend for the scope a `list` shows.
|
|
449
|
+
*
|
|
450
|
+
* `billing.currentMonthSpendCents` is the SCOPE's spend for the product — the
|
|
451
|
+
* server aggregates by owner scope, not by lease — so every row carried the same
|
|
452
|
+
* figure, and a column headed MONTH/CAP on per-machine rows read as that
|
|
453
|
+
* machine's cost when it was every machine's (OSK-9576). It is said once instead.
|
|
454
|
+
*/
|
|
455
|
+
export declare function dedicatedScopeMonthSpendCents(leases: Array<DedicatedLease | undefined | null>): number | null;
|
|
456
|
+
/**
|
|
457
|
+
* A lease's own cap, marked when the scope's spend has reached it. The mark is
|
|
458
|
+
* left off a terminal lease: its cap can no longer stop anything, and
|
|
459
|
+
* "$11.06/$10.00 OVER" on a machine terminated days ago read as that machine
|
|
460
|
+
* having overrun.
|
|
461
|
+
*/
|
|
462
|
+
export declare function dedicatedLeaseCapCell(lease: DedicatedLease | undefined | null): string;
|
|
463
|
+
/**
|
|
464
|
+
* A lease's STATUS cell. `archived` and `terminated` are both "gone" to read, and
|
|
465
|
+
* only one of them is still charging — so a lease billing retained storage says
|
|
466
|
+
* so (OSK-9593).
|
|
467
|
+
*/
|
|
468
|
+
export declare function dedicatedLeaseStatusCell(lease: DedicatedLease | undefined | null): string;
|
|
392
469
|
export declare function dedicatedLeaseDisplayName(lease: DedicatedLease | HarnessLease | undefined | null): string;
|
|
393
470
|
/** `$12.34` — cents are what the API speaks; dollars are what a person reads. */
|
|
394
471
|
export declare function formatUsdCents(cents: number | null | undefined): string;
|
|
395
|
-
/**
|
|
472
|
+
/**
|
|
473
|
+
* `$1.23 this month for machines of this type · $500.00 cap for this machine`,
|
|
474
|
+
* or why that sentence cannot be written.
|
|
475
|
+
*
|
|
476
|
+
* The two figures are different scopes and the sentence has to say so. The spend
|
|
477
|
+
* is a shared pot the server computes for (owner, team, machineProduct), so every
|
|
478
|
+
* lease of the same product reports the same number — a machine created minutes
|
|
479
|
+
* ago with no active seconds still reports the month's total. The cap is this
|
|
480
|
+
* lease's own. Printed as "$1.23 this month of $500.00 cap" the only available
|
|
481
|
+
* reading was that this machine had spent it.
|
|
482
|
+
*/
|
|
396
483
|
export declare function dedicatedSpendSummary(lease: DedicatedLease): string;
|
|
397
484
|
/**
|
|
398
485
|
* The human rendering of `machines dedicated show`, as lines.
|
|
@@ -461,12 +548,15 @@ interface CatalogSize {
|
|
|
461
548
|
vcpus?: number;
|
|
462
549
|
memoryGiB?: number;
|
|
463
550
|
accelerator?: string;
|
|
551
|
+
rateCentsPerHour?: number | null;
|
|
464
552
|
}
|
|
465
553
|
interface CatalogPriceLine {
|
|
466
554
|
label?: string;
|
|
467
555
|
display?: string;
|
|
468
556
|
amountCents?: number | null;
|
|
469
557
|
cadence?: string;
|
|
558
|
+
/** `charge` is billed, `hold` is reserved at start, `limit` is a cap. Absent means `charge`. */
|
|
559
|
+
kind?: 'charge' | 'hold' | 'limit';
|
|
470
560
|
}
|
|
471
561
|
export interface DedicatedCatalog {
|
|
472
562
|
availability: string;
|
|
@@ -480,9 +570,15 @@ export interface DedicatedCatalog {
|
|
|
480
570
|
};
|
|
481
571
|
retentionClasses: string[];
|
|
482
572
|
backupProfiles: string[];
|
|
573
|
+
/** Server-declared: what create applies when a flag is omitted. */
|
|
574
|
+
defaultSizePreset?: string;
|
|
575
|
+
defaultRetentionClass?: string;
|
|
576
|
+
defaultBackupProfile?: string;
|
|
483
577
|
defaultMonthlySpendingLimitCents?: number | null;
|
|
484
578
|
maxUserMonthlySpendingLimitCents?: number | null;
|
|
485
579
|
priceLines: CatalogPriceLine[];
|
|
580
|
+
/** The price book the quoted prices come from — what a later pricing question cites. */
|
|
581
|
+
priceBookVersion?: string;
|
|
486
582
|
headline?: string;
|
|
487
583
|
}
|
|
488
584
|
/**
|
|
@@ -493,6 +589,44 @@ export interface DedicatedCatalog {
|
|
|
493
589
|
* gated by server flags — so this is where a caller learns which ones exist.
|
|
494
590
|
*/
|
|
495
591
|
export declare function dedicatedCatalogFromProducts(payload: unknown): DedicatedCatalog | null;
|
|
592
|
+
/**
|
|
593
|
+
* The catalog's size rows: spec, the size's own hourly price, and which one
|
|
594
|
+
* `create` uses by default. The rows used to carry spec alone, sorted by name,
|
|
595
|
+
* so the $1.40/hr tier came first with nothing saying what it cost or that
|
|
596
|
+
* $0.65/hr standard was the default; a reader had to join two blocks by name.
|
|
597
|
+
*/
|
|
598
|
+
export declare function dedicatedCatalogSizeLines(catalog: DedicatedCatalog): string[];
|
|
599
|
+
export interface DedicatedCreateChoices {
|
|
600
|
+
name: string;
|
|
601
|
+
sizePreset: string;
|
|
602
|
+
storageGb?: number;
|
|
603
|
+
retentionClass?: string;
|
|
604
|
+
spendingLimitCents?: number;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* What a create is about to buy, in the words and numbers the catalog uses.
|
|
608
|
+
*
|
|
609
|
+
* `create` provisioned a billable machine the moment it ran — no confirmation,
|
|
610
|
+
* no dry run, and every omitted flag silently took a paid default — while
|
|
611
|
+
* `destroy` asked first. A loop probing size validation bought two real
|
|
612
|
+
* machines, one of them $1.40/hr (OSK-9592). This is what `create` now shows
|
|
613
|
+
* before it asks, and what `--dry-run` prints instead of creating.
|
|
614
|
+
*
|
|
615
|
+
* Every default comes from the catalog, never from this file: a CLI that
|
|
616
|
+
* restates a default it does not own is how `--storage-gb` once billed twice the
|
|
617
|
+
* product's disk. A value the catalog does not declare is shown as "server
|
|
618
|
+
* default" rather than guessed.
|
|
619
|
+
*/
|
|
620
|
+
export declare function dedicatedCreateSummary(catalog: DedicatedCatalog | null, choices: DedicatedCreateChoices): string[];
|
|
621
|
+
/**
|
|
622
|
+
* The catalog's money lines, grouped by what each amount IS.
|
|
623
|
+
*
|
|
624
|
+
* A start hold and a monthly cap used to print under "Prices" beside the hourly
|
|
625
|
+
* rates, so starting a machine read as a 33c charge and "$500 default monthly
|
|
626
|
+
* cap" read as a bill (OSK-9536). A line with no `kind` comes from a server that
|
|
627
|
+
* predates it and is shown the way every line used to be: as a charge.
|
|
628
|
+
*/
|
|
629
|
+
export declare function dedicatedCatalogPriceLineOutput(priceLines: CatalogPriceLine[], priceBookVersion?: string): string[];
|
|
496
630
|
/**
|
|
497
631
|
* The product refusal code the server sent (`DEDICATED_RUNTIME_NOT_ASSIGNABLE`,
|
|
498
632
|
* …), for `this.error(message, { code })`. Without it a `--json` caller got the
|
|
@@ -5,6 +5,8 @@ exports.describeDedicatedImageStanding = describeDedicatedImageStanding;
|
|
|
5
5
|
exports.dedicatedRuntimeCreateInput = dedicatedRuntimeCreateInput;
|
|
6
6
|
exports.isDedicatedRepositoryRef = isDedicatedRepositoryRef;
|
|
7
7
|
exports.createDedicatedRuntime = createDedicatedRuntime;
|
|
8
|
+
exports.getDedicatedOperatorPriceBook = getDedicatedOperatorPriceBook;
|
|
9
|
+
exports.dedicatedOperatorPriceBookLines = dedicatedOperatorPriceBookLines;
|
|
8
10
|
exports.listDedicatedRuntimes = listDedicatedRuntimes;
|
|
9
11
|
exports.getDedicatedRuntime = getDedicatedRuntime;
|
|
10
12
|
exports.performDedicatedLeaseAction = performDedicatedLeaseAction;
|
|
@@ -21,6 +23,10 @@ exports.writeDedicatedRuntimeFileChunk = writeDedicatedRuntimeFileChunk;
|
|
|
21
23
|
exports.parseDedicatedCopyEndpoints = parseDedicatedCopyEndpoints;
|
|
22
24
|
exports.dedicatedLeaseId = dedicatedLeaseId;
|
|
23
25
|
exports.dedicatedLeaseState = dedicatedLeaseState;
|
|
26
|
+
exports.dedicatedDestroyRetentionNote = dedicatedDestroyRetentionNote;
|
|
27
|
+
exports.dedicatedScopeMonthSpendCents = dedicatedScopeMonthSpendCents;
|
|
28
|
+
exports.dedicatedLeaseCapCell = dedicatedLeaseCapCell;
|
|
29
|
+
exports.dedicatedLeaseStatusCell = dedicatedLeaseStatusCell;
|
|
24
30
|
exports.dedicatedLeaseDisplayName = dedicatedLeaseDisplayName;
|
|
25
31
|
exports.formatUsdCents = formatUsdCents;
|
|
26
32
|
exports.dedicatedSpendSummary = dedicatedSpendSummary;
|
|
@@ -33,6 +39,9 @@ exports.dedicatedLeaseIdForDaemon = dedicatedLeaseIdForDaemon;
|
|
|
33
39
|
exports.dedicatedTerminalHarness = dedicatedTerminalHarness;
|
|
34
40
|
exports.selectDedicatedAttachHarness = selectDedicatedAttachHarness;
|
|
35
41
|
exports.dedicatedCatalogFromProducts = dedicatedCatalogFromProducts;
|
|
42
|
+
exports.dedicatedCatalogSizeLines = dedicatedCatalogSizeLines;
|
|
43
|
+
exports.dedicatedCreateSummary = dedicatedCreateSummary;
|
|
44
|
+
exports.dedicatedCatalogPriceLineOutput = dedicatedCatalogPriceLineOutput;
|
|
36
45
|
exports.dedicatedRuntimeApiErrorCode = dedicatedRuntimeApiErrorCode;
|
|
37
46
|
exports.dedicatedRuntimeApiErrorDetails = dedicatedRuntimeApiErrorDetails;
|
|
38
47
|
exports.formatDedicatedRuntimeApiError = formatDedicatedRuntimeApiError;
|
|
@@ -150,6 +159,59 @@ async function createDedicatedRuntime(input) {
|
|
|
150
159
|
const { requestId, workspaceId, ...body } = input;
|
|
151
160
|
return (0, api_fetch_1.apiFetch)(withDedicatedScope('/api/machines/dedicated', { workspaceId }), { method: 'POST', body, headers: { 'Idempotency-Key': requestId } });
|
|
152
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* The Dedicated Runtime price book as an operator reads it: which version and
|
|
164
|
+
* which pricing policy, and each tier's rate, cost and margin. The customer
|
|
165
|
+
* catalog carries none of the policy or cost facts, and the admin plane that
|
|
166
|
+
* also serves this is not deployed in production (OSK-9562).
|
|
167
|
+
*/
|
|
168
|
+
async function getDedicatedOperatorPriceBook() {
|
|
169
|
+
return (0, api_fetch_1.apiFetch)('/api/machines/dedicated/price-book');
|
|
170
|
+
}
|
|
171
|
+
function formatBps(bps) {
|
|
172
|
+
return bps === null ? 'unknown' : `${(bps / 100).toFixed(1)}%`;
|
|
173
|
+
}
|
|
174
|
+
function formatRateCents(cents) {
|
|
175
|
+
return cents === null ? 'none' : `$${(cents / 100).toFixed(2)}/hr`;
|
|
176
|
+
}
|
|
177
|
+
/** Human lines for `machines dedicated price-book`. Pure, so it can be pinned. */
|
|
178
|
+
function dedicatedOperatorPriceBookLines(read) {
|
|
179
|
+
const book = read.priceBook;
|
|
180
|
+
const lines = [
|
|
181
|
+
`Dedicated Runtime price book — ${book.approved ? 'approved' : 'NOT approved'}${book.required ? '' : ' (not required here)'}`,
|
|
182
|
+
` version ${book.version ?? 'not recorded'}`,
|
|
183
|
+
` policy ${book.pricingPolicyRef ?? 'not recorded'}`,
|
|
184
|
+
` target margin ${formatBps(book.targetGrossMarginBps)}`,
|
|
185
|
+
];
|
|
186
|
+
if (!book.approved && book.missingReason)
|
|
187
|
+
lines.push(` why ${book.missingReason}`);
|
|
188
|
+
if (read.availability === 'disabled' && read.disabledReason) {
|
|
189
|
+
lines.push(` product disabled: ${read.disabledReason}`);
|
|
190
|
+
}
|
|
191
|
+
if (read.configError)
|
|
192
|
+
lines.push(` config unreadable: ${read.configError}`);
|
|
193
|
+
lines.push('', 'Offered tiers');
|
|
194
|
+
if (book.presetChecks.length === 0)
|
|
195
|
+
lines.push(' none');
|
|
196
|
+
for (const check of book.presetChecks) {
|
|
197
|
+
const verdict = !check.priced
|
|
198
|
+
? 'UNPRICED'
|
|
199
|
+
: !check.providerCostRecorded
|
|
200
|
+
? 'UNCOSTED'
|
|
201
|
+
: check.marginTargetMet
|
|
202
|
+
? 'meets target'
|
|
203
|
+
: 'BELOW TARGET';
|
|
204
|
+
lines.push(` ${check.sizePreset.padEnd(12)} rate ${formatRateCents(check.customerRateCentsPerHour)} · cost ${formatRateCents(check.providerCostCentsPerHour)} · margin ${formatBps(check.grossMarginBps)} · ${verdict}`);
|
|
205
|
+
}
|
|
206
|
+
const withheld = read.sizeAvailability.filter((entry) => !entry.offered);
|
|
207
|
+
if (withheld.length > 0) {
|
|
208
|
+
lines.push('', 'Withheld tiers');
|
|
209
|
+
for (const entry of withheld) {
|
|
210
|
+
lines.push(` ${entry.id.padEnd(12)} ${entry.withheldReason ?? 'no reason recorded'}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return lines;
|
|
214
|
+
}
|
|
153
215
|
async function listDedicatedRuntimes(options = {}) {
|
|
154
216
|
const query = new URLSearchParams();
|
|
155
217
|
if (options.limit)
|
|
@@ -300,6 +362,71 @@ function dedicatedLeaseId(lease) {
|
|
|
300
362
|
function dedicatedLeaseState(lease) {
|
|
301
363
|
return String(lease?.state ?? 'unknown');
|
|
302
364
|
}
|
|
365
|
+
/**
|
|
366
|
+
* What `destroy` should say when it keeps the workspace — or null when it does
|
|
367
|
+
* not.
|
|
368
|
+
*
|
|
369
|
+
* A destroy under retention class standard/extended archives the lease and keeps
|
|
370
|
+
* its workspace volume, which keeps billing storage until it is purged. Nothing
|
|
371
|
+
* said so at the moment it mattered: `destroy` printed the new state and exited,
|
|
372
|
+
* `list` showed `archived` in the same column as `terminated`, and the one way to
|
|
373
|
+
* find out was the bill (OSK-9593).
|
|
374
|
+
*/
|
|
375
|
+
function dedicatedDestroyRetentionNote(priorLease, opts) {
|
|
376
|
+
if (opts.purge || !priorLease)
|
|
377
|
+
return null;
|
|
378
|
+
if (priorLease.state === 'archived')
|
|
379
|
+
return null; // destroying an archived lease purges it
|
|
380
|
+
const retentionClass = String(priorLease.storage?.retentionClass || 'none');
|
|
381
|
+
if (!opts.retain && retentionClass === 'none')
|
|
382
|
+
return null;
|
|
383
|
+
const id = dedicatedLeaseId(priorLease) || '<lease-id>';
|
|
384
|
+
const why = opts.retain ? '--retain-storage' : `retention class ${retentionClass}`;
|
|
385
|
+
return (`The workspace is kept (${why}), and its storage keeps billing until you delete it: ` +
|
|
386
|
+
`${opts.bin} machines dedicated destroy ${id} --purge-storage`);
|
|
387
|
+
}
|
|
388
|
+
const DEDICATED_TERMINAL_STATES = new Set(['terminated', 'failed', 'lost']);
|
|
389
|
+
/**
|
|
390
|
+
* Month-to-date Dedicated Runtime spend for the scope a `list` shows.
|
|
391
|
+
*
|
|
392
|
+
* `billing.currentMonthSpendCents` is the SCOPE's spend for the product — the
|
|
393
|
+
* server aggregates by owner scope, not by lease — so every row carried the same
|
|
394
|
+
* figure, and a column headed MONTH/CAP on per-machine rows read as that
|
|
395
|
+
* machine's cost when it was every machine's (OSK-9576). It is said once instead.
|
|
396
|
+
*/
|
|
397
|
+
function dedicatedScopeMonthSpendCents(leases) {
|
|
398
|
+
for (const lease of leases) {
|
|
399
|
+
const cents = lease?.billing
|
|
400
|
+
?.currentMonthSpendCents;
|
|
401
|
+
if (typeof cents === 'number' && Number.isFinite(cents))
|
|
402
|
+
return cents;
|
|
403
|
+
}
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* A lease's own cap, marked when the scope's spend has reached it. The mark is
|
|
408
|
+
* left off a terminal lease: its cap can no longer stop anything, and
|
|
409
|
+
* "$11.06/$10.00 OVER" on a machine terminated days ago read as that machine
|
|
410
|
+
* having overrun.
|
|
411
|
+
*/
|
|
412
|
+
function dedicatedLeaseCapCell(lease) {
|
|
413
|
+
const billing = lease?.billing;
|
|
414
|
+
if (!billing || typeof billing.monthlySpendLimitCents !== 'number')
|
|
415
|
+
return '-';
|
|
416
|
+
const reached = billing.spendingLimitExceeded && !DEDICATED_TERMINAL_STATES.has(dedicatedLeaseState(lease));
|
|
417
|
+
return `${formatUsdCents(billing.monthlySpendLimitCents)}${reached ? ' · reached' : ''}`;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* A lease's STATUS cell. `archived` and `terminated` are both "gone" to read, and
|
|
421
|
+
* only one of them is still charging — so a lease billing retained storage says
|
|
422
|
+
* so (OSK-9593).
|
|
423
|
+
*/
|
|
424
|
+
function dedicatedLeaseStatusCell(lease) {
|
|
425
|
+
const state = dedicatedLeaseState(lease);
|
|
426
|
+
const billableState = lease?.billing
|
|
427
|
+
?.billableState;
|
|
428
|
+
return billableState === 'storage' ? `${state} · billing storage` : state;
|
|
429
|
+
}
|
|
303
430
|
function dedicatedLeaseDisplayName(lease) {
|
|
304
431
|
return lease?.displayName ? String(lease.displayName) : '-';
|
|
305
432
|
}
|
|
@@ -310,7 +437,17 @@ function formatUsdCents(cents) {
|
|
|
310
437
|
const sign = cents < 0 ? '-' : '';
|
|
311
438
|
return `${sign}$${(Math.abs(cents) / 100).toFixed(2)}`;
|
|
312
439
|
}
|
|
313
|
-
/**
|
|
440
|
+
/**
|
|
441
|
+
* `$1.23 this month for machines of this type · $500.00 cap for this machine`,
|
|
442
|
+
* or why that sentence cannot be written.
|
|
443
|
+
*
|
|
444
|
+
* The two figures are different scopes and the sentence has to say so. The spend
|
|
445
|
+
* is a shared pot the server computes for (owner, team, machineProduct), so every
|
|
446
|
+
* lease of the same product reports the same number — a machine created minutes
|
|
447
|
+
* ago with no active seconds still reports the month's total. The cap is this
|
|
448
|
+
* lease's own. Printed as "$1.23 this month of $500.00 cap" the only available
|
|
449
|
+
* reading was that this machine had spent it.
|
|
450
|
+
*/
|
|
314
451
|
function dedicatedSpendSummary(lease) {
|
|
315
452
|
const billing = lease.billing;
|
|
316
453
|
if (!billing)
|
|
@@ -321,15 +458,33 @@ function dedicatedSpendSummary(lease) {
|
|
|
321
458
|
}
|
|
322
459
|
const spent = billing.currentMonthSpendCents;
|
|
323
460
|
const projected = billing.projectedCurrentMonthSpendCents;
|
|
324
|
-
const parts = [
|
|
461
|
+
const parts = [
|
|
462
|
+
`${formatUsdCents(spent)} this month for machines of this type`,
|
|
463
|
+
`${formatUsdCents(cap)} cap for this machine`,
|
|
464
|
+
];
|
|
325
465
|
if (typeof projected === 'number' && projected !== spent) {
|
|
326
466
|
parts.push(`projected ${formatUsdCents(projected)}`);
|
|
327
467
|
}
|
|
328
468
|
if (billing.spendingLimitExceeded) {
|
|
329
|
-
parts.push(
|
|
469
|
+
parts.push(`OVER CAP — ${overCapComputeClause(lease.state)}, files are kept`);
|
|
330
470
|
}
|
|
331
471
|
return parts.join(' · ');
|
|
332
472
|
}
|
|
473
|
+
/**
|
|
474
|
+
* What the cap has done to compute, in the tense the lease is actually in.
|
|
475
|
+
*
|
|
476
|
+
* This always said "compute is stopped", including for a machine that was still
|
|
477
|
+
* `requested` — which, over its cap, never provisions and cannot have its cap
|
|
478
|
+
* raised until it settles (OSK-9836). The reconciler stops compute for exactly
|
|
479
|
+
* `stopping`, `stopped` and `archived`; anything else is only on its way there.
|
|
480
|
+
*/
|
|
481
|
+
function overCapComputeClause(state) {
|
|
482
|
+
if (state === 'stopped' || state === 'archived')
|
|
483
|
+
return 'compute is stopped';
|
|
484
|
+
if (state === 'stopping')
|
|
485
|
+
return 'compute is stopping';
|
|
486
|
+
return 'compute will be stopped';
|
|
487
|
+
}
|
|
333
488
|
/**
|
|
334
489
|
* The human rendering of `machines dedicated show`, as lines.
|
|
335
490
|
*
|
|
@@ -743,14 +898,128 @@ function dedicatedCatalogFromProducts(payload) {
|
|
|
743
898
|
: {}),
|
|
744
899
|
retentionClasses: configuration.retentionClasses || [],
|
|
745
900
|
backupProfiles: configuration.backupProfiles || [],
|
|
901
|
+
...(typeof configuration.defaultSizePreset === 'string'
|
|
902
|
+
? { defaultSizePreset: configuration.defaultSizePreset }
|
|
903
|
+
: {}),
|
|
904
|
+
...(typeof configuration.defaultRetentionClass === 'string'
|
|
905
|
+
? { defaultRetentionClass: configuration.defaultRetentionClass }
|
|
906
|
+
: {}),
|
|
907
|
+
...(typeof configuration.defaultBackupProfile === 'string'
|
|
908
|
+
? { defaultBackupProfile: configuration.defaultBackupProfile }
|
|
909
|
+
: {}),
|
|
746
910
|
defaultMonthlySpendingLimitCents: billing.defaultMonthlySpendingLimitCents,
|
|
747
911
|
maxUserMonthlySpendingLimitCents: billing.maxUserMonthlySpendingLimitCents,
|
|
748
912
|
priceLines: Array.isArray(presentation.priceLines)
|
|
749
913
|
? presentation.priceLines
|
|
750
914
|
: [],
|
|
915
|
+
...(typeof billing.priceBook?.version === 'string'
|
|
916
|
+
? { priceBookVersion: billing.priceBook.version }
|
|
917
|
+
: {}),
|
|
751
918
|
...(typeof presentation.headline === 'string' ? { headline: presentation.headline } : {}),
|
|
752
919
|
};
|
|
753
920
|
}
|
|
921
|
+
/**
|
|
922
|
+
* The catalog's size rows: spec, the size's own hourly price, and which one
|
|
923
|
+
* `create` uses by default. The rows used to carry spec alone, sorted by name,
|
|
924
|
+
* so the $1.40/hr tier came first with nothing saying what it cost or that
|
|
925
|
+
* $0.65/hr standard was the default; a reader had to join two blocks by name.
|
|
926
|
+
*/
|
|
927
|
+
function dedicatedCatalogSizeLines(catalog) {
|
|
928
|
+
return catalog.sizes.map((size) => {
|
|
929
|
+
const spec = [
|
|
930
|
+
size.vcpus ? `${size.vcpus} vCPU` : '',
|
|
931
|
+
size.memoryGiB ? `${size.memoryGiB} GiB RAM` : '',
|
|
932
|
+
size.accelerator || '',
|
|
933
|
+
typeof size.rateCentsPerHour === 'number' && size.rateCentsPerHour > 0
|
|
934
|
+
? `${formatUsdCents(size.rateCentsPerHour)}/hr`
|
|
935
|
+
: '',
|
|
936
|
+
]
|
|
937
|
+
.filter(Boolean)
|
|
938
|
+
.join(' · ');
|
|
939
|
+
const isDefault = size.id !== undefined && size.id === catalog.defaultSizePreset;
|
|
940
|
+
return ` ${String(size.id).padEnd(14)}${spec}${isDefault ? ' (default)' : ''}`;
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* What a create is about to buy, in the words and numbers the catalog uses.
|
|
945
|
+
*
|
|
946
|
+
* `create` provisioned a billable machine the moment it ran — no confirmation,
|
|
947
|
+
* no dry run, and every omitted flag silently took a paid default — while
|
|
948
|
+
* `destroy` asked first. A loop probing size validation bought two real
|
|
949
|
+
* machines, one of them $1.40/hr (OSK-9592). This is what `create` now shows
|
|
950
|
+
* before it asks, and what `--dry-run` prints instead of creating.
|
|
951
|
+
*
|
|
952
|
+
* Every default comes from the catalog, never from this file: a CLI that
|
|
953
|
+
* restates a default it does not own is how `--storage-gb` once billed twice the
|
|
954
|
+
* product's disk. A value the catalog does not declare is shown as "server
|
|
955
|
+
* default" rather than guessed.
|
|
956
|
+
*/
|
|
957
|
+
function dedicatedCreateSummary(catalog, choices) {
|
|
958
|
+
const size = catalog?.sizes.find((entry) => entry.id === choices.sizePreset);
|
|
959
|
+
const spec = size
|
|
960
|
+
? [
|
|
961
|
+
size.vcpus ? `${size.vcpus} vCPU` : '',
|
|
962
|
+
size.memoryGiB ? `${size.memoryGiB} GiB RAM` : '',
|
|
963
|
+
typeof size.rateCentsPerHour === 'number' && size.rateCentsPerHour > 0
|
|
964
|
+
? `${formatUsdCents(size.rateCentsPerHour)} per running hour`
|
|
965
|
+
: '',
|
|
966
|
+
]
|
|
967
|
+
.filter(Boolean)
|
|
968
|
+
.join(' · ')
|
|
969
|
+
: 'not in the catalog this server offers';
|
|
970
|
+
const storagePrice = catalog?.priceLines.find((line) => line.cadence === 'per-gb-month');
|
|
971
|
+
const storageGb = choices.storageGb ?? catalog?.storage?.defaultGb;
|
|
972
|
+
const storage = storageGb !== undefined
|
|
973
|
+
? `${storageGb} GiB${choices.storageGb === undefined ? ' (catalog default)' : ''}`
|
|
974
|
+
: 'server default';
|
|
975
|
+
const retentionClass = choices.retentionClass ?? catalog?.defaultRetentionClass;
|
|
976
|
+
const retention = retentionClass
|
|
977
|
+
? `${retentionClass}${choices.retentionClass === undefined ? ' (catalog default)' : ''}`
|
|
978
|
+
: 'server default';
|
|
979
|
+
const retains = retentionClass !== undefined && retentionClass !== 'none';
|
|
980
|
+
const capCents = choices.spendingLimitCents ?? catalog?.defaultMonthlySpendingLimitCents;
|
|
981
|
+
const cap = capCents !== undefined && capCents !== null
|
|
982
|
+
? `${formatUsdCents(capCents)} per month${choices.spendingLimitCents === undefined ? ' (catalog default)' : ''}`
|
|
983
|
+
: 'server default';
|
|
984
|
+
return [
|
|
985
|
+
`Create Dedicated Runtime "${choices.name}" — it bills while it runs:`,
|
|
986
|
+
` size ${choices.sizePreset} — ${spec}`,
|
|
987
|
+
` storage ${storage}${storagePrice?.display ? ` — ${storagePrice.display}` : ''}`,
|
|
988
|
+
` retention ${retention}${retains ? ' — destroy keeps the workspace, and its storage bills until you purge it' : ''}`,
|
|
989
|
+
` monthly cap ${cap}`,
|
|
990
|
+
];
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* The catalog's money lines, grouped by what each amount IS.
|
|
994
|
+
*
|
|
995
|
+
* A start hold and a monthly cap used to print under "Prices" beside the hourly
|
|
996
|
+
* rates, so starting a machine read as a 33c charge and "$500 default monthly
|
|
997
|
+
* cap" read as a bill (OSK-9536). A line with no `kind` comes from a server that
|
|
998
|
+
* predates it and is shown the way every line used to be: as a charge.
|
|
999
|
+
*/
|
|
1000
|
+
function dedicatedCatalogPriceLineOutput(priceLines, priceBookVersion) {
|
|
1001
|
+
// The version is what a charge dispute later cites; it was in the payload and
|
|
1002
|
+
// the command dropped it (OSK-9562).
|
|
1003
|
+
const pricesHeading = priceBookVersion ? `Prices (price book ${priceBookVersion})` : 'Prices';
|
|
1004
|
+
const groups = [
|
|
1005
|
+
{ kind: 'charge', heading: pricesHeading },
|
|
1006
|
+
{ kind: 'hold', heading: 'Held against your cap at start (not billed)' },
|
|
1007
|
+
{ kind: 'limit', heading: 'Monthly caps (--spending-limit-cents)' },
|
|
1008
|
+
];
|
|
1009
|
+
if (priceLines.length === 0)
|
|
1010
|
+
return ['', pricesHeading, ' not published by this server'];
|
|
1011
|
+
const output = [];
|
|
1012
|
+
for (const group of groups) {
|
|
1013
|
+
const lines = priceLines.filter((line) => (line.kind || 'charge') === group.kind);
|
|
1014
|
+
if (lines.length === 0)
|
|
1015
|
+
continue;
|
|
1016
|
+
output.push('', group.heading);
|
|
1017
|
+
for (const line of lines) {
|
|
1018
|
+
output.push(` ${line.display || `${formatUsdCents(line.amountCents)} ${line.label || ''}`}`);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
return output;
|
|
1022
|
+
}
|
|
754
1023
|
/**
|
|
755
1024
|
* Dedicated Runtime commands are unusually likely to meet a server that has
|
|
756
1025
|
* never heard of them.
|
|
@@ -867,9 +1136,44 @@ function dedicatedRuntimeApiErrorDetails(err) {
|
|
|
867
1136
|
*/
|
|
868
1137
|
function describeRefusalReasons(err) {
|
|
869
1138
|
const details = dedicatedRuntimeApiErrorDetails(err);
|
|
1139
|
+
const spend = describeSpendingCapRefusal(err.body, details);
|
|
1140
|
+
if (spend)
|
|
1141
|
+
return spend;
|
|
870
1142
|
const sentences = (0, harnesses_1.describeHealthReasonSentences)(details?.reasons, details?.state);
|
|
871
1143
|
return sentences ? ` Reasons: ${sentences}` : '';
|
|
872
1144
|
}
|
|
1145
|
+
/**
|
|
1146
|
+
* The numbers behind a cap refusal: the cap, this month's spend so far, and
|
|
1147
|
+
* where the refused action would have taken it — plus the command that raises
|
|
1148
|
+
* the cap. Without them "would exceed the monthly cap" left a user guessing by
|
|
1149
|
+
* how much, and which cap (OSK-9552).
|
|
1150
|
+
*/
|
|
1151
|
+
function describeSpendingCapRefusal(body, details) {
|
|
1152
|
+
let code;
|
|
1153
|
+
try {
|
|
1154
|
+
code = JSON.parse(body || '{}').code;
|
|
1155
|
+
}
|
|
1156
|
+
catch {
|
|
1157
|
+
return '';
|
|
1158
|
+
}
|
|
1159
|
+
if (code !== 'RUNTIME_SPENDING_LIMIT_EXCEEDED' || !details)
|
|
1160
|
+
return '';
|
|
1161
|
+
const cents = (key) => {
|
|
1162
|
+
const value = details[key];
|
|
1163
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
1164
|
+
};
|
|
1165
|
+
const limit = cents('limitCents');
|
|
1166
|
+
const spent = cents('currentSpendCents');
|
|
1167
|
+
const projected = cents('projectedCents');
|
|
1168
|
+
const parts = [
|
|
1169
|
+
limit !== null ? `Cap ${formatUsdCents(limit)}` : '',
|
|
1170
|
+
spent !== null ? `spent this month ${formatUsdCents(spent)}` : '',
|
|
1171
|
+
projected !== null ? `this would bring it to ${formatUsdCents(projected)}` : '',
|
|
1172
|
+
].filter(Boolean);
|
|
1173
|
+
if (parts.length === 0)
|
|
1174
|
+
return '';
|
|
1175
|
+
return ` ${parts.join('; ')}. Raise the cap with \`machines dedicated spending-limit <lease-id> --cents <n>\`.`;
|
|
1176
|
+
}
|
|
873
1177
|
function formatDedicatedRuntimeApiError(err) {
|
|
874
1178
|
if (!(err instanceof api_fetch_1.ApiFetchError) || !err.body) {
|
|
875
1179
|
return null;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isFailedLookupValue = isFailedLookupValue;
|
|
4
|
+
exports.describeFailedLookupValue = describeFailedLookupValue;
|
|
5
|
+
/**
|
|
6
|
+
* Values a script produces when a lookup upstream has ALREADY failed.
|
|
7
|
+
*
|
|
8
|
+
* `jq -r .id` on a missing field prints `null`. A JavaScript value that was
|
|
9
|
+
* never set stringifies to `undefined`; an object to `[object Object]`. Python
|
|
10
|
+
* prints `None`, Ruby `nil`, and a boolean field read as an id gives `true` or
|
|
11
|
+
* `false`. No person types any of these as a reference to a Task, a Space or a
|
|
12
|
+
* member — and a script passes one exactly when its previous step went wrong.
|
|
13
|
+
*
|
|
14
|
+
* The reference resolvers are generous by design: a person can type part of a
|
|
15
|
+
* title, and when exactly one title contains it, that is the one they meant.
|
|
16
|
+
* The same generosity turned `tasks complete "$ID"` with `ID=null` into
|
|
17
|
+
* "complete whichever single task mentions null". So these are refused before
|
|
18
|
+
* any search runs. Matching is on the WHOLE trimmed value, case-insensitively:
|
|
19
|
+
* a real title that merely contains one of these words still resolves.
|
|
20
|
+
*/
|
|
21
|
+
const FAILED_LOOKUP_VALUES = new Set([
|
|
22
|
+
'null',
|
|
23
|
+
'undefined',
|
|
24
|
+
'none',
|
|
25
|
+
'nil',
|
|
26
|
+
'nan',
|
|
27
|
+
'true',
|
|
28
|
+
'false',
|
|
29
|
+
'[object object]',
|
|
30
|
+
]);
|
|
31
|
+
function isFailedLookupValue(value) {
|
|
32
|
+
return typeof value === 'string' && FAILED_LOOKUP_VALUES.has(value.trim().toLowerCase());
|
|
33
|
+
}
|
|
34
|
+
/** The shared explanation, so every resolver refuses in the same words. */
|
|
35
|
+
function describeFailedLookupValue(value, noun) {
|
|
36
|
+
return (`"${value.trim()}" is not a ${noun} reference — it is what a failed lookup prints ` +
|
|
37
|
+
'(for example `jq -r` on a missing field, or an unset variable). Refusing to search ' +
|
|
38
|
+
'names for it, because a single accidental match would be acted on.\n' +
|
|
39
|
+
' → check the step that produced this value; it most likely failed.');
|
|
40
|
+
}
|
|
@@ -242,10 +242,17 @@ async function resolveFirstPartyHarnessAgent(explicit, deps = {}, options = {})
|
|
|
242
242
|
// Asked, not told: the caller opted out of creation, so "no default" is a fact
|
|
243
243
|
// about this machine rather than a failure, and the remedy is a real command.
|
|
244
244
|
if (options.createDefault === false) {
|
|
245
|
-
throw new FirstPartyHarnessAgentError('agent-unset',
|
|
245
|
+
throw new FirstPartyHarnessAgentError('agent-unset',
|
|
246
|
+
// No roster here. The question was which agent a session runs as, and a
|
|
247
|
+
// hundred names in front of the one sentence that answers it buried the
|
|
248
|
+
// answer (OSK-9396). A person choosing one has `agents list` for that.
|
|
249
|
+
`nothing is configured and you have no ${auth_core_1.FIRST_PARTY_HARNESS.displayName} default agent yet. ` +
|
|
246
250
|
'One is created automatically the first time you run a managed session — ' +
|
|
247
251
|
`or make it now with \`${auth_core_1.FIRST_PARTY_HARNESS.command} skrr-agent --create\`` +
|
|
248
|
-
(rows.length
|
|
252
|
+
(rows.length
|
|
253
|
+
? `, or pick one of your ${rows.length} with ` +
|
|
254
|
+
`\`${auth_core_1.FIRST_PARTY_HARNESS.command} skrr-agent --set <id-or-name>\` (see \`skrr agents list\`)`
|
|
255
|
+
: ''));
|
|
249
256
|
}
|
|
250
257
|
// The endpoint answered without an agent. Nothing here can repair that, but
|
|
251
258
|
// the user still has every ordinary way to name one.
|
|
@@ -35,6 +35,21 @@ export interface DoctorCheck {
|
|
|
35
35
|
detail: string;
|
|
36
36
|
/** What to do about it. Only present when there is something to do. */
|
|
37
37
|
remedy?: string;
|
|
38
|
+
/** The files and directories a check looked at, for `--json` consumers. */
|
|
39
|
+
sources?: DoctorSource[];
|
|
40
|
+
}
|
|
41
|
+
/** One place the engine reads instructions or skills from. */
|
|
42
|
+
export interface DoctorSource {
|
|
43
|
+
/** As a person would type it: relative for the project, `~/` for the user. */
|
|
44
|
+
path: string;
|
|
45
|
+
kind: 'instructions' | 'skills';
|
|
46
|
+
owner: 'engine' | 'compatibility';
|
|
47
|
+
scope: 'project' | 'user';
|
|
48
|
+
present: boolean;
|
|
49
|
+
/** Skill directories holding a SKILL.md; only for a present skill root. */
|
|
50
|
+
skills?: number;
|
|
51
|
+
/** Why the engine will not read it although it exists, when it will not. */
|
|
52
|
+
disabled?: string;
|
|
38
53
|
}
|
|
39
54
|
export interface DoctorReport {
|
|
40
55
|
checks: DoctorCheck[];
|