@skrr-ai/cli 0.1.38 → 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 +8 -0
- package/dist/commands/machines/dedicated/create.js +6 -2
- package/dist/commands/machines/dedicated/destroy.js +10 -10
- package/dist/commands/machines/dedicated/exec.js +3 -1
- package/dist/commands/machines/dedicated/price-book.d.ts +17 -0
- package/dist/commands/machines/dedicated/price-book.js +35 -0
- package/dist/lib/dedicated-lease-command.d.ts +3 -1
- package/dist/lib/dedicated-lease-command.js +4 -2
- package/dist/lib/dedicated-machines.d.ts +40 -0
- package/dist/lib/dedicated-machines.js +71 -1
- package/oclif.manifest.json +18725 -18666
- package/package.json +1 -1
package/bin/dev-fallback.js
CHANGED
|
@@ -245,6 +245,14 @@ function findAlternateCli({
|
|
|
245
245
|
function missingLocalCommandBuild({ cliRoot, argv, fileSystem = fs, verifySourceIdentity = true }) {
|
|
246
246
|
const commandsDirectory = path.join(cliRoot, 'dist', 'commands');
|
|
247
247
|
const sourceCommandsDirectory = path.join(cliRoot, 'src', 'commands');
|
|
248
|
+
// Staleness is a relation between a build and its SOURCE, so a CLI without
|
|
249
|
+
// source — every installed npm package, which ships `dist` and no `src` — has
|
|
250
|
+
// nothing to be stale against. Every check below is a development-checkout
|
|
251
|
+
// guard. Only the per-command one happened to notice: it looks a source file
|
|
252
|
+
// up first. The `--version` branch did not, read the missing source-digest
|
|
253
|
+
// manifest as a missing build, and made an installed 0.1.38 report whatever
|
|
254
|
+
// other `skrr` was on the PATH, or fail (OSK-9883).
|
|
255
|
+
if (!fileSystem.existsSync(sourceCommandsDirectory)) return null;
|
|
248
256
|
let commandBuildManifest;
|
|
249
257
|
try {
|
|
250
258
|
commandBuildManifest = JSON.parse(
|
|
@@ -72,11 +72,15 @@ class DedicatedMachinesCreate extends dedicated_lease_command_1.DedicatedLeaseCo
|
|
|
72
72
|
if (flags.repository !== undefined && !(0, dedicated_machines_1.isDedicatedRepositoryRef)(flags.repository)) {
|
|
73
73
|
this.error(`--repository must look like owner/repo, got "${flags.repository}".`, { exit: 2 });
|
|
74
74
|
}
|
|
75
|
+
// The server trims the preset, so ' standard' buys a standard machine; the
|
|
76
|
+
// preview must judge the same value, or it calls a size it is about to buy
|
|
77
|
+
// "not in the catalog" and then buys it anyway (OSK-9592).
|
|
78
|
+
const sizePreset = flags['size-preset'].trim();
|
|
75
79
|
const requestId = flags['request-id'] || newRequestId();
|
|
76
80
|
const body = (0, dedicated_machines_1.dedicatedRuntimeCreateInput)({
|
|
77
81
|
requestId,
|
|
78
82
|
displayName: flags.name,
|
|
79
|
-
sizePreset
|
|
83
|
+
sizePreset,
|
|
80
84
|
monthlySpendingLimitCents: flags['spending-limit-cents'],
|
|
81
85
|
regionClass: flags['region-class'],
|
|
82
86
|
storageGb: flags['storage-gb'],
|
|
@@ -93,7 +97,7 @@ class DedicatedMachinesCreate extends dedicated_lease_command_1.DedicatedLeaseCo
|
|
|
93
97
|
const catalog = await this.readCatalogForSummary();
|
|
94
98
|
const summary = (0, dedicated_machines_1.dedicatedCreateSummary)(catalog, {
|
|
95
99
|
name: flags.name,
|
|
96
|
-
sizePreset
|
|
100
|
+
sizePreset,
|
|
97
101
|
storageGb: flags['storage-gb'],
|
|
98
102
|
retentionClass: flags['retention-class'],
|
|
99
103
|
spendingLimitCents: flags['spending-limit-cents'],
|
|
@@ -73,16 +73,16 @@ class DedicatedMachinesDestroy extends dedicated_lease_command_1.DedicatedLeaseC
|
|
|
73
73
|
else if (flags['retain-storage'])
|
|
74
74
|
retentionIntent = 'retain';
|
|
75
75
|
const response = await this.callDedicated(() => (0, dedicated_machines_1.destroyDedicatedRuntime)(leaseId, { ...this.scopeFrom(flags), retentionIntent }));
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
const note = (0, dedicated_machines_1.dedicatedDestroyRetentionNote)(prior, {
|
|
77
|
+
purge: Boolean(flags['purge-storage']),
|
|
78
|
+
retain: Boolean(flags['retain-storage']),
|
|
79
|
+
bin: this.config.bin,
|
|
80
|
+
});
|
|
81
|
+
// A script reading --json is exactly the caller that never sees a printed
|
|
82
|
+
// line, so the kept-and-billing fact rides in the document too (OSK-9593).
|
|
83
|
+
await this.reportLeaseAction(response, flags, { kind: 'destroyed' }, 'Destroying', note ? { storageNote: note } : {});
|
|
84
|
+
if (!flags.json && note)
|
|
85
|
+
this.log(note);
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
exports.default = DedicatedMachinesDestroy;
|
|
@@ -55,6 +55,8 @@ class DedicatedMachinesExec extends base_command_1.BaseCommand {
|
|
|
55
55
|
// What a script depends on, in the help a script author reads (OSK-8703).
|
|
56
56
|
static description = [
|
|
57
57
|
'Runs the command once, as the workload user, in /workspace or --cwd, through a shell with no TTY. ' +
|
|
58
|
+
'The workload user can read /workspace but writes only under user-data/ (its HOME) and repos/, so a ' +
|
|
59
|
+
'command that writes to its starting directory needs --cwd user-data or a path under one of those. ' +
|
|
58
60
|
'Give it after -- as words (each one quoted for you), or as one shell string with --command; not both. ' +
|
|
59
61
|
'The agent shell policy does not apply. A start whose answer is lost is followed up under the same ' +
|
|
60
62
|
'request id, never run a second time.',
|
|
@@ -95,7 +97,7 @@ class DedicatedMachinesExec extends base_command_1.BaseCommand {
|
|
|
95
97
|
description: 'Command to run as one shell string, instead of the words after --',
|
|
96
98
|
}),
|
|
97
99
|
cwd: core_1.Flags.string({
|
|
98
|
-
description: 'Working directory, relative to /workspace (for example repos/app)',
|
|
100
|
+
description: 'Working directory, relative to /workspace (for example repos/app or user-data). /workspace itself is not writable by the workload user.',
|
|
99
101
|
}),
|
|
100
102
|
timeout: core_1.Flags.string({
|
|
101
103
|
description: `How long to let it run, such as 30s or 5m (default 2m, max ${dedicated_machines_1.DEDICATED_EXEC_MAX_TIMEOUT_MS / 60000}m). The process group is killed at the deadline.`,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DedicatedLeaseCommand } from '../../../lib/dedicated-lease-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr machines dedicated price-book` — the operator's answer to "under what
|
|
4
|
+
* policy, and at what margin, is each tier sold".
|
|
5
|
+
*
|
|
6
|
+
* `catalog` is the customer view: prices and the book version, never a cost or
|
|
7
|
+
* a policy. This is admin-only on the server, because costs and margins are not
|
|
8
|
+
* customer facts.
|
|
9
|
+
*/
|
|
10
|
+
export default class DedicatedMachinesPriceBook extends DedicatedLeaseCommand {
|
|
11
|
+
static description: string;
|
|
12
|
+
static examples: string[];
|
|
13
|
+
static flags: {
|
|
14
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
};
|
|
16
|
+
run(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const dedicated_lease_command_1 = require("../../../lib/dedicated-lease-command");
|
|
5
|
+
const dedicated_machines_1 = require("../../../lib/dedicated-machines");
|
|
6
|
+
/**
|
|
7
|
+
* `skrr machines dedicated price-book` — the operator's answer to "under what
|
|
8
|
+
* policy, and at what margin, is each tier sold".
|
|
9
|
+
*
|
|
10
|
+
* `catalog` is the customer view: prices and the book version, never a cost or
|
|
11
|
+
* a policy. This is admin-only on the server, because costs and margins are not
|
|
12
|
+
* customer facts.
|
|
13
|
+
*/
|
|
14
|
+
class DedicatedMachinesPriceBook extends dedicated_lease_command_1.DedicatedLeaseCommand {
|
|
15
|
+
static description = 'Show the Dedicated Runtime price book an operator audits: version, pricing policy, and each tier rate, cost and margin (admin only)';
|
|
16
|
+
static examples = [
|
|
17
|
+
'<%= config.bin %> machines dedicated price-book',
|
|
18
|
+
'<%= config.bin %> machines dedicated price-book --json',
|
|
19
|
+
];
|
|
20
|
+
static flags = {
|
|
21
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
22
|
+
};
|
|
23
|
+
async run() {
|
|
24
|
+
this.requireAuth();
|
|
25
|
+
const { flags } = await this.parse(DedicatedMachinesPriceBook);
|
|
26
|
+
const read = await this.callDedicated(() => (0, dedicated_machines_1.getDedicatedOperatorPriceBook)());
|
|
27
|
+
if (flags.json) {
|
|
28
|
+
this.log(JSON.stringify(read, null, 2));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
for (const line of (0, dedicated_machines_1.dedicatedOperatorPriceBookLines)(read))
|
|
32
|
+
this.log(line);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.default = DedicatedMachinesPriceBook;
|
|
@@ -61,7 +61,9 @@ export declare abstract class DedicatedLeaseCommand extends BaseCommand {
|
|
|
61
61
|
timeout?: string;
|
|
62
62
|
interval?: number;
|
|
63
63
|
workspace?: string;
|
|
64
|
-
}, goal: DedicatedWaitGoal | null, verb: string
|
|
64
|
+
}, goal: DedicatedWaitGoal | null, verb: string,
|
|
65
|
+
/** Fields a `--json` caller needs that the server response does not carry. */
|
|
66
|
+
jsonExtra?: Record<string, unknown>): Promise<void>;
|
|
65
67
|
}
|
|
66
68
|
/** The same transient verdict BaseCommand gives an ordinary API call. */
|
|
67
69
|
export declare function dedicatedRuntimeApiErrorRetryable(err: unknown): boolean;
|
|
@@ -145,7 +145,9 @@ class DedicatedLeaseCommand extends base_command_1.BaseCommand {
|
|
|
145
145
|
* Print the lease an action returned, or wait for its operation to finish
|
|
146
146
|
* first when `--wait` was passed.
|
|
147
147
|
*/
|
|
148
|
-
async reportLeaseAction(response, flags, goal, verb
|
|
148
|
+
async reportLeaseAction(response, flags, goal, verb,
|
|
149
|
+
/** Fields a `--json` caller needs that the server response does not carry. */
|
|
150
|
+
jsonExtra = {}) {
|
|
149
151
|
let lease = response?.lease;
|
|
150
152
|
const id = (0, dedicated_machines_1.dedicatedLeaseId)(lease);
|
|
151
153
|
if (flags.wait && goal && id) {
|
|
@@ -201,7 +203,7 @@ class DedicatedLeaseCommand extends base_command_1.BaseCommand {
|
|
|
201
203
|
}
|
|
202
204
|
}
|
|
203
205
|
if (flags.json) {
|
|
204
|
-
this.log(JSON.stringify({ ...(response || {}), lease }, null, 2));
|
|
206
|
+
this.log(JSON.stringify({ ...(response || {}), lease, ...jsonExtra }, null, 2));
|
|
205
207
|
return;
|
|
206
208
|
}
|
|
207
209
|
this.log(`Dedicated Runtime ${id || 'unknown'} ${(0, dedicated_machines_1.dedicatedLeaseState)(lease)}.`);
|
|
@@ -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;
|
|
@@ -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;
|
|
@@ -157,6 +159,59 @@ async function createDedicatedRuntime(input) {
|
|
|
157
159
|
const { requestId, workspaceId, ...body } = input;
|
|
158
160
|
return (0, api_fetch_1.apiFetch)(withDedicatedScope('/api/machines/dedicated', { workspaceId }), { method: 'POST', body, headers: { 'Idempotency-Key': requestId } });
|
|
159
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
|
+
}
|
|
160
215
|
async function listDedicatedRuntimes(options = {}) {
|
|
161
216
|
const query = new URLSearchParams();
|
|
162
217
|
if (options.limit)
|
|
@@ -411,10 +466,25 @@ function dedicatedSpendSummary(lease) {
|
|
|
411
466
|
parts.push(`projected ${formatUsdCents(projected)}`);
|
|
412
467
|
}
|
|
413
468
|
if (billing.spendingLimitExceeded) {
|
|
414
|
-
parts.push(
|
|
469
|
+
parts.push(`OVER CAP — ${overCapComputeClause(lease.state)}, files are kept`);
|
|
415
470
|
}
|
|
416
471
|
return parts.join(' · ');
|
|
417
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
|
+
}
|
|
418
488
|
/**
|
|
419
489
|
* The human rendering of `machines dedicated show`, as lines.
|
|
420
490
|
*
|