@skrr-ai/cli 0.1.25 → 0.1.27
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/dist/base-command.js +29 -5
- package/dist/commands/code/install.js +13 -0
- package/dist/commands/harnesses/leases/billing.d.ts +9 -6
- package/dist/commands/harnesses/leases/billing.js +19 -24
- package/dist/commands/machines/dedicated/attach.d.ts +28 -0
- package/dist/commands/machines/dedicated/attach.js +76 -0
- package/dist/commands/machines/dedicated/catalog.d.ts +17 -0
- package/dist/commands/machines/dedicated/catalog.js +75 -0
- package/dist/commands/machines/dedicated/cp.d.ts +22 -0
- package/dist/commands/machines/dedicated/cp.js +76 -0
- package/dist/commands/machines/dedicated/create.d.ts +6 -2
- package/dist/commands/machines/dedicated/create.js +29 -20
- package/dist/commands/machines/dedicated/current.d.ts +19 -0
- package/dist/commands/machines/dedicated/current.js +49 -0
- package/dist/commands/machines/dedicated/destroy.d.ts +6 -2
- package/dist/commands/machines/dedicated/destroy.js +43 -25
- package/dist/commands/machines/dedicated/exec.d.ts +32 -0
- package/dist/commands/machines/dedicated/exec.js +122 -0
- package/dist/commands/machines/dedicated/grow.d.ts +6 -2
- package/dist/commands/machines/dedicated/grow.js +16 -20
- package/dist/commands/machines/dedicated/health-check.d.ts +2 -2
- package/dist/commands/machines/dedicated/health-check.js +18 -15
- package/dist/commands/machines/dedicated/incident-close.d.ts +3 -2
- package/dist/commands/machines/dedicated/incident-close.js +13 -15
- package/dist/commands/machines/dedicated/index.js +39 -16
- package/dist/commands/machines/dedicated/list.d.ts +2 -2
- package/dist/commands/machines/dedicated/list.js +28 -17
- package/dist/commands/machines/dedicated/restart.d.ts +5 -2
- package/dist/commands/machines/dedicated/restart.js +10 -20
- package/dist/commands/machines/dedicated/restore.d.ts +26 -0
- package/dist/commands/machines/dedicated/restore.js +64 -0
- package/dist/commands/machines/dedicated/show.d.ts +2 -2
- package/dist/commands/machines/dedicated/show.js +30 -31
- package/dist/commands/machines/dedicated/sign-in.d.ts +19 -0
- package/dist/commands/machines/dedicated/sign-in.js +49 -0
- package/dist/commands/machines/dedicated/snapshot.d.ts +5 -2
- package/dist/commands/machines/dedicated/snapshot.js +13 -20
- package/dist/commands/machines/dedicated/spending-limit.d.ts +22 -0
- package/dist/commands/machines/dedicated/spending-limit.js +51 -0
- package/dist/commands/machines/dedicated/start.d.ts +5 -2
- package/dist/commands/machines/dedicated/start.js +10 -20
- package/dist/commands/machines/dedicated/stop.d.ts +5 -2
- package/dist/commands/machines/dedicated/stop.js +10 -20
- package/dist/commands/machines/dedicated/terminal.d.ts +22 -0
- package/dist/commands/machines/dedicated/terminal.js +42 -0
- package/dist/commands/tasks/list.js +27 -0
- package/dist/lib/daemonBroker.d.ts +8 -0
- package/dist/lib/daemonBroker.js +2 -2
- package/dist/lib/dedicated-copy.d.ts +22 -0
- package/dist/lib/dedicated-copy.js +115 -0
- package/dist/lib/dedicated-exec.d.ts +80 -0
- package/dist/lib/dedicated-exec.js +271 -0
- package/dist/lib/dedicated-lease-command.d.ts +59 -0
- package/dist/lib/dedicated-lease-command.js +181 -0
- package/dist/lib/dedicated-machines.d.ts +337 -12
- package/dist/lib/dedicated-machines.js +502 -25
- package/dist/lib/dedicated-terminal.d.ts +89 -0
- package/dist/lib/dedicated-terminal.js +275 -0
- package/dist/lib/dedicated-wait.d.ts +72 -0
- package/dist/lib/dedicated-wait.js +195 -0
- package/dist/lib/edge-error-page.d.ts +49 -0
- package/dist/lib/edge-error-page.js +120 -0
- package/dist/lib/harnesses.d.ts +15 -1
- package/dist/lib/harnesses.js +20 -2
- package/dist/lib/hosted-machines.js +7 -0
- package/dist/lib/node-adapter.js +1 -1
- package/dist/lib/sky-code.d.ts +30 -1
- package/dist/lib/sky-code.js +44 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +2 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.d.ts +10 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.js +17 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.d.ts +10 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.js +16 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +2625 -2608
- package/oclif.manifest.json +27851 -26936
- package/package.json +1 -1
package/dist/base-command.js
CHANGED
|
@@ -38,6 +38,7 @@ const refresh_1 = require("./lib/refresh");
|
|
|
38
38
|
const auth_storage_1 = require("./lib/auth-storage");
|
|
39
39
|
const update_check_1 = require("./lib/update-check");
|
|
40
40
|
const web_url_1 = require("./lib/web-url");
|
|
41
|
+
const edge_error_page_1 = require("./lib/edge-error-page");
|
|
41
42
|
const delegated_cli_1 = require("./lib/delegated-cli");
|
|
42
43
|
const tasks_1 = require("./lib/tasks");
|
|
43
44
|
function assigneePayloadNeedsResolution(payload) {
|
|
@@ -284,11 +285,10 @@ class BaseCommand extends core_1.Command {
|
|
|
284
285
|
const accessToken = autoResult.outcome.accessToken;
|
|
285
286
|
this.resolvedCredential = {
|
|
286
287
|
token: accessToken,
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
//
|
|
290
|
-
|
|
291
|
-
source: 'keychain',
|
|
288
|
+
// The backend the broker actually wrote to. Hard-coding
|
|
289
|
+
// 'keychain' labelled a Linux credential (always the file)
|
|
290
|
+
// "macOS Keychain" in the same process that minted it.
|
|
291
|
+
source: autoResult.outcome.storedIn === 'keychain' ? 'keychain' : 'file',
|
|
292
292
|
kind: (0, auth_core_1.classifyTokenKind)(accessToken),
|
|
293
293
|
};
|
|
294
294
|
}
|
|
@@ -888,6 +888,30 @@ class BaseCommand extends core_1.Command {
|
|
|
888
888
|
retryable: true,
|
|
889
889
|
});
|
|
890
890
|
}
|
|
891
|
+
else if ((e.status === 403 || e.status === 504) &&
|
|
892
|
+
!body &&
|
|
893
|
+
(0, edge_error_page_1.describeEdgeErrorPage)({ status: e.status, body: e.body, method: e.method })) {
|
|
894
|
+
// An HTML page in place of the API's JSON: the edge answered, not the
|
|
895
|
+
// API (OSK-8700, OSK-8705). A WAF 403 is a content match that the same
|
|
896
|
+
// request will hit again, not "transient" and not a permission; an edge
|
|
897
|
+
// 504 is a request the API may still be carrying out, not proof of an
|
|
898
|
+
// outage. 502/503 pages keep the outage branch below, which is what
|
|
899
|
+
// they usually are and which records the incident.
|
|
900
|
+
const edge = (0, edge_error_page_1.describeEdgeErrorPage)({
|
|
901
|
+
status: e.status,
|
|
902
|
+
body: e.body,
|
|
903
|
+
method: e.method,
|
|
904
|
+
host: this.cliConfig?.baseURL,
|
|
905
|
+
});
|
|
906
|
+
this.failWithCliError({
|
|
907
|
+
message: say(edge.message),
|
|
908
|
+
code: edge.code,
|
|
909
|
+
status: e.status,
|
|
910
|
+
exit: e.status === 403 ? 3 : 5,
|
|
911
|
+
retryable: edge.retryable,
|
|
912
|
+
...(edge.requestId ? { details: { edgeRequestId: edge.requestId } } : {}),
|
|
913
|
+
});
|
|
914
|
+
}
|
|
891
915
|
else if (e.status === 403) {
|
|
892
916
|
// A 403 WITH a body is the API deciding; it says why, and we relay it.
|
|
893
917
|
//
|
|
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const base_command_1 = require("../../base-command");
|
|
5
5
|
const api_fetch_1 = require("../../lib/api-fetch");
|
|
6
6
|
const daemon_ref_1 = require("../../lib/daemon-ref");
|
|
7
|
+
const sky_code_1 = require("../../lib/sky-code");
|
|
7
8
|
/**
|
|
8
9
|
* `skrr code install` — install the engine from the terminal.
|
|
9
10
|
*
|
|
@@ -47,6 +48,18 @@ class CodeInstall extends base_command_1.BaseCommand {
|
|
|
47
48
|
};
|
|
48
49
|
async run() {
|
|
49
50
|
const { flags } = await this.parse(CodeInstall);
|
|
51
|
+
// Refused locally, before choosing a daemon. The daemon and the API refuse
|
|
52
|
+
// too, but with several active daemons this command would first ask which
|
|
53
|
+
// one — and "pick a machine" is the wrong question to put to someone whose
|
|
54
|
+
// answer is "none of them can do this here".
|
|
55
|
+
if ((0, sky_code_1.isDedicatedRuntimeWorkload)()) {
|
|
56
|
+
this.failWithCliError({
|
|
57
|
+
message: sky_code_1.DEDICATED_RUNTIME_ENGINE_MESSAGE,
|
|
58
|
+
code: 'DEDICATED_RUNTIME_ENGINE_SHIPS_WITH_IMAGE',
|
|
59
|
+
exit: 1,
|
|
60
|
+
retryable: false,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
50
63
|
const daemonId = await this.resolveDaemon(flags.daemon);
|
|
51
64
|
let started;
|
|
52
65
|
try {
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { BaseCommand } from '../../../base-command';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Change a lease's monthly spending cap.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* `PATCH /api/machines/leases/:id/billing` accepts `spendingLimitCents` and
|
|
6
|
+
* NOTHING else — its own comment says lifecycle billing state, usage and cost
|
|
7
|
+
* fields stay server-owned. This command used to be "change who pays", sending
|
|
8
|
+
* `{ workspaceId }`: no API moves a lease's payer, so every call was answered
|
|
9
|
+
* `INVALID_RUNTIME_SPENDING_LIMIT` for a field it never sent, while the parity
|
|
10
|
+
* check stayed green because it tests that the URL is reachable, not that the
|
|
11
|
+
* body means anything to it.
|
|
8
12
|
*/
|
|
9
13
|
export default class HarnessesLeasesBilling extends BaseCommand {
|
|
10
14
|
static description: string;
|
|
@@ -14,8 +18,7 @@ export default class HarnessesLeasesBilling extends BaseCommand {
|
|
|
14
18
|
};
|
|
15
19
|
static flags: {
|
|
16
20
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
|
-
|
|
18
|
-
personal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
21
|
+
'spending-limit-cents': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
22
|
};
|
|
20
23
|
run(): Promise<void>;
|
|
21
24
|
}
|
|
@@ -13,50 +13,45 @@ const core_1 = require("@oclif/core");
|
|
|
13
13
|
const base_command_1 = require("../../../base-command");
|
|
14
14
|
const harnesses_1 = require("../../../lib/harnesses");
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Change a lease's monthly spending cap.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* `PATCH /api/machines/leases/:id/billing` accepts `spendingLimitCents` and
|
|
19
|
+
* NOTHING else — its own comment says lifecycle billing state, usage and cost
|
|
20
|
+
* fields stay server-owned. This command used to be "change who pays", sending
|
|
21
|
+
* `{ workspaceId }`: no API moves a lease's payer, so every call was answered
|
|
22
|
+
* `INVALID_RUNTIME_SPENDING_LIMIT` for a field it never sent, while the parity
|
|
23
|
+
* check stayed green because it tests that the URL is reachable, not that the
|
|
24
|
+
* body means anything to it.
|
|
21
25
|
*/
|
|
22
26
|
class HarnessesLeasesBilling extends base_command_1.BaseCommand {
|
|
23
|
-
static description = 'Change
|
|
27
|
+
static description = 'Change the monthly spending cap of a hosted lease (Hosted Machine or Dedicated Runtime)';
|
|
24
28
|
static examples = [
|
|
25
|
-
'<%= config.bin %> harnesses leases billing <lease-id> --
|
|
26
|
-
'<%= config.bin %> harnesses leases billing <lease-id> --
|
|
29
|
+
'<%= config.bin %> harnesses leases billing <lease-id> --spending-limit-cents 30000',
|
|
30
|
+
'<%= config.bin %> harnesses leases billing <lease-id> --spending-limit-cents 5000 --json',
|
|
27
31
|
];
|
|
28
32
|
static args = {
|
|
29
33
|
lease: core_1.Args.string({ ignoreStdin: true, description: 'Lease ID', required: true }),
|
|
30
34
|
};
|
|
31
35
|
static flags = {
|
|
32
36
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
33
|
-
|
|
34
|
-
description: '
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
personal: core_1.Flags.boolean({
|
|
38
|
-
description: 'Bill you personally instead of a workspace',
|
|
39
|
-
exclusive: ['workspace'],
|
|
37
|
+
'spending-limit-cents': core_1.Flags.integer({
|
|
38
|
+
description: 'New monthly cap in cents. Refused below what the month has already spent or is projected to. Who pays for a lease is set at create and cannot be changed.',
|
|
39
|
+
required: true,
|
|
40
|
+
min: 1,
|
|
40
41
|
}),
|
|
41
42
|
};
|
|
42
43
|
async run() {
|
|
43
44
|
this.requireAuth();
|
|
44
45
|
const { args, flags } = await this.parse(HarnessesLeasesBilling);
|
|
45
|
-
if (!flags.workspace && !flags.personal) {
|
|
46
|
-
this.error('Name the new payer: --workspace <id> or --personal.', { exit: 1 });
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
// `null` is the explicit "no workspace pays this" signal, not an omission.
|
|
50
|
-
const body = { workspaceId: flags.personal ? null : flags.workspace };
|
|
51
46
|
try {
|
|
52
|
-
const response = await (0, harnesses_1.setHarnessLeaseBilling)(args.lease,
|
|
47
|
+
const response = await (0, harnesses_1.setHarnessLeaseBilling)(args.lease, {
|
|
48
|
+
spendingLimitCents: flags['spending-limit-cents'],
|
|
49
|
+
});
|
|
53
50
|
if (flags.json) {
|
|
54
51
|
this.log(JSON.stringify(response, null, 2));
|
|
55
52
|
return;
|
|
56
53
|
}
|
|
57
|
-
this.log(flags.
|
|
58
|
-
? `${args.lease} now bills you personally.`
|
|
59
|
-
: `${args.lease} now bills workspace ${flags.workspace}.`);
|
|
54
|
+
this.log(`${args.lease} monthly spending cap set to $${(flags['spending-limit-cents'] / 100).toFixed(2)}.`);
|
|
60
55
|
}
|
|
61
56
|
catch (err) {
|
|
62
57
|
this.handleApiError(err);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DedicatedLeaseCommand } from '../../../lib/dedicated-lease-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr machines dedicated attach` — run an agent on this machine.
|
|
4
|
+
*
|
|
5
|
+
* The only way to put an agent's turns on a Dedicated Runtime is to pin it to a
|
|
6
|
+
* harness row the machine's daemon registered, and the lease payload names no
|
|
7
|
+
* daemon, so the caller had to cross-reference `harnesses list` by metadata the
|
|
8
|
+
* table does not print. The admission error even told users to "attach it",
|
|
9
|
+
* naming a command that did not exist.
|
|
10
|
+
*
|
|
11
|
+
* This resolves the row from the lease and hands off to `agents attach-harness`,
|
|
12
|
+
* so execution-order semantics, agent resolution and task-pin migration stay in
|
|
13
|
+
* the one command that owns them.
|
|
14
|
+
*/
|
|
15
|
+
export default class DedicatedMachinesAttach extends DedicatedLeaseCommand {
|
|
16
|
+
static description: string;
|
|
17
|
+
static examples: string[];
|
|
18
|
+
static args: {
|
|
19
|
+
lease: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
20
|
+
};
|
|
21
|
+
static flags: {
|
|
22
|
+
agent: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
23
|
+
engine: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
24
|
+
'rebind-tasks': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
25
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
26
|
+
};
|
|
27
|
+
run(): Promise<void>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
7
|
+
const dedicated_lease_command_1 = require("../../../lib/dedicated-lease-command");
|
|
8
|
+
const dedicated_machines_1 = require("../../../lib/dedicated-machines");
|
|
9
|
+
const harnesses_1 = require("../../../lib/harnesses");
|
|
10
|
+
const attach_harness_1 = __importDefault(require("../../agents/attach-harness"));
|
|
11
|
+
/**
|
|
12
|
+
* `skrr machines dedicated attach` — run an agent on this machine.
|
|
13
|
+
*
|
|
14
|
+
* The only way to put an agent's turns on a Dedicated Runtime is to pin it to a
|
|
15
|
+
* harness row the machine's daemon registered, and the lease payload names no
|
|
16
|
+
* daemon, so the caller had to cross-reference `harnesses list` by metadata the
|
|
17
|
+
* table does not print. The admission error even told users to "attach it",
|
|
18
|
+
* naming a command that did not exist.
|
|
19
|
+
*
|
|
20
|
+
* This resolves the row from the lease and hands off to `agents attach-harness`,
|
|
21
|
+
* so execution-order semantics, agent resolution and task-pin migration stay in
|
|
22
|
+
* the one command that owns them.
|
|
23
|
+
*/
|
|
24
|
+
class DedicatedMachinesAttach extends dedicated_lease_command_1.DedicatedLeaseCommand {
|
|
25
|
+
static description = 'Pin an agent to a Dedicated Runtime so its turns and tasks run on that machine, under the engine you choose';
|
|
26
|
+
static examples = [
|
|
27
|
+
'<%= config.bin %> machines dedicated attach <lease-id> --agent <agent-id>',
|
|
28
|
+
'<%= config.bin %> machines dedicated attach <lease-id> --agent <agent-id> --engine claude --rebind-tasks',
|
|
29
|
+
'<%= config.bin %> machines dedicated attach <lease-id> --agent <agent-id> --engine codex --json',
|
|
30
|
+
];
|
|
31
|
+
static args = {
|
|
32
|
+
lease: core_1.Args.string({
|
|
33
|
+
description: dedicated_lease_command_1.DEDICATED_LEASE_ARG_DESCRIPTION,
|
|
34
|
+
required: true,
|
|
35
|
+
ignoreStdin: true,
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
static flags = {
|
|
39
|
+
agent: core_1.Flags.string({
|
|
40
|
+
description: 'Agent to attach. Inside an agent session it defaults to that agent (OVERSKY_SESSION_AGENT_ID).',
|
|
41
|
+
}),
|
|
42
|
+
engine: core_1.Flags.string({
|
|
43
|
+
description: 'Which engine row to attach when the machine registered several (claude, codex, sky-code, oversky). Required only when it is ambiguous.',
|
|
44
|
+
}),
|
|
45
|
+
'rebind-tasks': core_1.Flags.boolean({
|
|
46
|
+
description: 'Publish the updated agent release and move dormant assigned task pins to it. Running and finished tasks are never changed.',
|
|
47
|
+
}),
|
|
48
|
+
json: core_1.Flags.boolean({ description: 'Output the attachment result as JSON' }),
|
|
49
|
+
};
|
|
50
|
+
async run() {
|
|
51
|
+
this.requireAuth();
|
|
52
|
+
const { args, flags } = await this.parse(DedicatedMachinesAttach);
|
|
53
|
+
const leaseId = await this.resolveLeaseArg(args.lease);
|
|
54
|
+
const response = await this.callDedicated(() => (0, dedicated_machines_1.getDedicatedRuntime)(leaseId, this.scopeFrom(flags)));
|
|
55
|
+
const lease = response?.lease;
|
|
56
|
+
if (!lease)
|
|
57
|
+
this.error('Dedicated Runtime lease not found.', { exit: 1 });
|
|
58
|
+
const listed = await this.callDedicated(() => (0, harnesses_1.listHarnesses)());
|
|
59
|
+
const selection = (0, dedicated_machines_1.selectDedicatedAttachHarness)(lease, listed?.harnesses ?? [], flags.engine);
|
|
60
|
+
if ('error' in selection) {
|
|
61
|
+
this.error(selection.error, { exit: 1 });
|
|
62
|
+
}
|
|
63
|
+
const { harness } = selection;
|
|
64
|
+
if (!flags.json) {
|
|
65
|
+
process.stderr.write(`Attaching ${harness.provider} on ${leaseId} (harness ${harness._id}, ${harness.status || 'status unknown'}).\n` +
|
|
66
|
+
'Everything the agent runs there acts as you: it shares the machine’s sign-ins and your skrr login.\n');
|
|
67
|
+
}
|
|
68
|
+
await attach_harness_1.default.run([
|
|
69
|
+
harness._id,
|
|
70
|
+
...(flags.agent ? ['--agent', flags.agent] : []),
|
|
71
|
+
...(flags['rebind-tasks'] ? ['--rebind-tasks'] : []),
|
|
72
|
+
...(flags.json ? ['--json'] : []),
|
|
73
|
+
], this.config);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.default = DedicatedMachinesAttach;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DedicatedLeaseCommand } from '../../../lib/dedicated-lease-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr machines dedicated catalog` — what `create` will accept, and what it costs.
|
|
4
|
+
*
|
|
5
|
+
* `--size-preset`, `--storage-gb`, `--retention-class` and `--backup-profile`
|
|
6
|
+
* carry no client-side values on purpose: presets are gated by server flags and
|
|
7
|
+
* the storage bounds are configuration. That made `create --help` point at
|
|
8
|
+
* `harnesses products`, whose table shows none of them without `--json`.
|
|
9
|
+
*/
|
|
10
|
+
export default class DedicatedMachinesCatalog 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,75 @@
|
|
|
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
|
+
const harnesses_1 = require("../../../lib/harnesses");
|
|
7
|
+
/**
|
|
8
|
+
* `skrr machines dedicated catalog` — what `create` will accept, and what it costs.
|
|
9
|
+
*
|
|
10
|
+
* `--size-preset`, `--storage-gb`, `--retention-class` and `--backup-profile`
|
|
11
|
+
* carry no client-side values on purpose: presets are gated by server flags and
|
|
12
|
+
* the storage bounds are configuration. That made `create --help` point at
|
|
13
|
+
* `harnesses products`, whose table shows none of them without `--json`.
|
|
14
|
+
*/
|
|
15
|
+
class DedicatedMachinesCatalog extends dedicated_lease_command_1.DedicatedLeaseCommand {
|
|
16
|
+
static description = 'Show the Dedicated Runtime sizes, storage bounds, retention classes, backup profiles and prices that create accepts';
|
|
17
|
+
static examples = [
|
|
18
|
+
'<%= config.bin %> machines dedicated catalog',
|
|
19
|
+
'<%= config.bin %> machines dedicated catalog --json',
|
|
20
|
+
];
|
|
21
|
+
static flags = {
|
|
22
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
23
|
+
};
|
|
24
|
+
async run() {
|
|
25
|
+
this.requireAuth();
|
|
26
|
+
const { flags } = await this.parse(DedicatedMachinesCatalog);
|
|
27
|
+
const payload = await this.callDedicated(() => (0, harnesses_1.listHarnessProducts)());
|
|
28
|
+
const catalog = (0, dedicated_machines_1.dedicatedCatalogFromProducts)(payload);
|
|
29
|
+
if (!catalog) {
|
|
30
|
+
this.error('This server does not offer Dedicated Runtime.', { exit: 1 });
|
|
31
|
+
}
|
|
32
|
+
if (flags.json) {
|
|
33
|
+
this.log(JSON.stringify({ catalog }, null, 2));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.log(`Dedicated Runtime — ${catalog.availability}`);
|
|
37
|
+
if (catalog.disabledReason)
|
|
38
|
+
this.log(` ${catalog.disabledReason}`);
|
|
39
|
+
if (catalog.headline)
|
|
40
|
+
this.log(` ${catalog.headline}`);
|
|
41
|
+
this.log('\nSizes (--size-preset)');
|
|
42
|
+
if (catalog.sizes.length === 0)
|
|
43
|
+
this.log(' none offered right now');
|
|
44
|
+
for (const size of catalog.sizes) {
|
|
45
|
+
const spec = [
|
|
46
|
+
size.vcpus ? `${size.vcpus} vCPU` : '',
|
|
47
|
+
size.memoryGiB ? `${size.memoryGiB} GiB RAM` : '',
|
|
48
|
+
size.accelerator || '',
|
|
49
|
+
]
|
|
50
|
+
.filter(Boolean)
|
|
51
|
+
.join(' · ');
|
|
52
|
+
this.log(` ${String(size.id).padEnd(14)}${spec}`);
|
|
53
|
+
}
|
|
54
|
+
if (catalog.storage) {
|
|
55
|
+
const { minGb, defaultGb, maxGb } = catalog.storage;
|
|
56
|
+
this.log(`\nWorkspace (--storage-gb)\n ${minGb}–${maxGb} GiB, default ${defaultGb}; grow later, never shrink`);
|
|
57
|
+
}
|
|
58
|
+
if (catalog.retentionClasses.length) {
|
|
59
|
+
this.log(`\nRetention (--retention-class)\n ${catalog.retentionClasses.join(', ')}`);
|
|
60
|
+
}
|
|
61
|
+
if (catalog.backupProfiles.length) {
|
|
62
|
+
this.log(`\nBackup (--backup-profile)\n ${catalog.backupProfiles.join(', ')}`);
|
|
63
|
+
}
|
|
64
|
+
if (catalog.regionClasses.length) {
|
|
65
|
+
this.log(`\nRegion (--region-class)\n ${catalog.regionClasses.join(', ')}`);
|
|
66
|
+
}
|
|
67
|
+
this.log('\nPrices');
|
|
68
|
+
if (catalog.priceLines.length === 0)
|
|
69
|
+
this.log(' not published by this server');
|
|
70
|
+
for (const line of catalog.priceLines) {
|
|
71
|
+
this.log(` ${line.display || `${(0, dedicated_machines_1.formatUsdCents)(line.amountCents)} ${line.label || ''}`}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.default = DedicatedMachinesCatalog;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr machines dedicated cp` — copy ONE file to or from a Dedicated Runtime.
|
|
4
|
+
*
|
|
5
|
+
* On the machine, paths resolve against /workspace and must be inside `repos/`
|
|
6
|
+
* or `user-data/`; the rest of the workspace belongs to the runtime. Files are
|
|
7
|
+
* limited to 64 MiB. See lib/dedicated-copy.ts for how neither end is ever left
|
|
8
|
+
* half-written.
|
|
9
|
+
*/
|
|
10
|
+
export default class DedicatedMachinesCp extends BaseCommand {
|
|
11
|
+
static description: string;
|
|
12
|
+
static examples: string[];
|
|
13
|
+
static args: {
|
|
14
|
+
source: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
15
|
+
destination: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
16
|
+
};
|
|
17
|
+
static flags: {
|
|
18
|
+
workspace: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
20
|
+
};
|
|
21
|
+
run(): Promise<void>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../../../base-command");
|
|
5
|
+
const dedicated_machines_1 = require("../../../lib/dedicated-machines");
|
|
6
|
+
const dedicated_copy_1 = require("../../../lib/dedicated-copy");
|
|
7
|
+
/**
|
|
8
|
+
* `skrr machines dedicated cp` — copy ONE file to or from a Dedicated Runtime.
|
|
9
|
+
*
|
|
10
|
+
* On the machine, paths resolve against /workspace and must be inside `repos/`
|
|
11
|
+
* or `user-data/`; the rest of the workspace belongs to the runtime. Files are
|
|
12
|
+
* limited to 64 MiB. See lib/dedicated-copy.ts for how neither end is ever left
|
|
13
|
+
* half-written.
|
|
14
|
+
*/
|
|
15
|
+
class DedicatedMachinesCp extends base_command_1.BaseCommand {
|
|
16
|
+
static description = 'Copy a file to or from a Dedicated Runtime machine';
|
|
17
|
+
static examples = [
|
|
18
|
+
'<%= config.bin %> machines dedicated cp ./dist/app.tar.gz rtl_abc123:repos/app/app.tar.gz',
|
|
19
|
+
'<%= config.bin %> machines dedicated cp rtl_abc123:repos/app/coverage/report.html ./report.html',
|
|
20
|
+
];
|
|
21
|
+
// `ignoreStdin: true` on both, per the CLI's own hygiene rule: without it oclif
|
|
22
|
+
// will read a missing positional from stdin, so `skrr machines dedicated cp`
|
|
23
|
+
// typed with one argument hangs on a pipe instead of saying what it needs.
|
|
24
|
+
static args = {
|
|
25
|
+
source: core_1.Args.string({
|
|
26
|
+
description: 'Local path, or <lease-id>:<path> on the machine',
|
|
27
|
+
required: true,
|
|
28
|
+
ignoreStdin: true,
|
|
29
|
+
}),
|
|
30
|
+
destination: core_1.Args.string({
|
|
31
|
+
description: 'Local path, or <lease-id>:<path> on the machine',
|
|
32
|
+
required: true,
|
|
33
|
+
ignoreStdin: true,
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
static flags = {
|
|
37
|
+
workspace: core_1.Flags.string({ description: 'Workspace scope' }),
|
|
38
|
+
json: core_1.Flags.boolean({ description: 'Output the result as JSON' }),
|
|
39
|
+
};
|
|
40
|
+
async run() {
|
|
41
|
+
this.requireAuth();
|
|
42
|
+
const { args, flags } = await this.parse(DedicatedMachinesCp);
|
|
43
|
+
let plan;
|
|
44
|
+
try {
|
|
45
|
+
plan = (0, dedicated_machines_1.parseDedicatedCopyEndpoints)(args.source, args.destination);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
this.error(err.message, { exit: 2 });
|
|
49
|
+
}
|
|
50
|
+
const scope = { workspaceId: flags.workspace };
|
|
51
|
+
let result;
|
|
52
|
+
try {
|
|
53
|
+
result =
|
|
54
|
+
plan.direction === 'upload'
|
|
55
|
+
? await (0, dedicated_copy_1.uploadToDedicatedRuntime)(plan.localPath, plan.leaseId, plan.remotePath, scope)
|
|
56
|
+
: await (0, dedicated_copy_1.downloadFromDedicatedRuntime)(plan.leaseId, plan.remotePath, plan.localPath, scope);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
const message = (0, dedicated_machines_1.formatDedicatedRuntimeApiError)(err);
|
|
60
|
+
if (message)
|
|
61
|
+
this.error(message, { exit: 1, code: (0, dedicated_machines_1.dedicatedRuntimeApiErrorCode)(err) });
|
|
62
|
+
// A local failure (missing file, too large, changed mid-copy) is ours to
|
|
63
|
+
// explain; an API failure without a readable body goes to the shared path.
|
|
64
|
+
if (err instanceof Error && typeof err.status !== 'number') {
|
|
65
|
+
this.error(err.message, { exit: 1 });
|
|
66
|
+
}
|
|
67
|
+
this.handleApiError(err);
|
|
68
|
+
}
|
|
69
|
+
if (flags.json) {
|
|
70
|
+
this.log(JSON.stringify({ direction: plan.direction, ...result }, null, 2));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
this.log(`${plan.direction === 'upload' ? 'Uploaded' : 'Downloaded'} ${result.bytes} bytes → ${result.destination}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.default = DedicatedMachinesCp;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export default class DedicatedMachinesCreate extends
|
|
1
|
+
import { DedicatedLeaseCommand } from '../../../lib/dedicated-lease-command';
|
|
2
|
+
export default class DedicatedMachinesCreate extends DedicatedLeaseCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
|
+
wait: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
timeout: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
interval: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
6
9
|
name: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
10
|
'size-preset': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
11
|
'region-class': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
@@ -10,6 +13,7 @@ export default class DedicatedMachinesCreate extends BaseCommand {
|
|
|
10
13
|
'retention-class': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
14
|
'backup-profile': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
15
|
'spending-limit-cents': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
|
+
repository: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
17
|
workspace: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
18
|
'request-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
19
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const node_crypto_1 = require("node:crypto");
|
|
5
|
-
const
|
|
5
|
+
const dedicated_lease_command_1 = require("../../../lib/dedicated-lease-command");
|
|
6
6
|
const dedicated_machines_1 = require("../../../lib/dedicated-machines");
|
|
7
|
-
class DedicatedMachinesCreate extends
|
|
8
|
-
static description = 'Request a Dedicated Runtime lease';
|
|
7
|
+
class DedicatedMachinesCreate extends dedicated_lease_command_1.DedicatedLeaseCommand {
|
|
8
|
+
static description = 'Request a Dedicated Runtime lease. See `machines dedicated catalog` for sizes, storage bounds and prices.';
|
|
9
9
|
static examples = [
|
|
10
10
|
'<%= config.bin %> machines dedicated create --name dev-box --size-preset standard --spending-limit-cents 20000',
|
|
11
|
-
'<%= config.bin %> machines dedicated create --name dev-box --size-preset standard --spending-limit-cents 20000 --json',
|
|
11
|
+
'<%= config.bin %> machines dedicated create --name dev-box --size-preset standard --spending-limit-cents 20000 --repository acme/app --wait --json',
|
|
12
12
|
];
|
|
13
13
|
static flags = {
|
|
14
14
|
name: core_1.Flags.string({ description: 'Display name for the dedicated machine', required: true }),
|
|
15
15
|
'size-preset': core_1.Flags.string({
|
|
16
|
-
description: 'Instance size preset (
|
|
16
|
+
description: 'Instance size preset (see `machines dedicated catalog`)',
|
|
17
17
|
required: true,
|
|
18
18
|
}),
|
|
19
19
|
// None of these four carry a client-side default, deliberately.
|
|
@@ -33,26 +33,34 @@ class DedicatedMachinesCreate extends base_command_1.BaseCommand {
|
|
|
33
33
|
description: 'Workspace storage size in GB. Defaults to the product catalog size.',
|
|
34
34
|
}),
|
|
35
35
|
'retention-class': core_1.Flags.string({
|
|
36
|
-
description: '
|
|
36
|
+
description: 'What destroy does with the workspace: none (delete), standard or extended (archive it). Defaults to the product catalog value.',
|
|
37
37
|
}),
|
|
38
38
|
'backup-profile': core_1.Flags.string({
|
|
39
39
|
description: 'crash-consistent (AWS Backup) or application-consistent (guest fsfreeze while the daemon is reachable; scheduled DLM when that plan is enabled). Defaults to the product catalog value.',
|
|
40
40
|
}),
|
|
41
41
|
'spending-limit-cents': core_1.Flags.integer({
|
|
42
|
-
description: 'Monthly spending limit in cents. Required
|
|
42
|
+
description: 'Monthly spending limit in cents. Required; change it later with `machines dedicated spending-limit`.',
|
|
43
43
|
required: true,
|
|
44
44
|
}),
|
|
45
|
+
repository: core_1.Flags.string({
|
|
46
|
+
description: 'Default GitHub repository (owner/repo) for git credentials on the machine. Requires the GitHub App installed for it; a clone of another repository the App covers still works.',
|
|
47
|
+
}),
|
|
45
48
|
workspace: core_1.Flags.string({ description: 'Workspace scope' }),
|
|
46
49
|
'request-id': core_1.Flags.string({
|
|
47
50
|
description: 'Idempotency key. Reuse it to safely retry the same create request.',
|
|
48
51
|
}),
|
|
49
52
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
53
|
+
...dedicated_lease_command_1.dedicatedWaitFlags,
|
|
50
54
|
};
|
|
51
55
|
async run() {
|
|
52
56
|
this.requireAuth();
|
|
53
57
|
const { flags } = await this.parse(DedicatedMachinesCreate);
|
|
58
|
+
if (flags.repository !== undefined && !(0, dedicated_machines_1.isDedicatedRepositoryRef)(flags.repository)) {
|
|
59
|
+
this.error(`--repository must look like owner/repo, got "${flags.repository}".`, { exit: 2 });
|
|
60
|
+
}
|
|
61
|
+
const requestId = flags['request-id'] || newRequestId();
|
|
54
62
|
const body = (0, dedicated_machines_1.dedicatedRuntimeCreateInput)({
|
|
55
|
-
requestId
|
|
63
|
+
requestId,
|
|
56
64
|
displayName: flags.name,
|
|
57
65
|
sizePreset: flags['size-preset'],
|
|
58
66
|
monthlySpendingLimitCents: flags['spending-limit-cents'],
|
|
@@ -60,27 +68,28 @@ class DedicatedMachinesCreate extends base_command_1.BaseCommand {
|
|
|
60
68
|
storageGb: flags['storage-gb'],
|
|
61
69
|
retentionClass: flags['retention-class'],
|
|
62
70
|
backupProfile: flags['backup-profile'],
|
|
71
|
+
repositoryRef: flags.repository,
|
|
63
72
|
workspaceId: flags.workspace,
|
|
64
73
|
});
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
response = await (0, dedicated_machines_1.createDedicatedRuntime)(body);
|
|
68
|
-
}
|
|
69
|
-
catch (err) {
|
|
70
|
-
const message = (0, dedicated_machines_1.formatDedicatedRuntimeApiError)(err);
|
|
71
|
-
if (message)
|
|
72
|
-
this.error(message, { exit: 1 });
|
|
73
|
-
this.handleApiError(err);
|
|
74
|
-
}
|
|
74
|
+
const response = await this.callDedicated(() => (0, dedicated_machines_1.createDedicatedRuntime)(body));
|
|
75
75
|
const lease = response?.lease;
|
|
76
|
+
const id = (0, dedicated_machines_1.dedicatedLeaseId)(lease);
|
|
77
|
+
if (flags.wait) {
|
|
78
|
+
// The request id is what makes a retry safe, and a --wait that times out
|
|
79
|
+
// is exactly when someone retries — so say it before watching.
|
|
80
|
+
if (!flags.json && !flags['request-id']) {
|
|
81
|
+
process.stderr.write(`Request id ${requestId} (reuse it with --request-id to retry safely)\n`);
|
|
82
|
+
}
|
|
83
|
+
await this.reportLeaseAction(response, flags, { kind: 'running' }, 'Provisioning');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
76
86
|
if (flags.json) {
|
|
77
87
|
this.log(JSON.stringify(response, null, 2));
|
|
78
88
|
return;
|
|
79
89
|
}
|
|
80
|
-
const id = (0, dedicated_machines_1.dedicatedLeaseId)(lease);
|
|
81
90
|
this.log(`Dedicated Runtime ${(0, dedicated_machines_1.dedicatedLeaseDisplayName)(lease)} (${id || 'unknown'}) ${(0, dedicated_machines_1.dedicatedLeaseState)(lease)}.`);
|
|
82
91
|
if (id) {
|
|
83
|
-
this.log(`Poll: ${this.config.bin} machines dedicated show ${id}`);
|
|
92
|
+
this.log(`Poll: ${this.config.bin} machines dedicated show ${id} (or pass --wait)`);
|
|
84
93
|
}
|
|
85
94
|
}
|
|
86
95
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DedicatedLeaseCommand } from '../../../lib/dedicated-lease-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr machines dedicated current` — which Dedicated Runtime am I running on?
|
|
4
|
+
*
|
|
5
|
+
* An agent working on the machine is the caller most likely to need its own
|
|
6
|
+
* lease — to snapshot before something risky, read the spend against the cap,
|
|
7
|
+
* or stop the machine when the work is done — and nothing in its environment
|
|
8
|
+
* names it. Every lease command also accepts `self`; this prints the answer so a
|
|
9
|
+
* script can hold it.
|
|
10
|
+
*/
|
|
11
|
+
export default class DedicatedMachinesCurrent extends DedicatedLeaseCommand {
|
|
12
|
+
static description: string;
|
|
13
|
+
static examples: string[];
|
|
14
|
+
static flags: {
|
|
15
|
+
id: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
};
|
|
18
|
+
run(): Promise<void>;
|
|
19
|
+
}
|