@skrr-ai/cli 0.1.88 → 0.1.90

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.
Files changed (59) hide show
  1. package/dist/commands/machines/computer-adoption.d.ts +3 -2
  2. package/dist/commands/machines/computer-adoption.js +4 -3
  3. package/dist/commands/machines/dedicated/agent-browser.d.ts +25 -0
  4. package/dist/commands/machines/dedicated/agent-browser.js +65 -0
  5. package/dist/commands/machines/dedicated/exec.js +60 -14
  6. package/dist/commands/machines/dedicated/index.js +2 -0
  7. package/dist/commands/machines/dedicated/power/explain.d.ts +13 -0
  8. package/dist/commands/machines/dedicated/power/explain.js +36 -0
  9. package/dist/commands/machines/dedicated/power/index.d.ts +10 -0
  10. package/dist/commands/machines/dedicated/power/index.js +24 -0
  11. package/dist/commands/machines/dedicated/power/keep-awake.d.ts +20 -0
  12. package/dist/commands/machines/dedicated/power/keep-awake.js +69 -0
  13. package/dist/commands/machines/dedicated/power/set.d.ts +23 -0
  14. package/dist/commands/machines/dedicated/power/set.js +106 -0
  15. package/dist/commands/machines/dedicated/power/show.d.ts +13 -0
  16. package/dist/commands/machines/dedicated/power/show.js +36 -0
  17. package/dist/commands/machines/dedicated/show.js +17 -2
  18. package/dist/lib/commitments.d.ts +1 -1
  19. package/dist/lib/commitments.js +4 -2
  20. package/dist/lib/computer-adoption.d.ts +5 -0
  21. package/dist/lib/computer-adoption.js +6 -1
  22. package/dist/lib/computer-consent.d.ts +43 -1
  23. package/dist/lib/computer-consent.js +125 -4
  24. package/dist/lib/dedicated-keep-awake.d.ts +19 -0
  25. package/dist/lib/dedicated-keep-awake.js +64 -0
  26. package/dist/lib/dedicated-machines.d.ts +31 -0
  27. package/dist/lib/dedicated-machines.js +40 -0
  28. package/dist/lib/dedicated-power.d.ts +61 -0
  29. package/dist/lib/dedicated-power.js +243 -0
  30. package/dist/lib/exec-runtime-binary.d.ts +3 -1
  31. package/dist/lib/exec-runtime-binary.js +16 -2
  32. package/dist/lib/format.d.ts +13 -0
  33. package/dist/lib/format.js +51 -0
  34. package/dist/lib/keychain.js +3 -0
  35. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.d.ts +135 -8
  36. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.js +166 -16
  37. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/dedicatedRuntimeBusyWire.d.ts +107 -0
  38. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/dedicatedRuntimeBusyWire.js +151 -0
  39. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/dedicatedRuntimeWakeWire.d.ts +115 -0
  40. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/dedicatedRuntimeWakeWire.js +117 -0
  41. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
  42. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +8 -3
  43. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.d.ts +31 -7
  44. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +149 -9
  45. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.d.ts +135 -8
  46. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.js +161 -13
  47. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/dedicatedRuntimeBusyWire.d.ts +107 -0
  48. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/dedicatedRuntimeBusyWire.js +147 -0
  49. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/dedicatedRuntimeWakeWire.d.ts +115 -0
  50. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/dedicatedRuntimeWakeWire.js +113 -0
  51. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
  52. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -1
  53. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.d.ts +31 -7
  54. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +144 -8
  55. package/dist/node_modules/@skrr-ai/auth-core/package.json +21 -1
  56. package/dist/node_modules/@skrr-ai/data-provider/index.js +6730 -6366
  57. package/dist/node_modules/@skrr-ai/data-provider/package.json +1 -1
  58. package/oclif.manifest.json +6303 -5852
  59. package/package.json +2 -2
@@ -1,8 +1,9 @@
1
1
  import { BaseCommand } from '../../base-command';
2
2
  /**
3
3
  * `skrr machines computer-adoption` — the share of daemons still on the old
4
- * event families, which is the number retiring `browser:liveview:*` and
5
- * `agent:terminal:*` waits on (OSK-13578). Admin only on the server: it
4
+ * event families, the number retiring `browser:liveview:*` and
5
+ * `agent:terminal:*` waited on (OSK-13578). They are retired (OSK-13509), so it
6
+ * now counts who the retirement stranded. Admin only on the server: it
6
7
  * describes the fleet, not the caller.
7
8
  */
8
9
  export default class MachinesComputerAdoption extends BaseCommand {
@@ -5,12 +5,13 @@ const base_command_1 = require("../../base-command");
5
5
  const computer_adoption_1 = require("../../lib/computer-adoption");
6
6
  /**
7
7
  * `skrr machines computer-adoption` — the share of daemons still on the old
8
- * event families, which is the number retiring `browser:liveview:*` and
9
- * `agent:terminal:*` waits on (OSK-13578). Admin only on the server: it
8
+ * event families, the number retiring `browser:liveview:*` and
9
+ * `agent:terminal:*` waited on (OSK-13578). They are retired (OSK-13509), so it
10
+ * now counts who the retirement stranded. Admin only on the server: it
10
11
  * describes the fleet, not the caller.
11
12
  */
12
13
  class MachinesComputerAdoption extends base_command_1.BaseCommand {
13
- static description = 'Show how many daemons are still on the old browser live view / agent terminal event families instead of the computer protocol, and whether the retirement criterion is met (admin only)';
14
+ static description = 'Show how many daemons are still on the old browser live view / agent terminal event families (now retired) instead of the computer protocol, and the retirement criterion (admin only)';
14
15
  static examples = [
15
16
  '<%= config.bin %> machines computer-adoption',
16
17
  '<%= config.bin %> machines computer-adoption --json',
@@ -0,0 +1,25 @@
1
+ import { DedicatedLeaseCommand } from '../../../lib/dedicated-lease-command';
2
+ /**
3
+ * `skrr machines dedicated agent-browser` — do the agents on this machine get a
4
+ * browser? (OSK-13809)
5
+ *
6
+ * A new Dedicated Runtime gives its agents a browser by default; a machine
7
+ * created before that decision keeps what it had. This is the one switch for
8
+ * both directions, per machine: `--off` takes it away and it stays away across
9
+ * restarts, image updates and replacements; `--on` gives it to a machine that
10
+ * did not have it. Either change is written to the machine's audit record.
11
+ * With neither flag it prints the current setting.
12
+ */
13
+ export default class DedicatedMachinesAgentBrowser extends DedicatedLeaseCommand {
14
+ static description: string;
15
+ static examples: string[];
16
+ static args: {
17
+ lease: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
18
+ };
19
+ static flags: {
20
+ on: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
21
+ off: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
22
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
23
+ };
24
+ run(): Promise<void>;
25
+ }
@@ -0,0 +1,65 @@
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 agent-browser` — do the agents on this machine get a
8
+ * browser? (OSK-13809)
9
+ *
10
+ * A new Dedicated Runtime gives its agents a browser by default; a machine
11
+ * created before that decision keeps what it had. This is the one switch for
12
+ * both directions, per machine: `--off` takes it away and it stays away across
13
+ * restarts, image updates and replacements; `--on` gives it to a machine that
14
+ * did not have it. Either change is written to the machine's audit record.
15
+ * With neither flag it prints the current setting.
16
+ */
17
+ class DedicatedMachinesAgentBrowser extends dedicated_lease_command_1.DedicatedLeaseCommand {
18
+ static description = 'Show or change whether the agents on a Dedicated Runtime get a browser. On by default for new machines; --off turns it off for this machine and it stays off.';
19
+ static examples = [
20
+ '<%= config.bin %> machines dedicated agent-browser <lease-id>',
21
+ '<%= config.bin %> machines dedicated agent-browser <lease-id> --off',
22
+ '<%= config.bin %> machines dedicated agent-browser <lease-id> --on --json',
23
+ ];
24
+ static args = {
25
+ lease: core_1.Args.string({
26
+ description: dedicated_lease_command_1.DEDICATED_LEASE_ARG_DESCRIPTION,
27
+ required: true,
28
+ ignoreStdin: true,
29
+ }),
30
+ };
31
+ static flags = {
32
+ on: core_1.Flags.boolean({
33
+ description: "Give this machine's agents a browser. Recorded in the machine's audit record.",
34
+ exclusive: ['off'],
35
+ }),
36
+ off: core_1.Flags.boolean({
37
+ description: "Take the browser away from this machine's agents. Stays off until you turn it on. Recorded in the machine's audit record.",
38
+ exclusive: ['on'],
39
+ }),
40
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
41
+ };
42
+ async run() {
43
+ this.requireAuth();
44
+ const { args, flags } = await this.parse(DedicatedMachinesAgentBrowser);
45
+ const leaseId = await this.resolveLeaseArg(args.lease);
46
+ const scope = this.scopeFrom(flags);
47
+ const wantsChange = flags.on || flags.off;
48
+ const response = await this.callDedicated(() => wantsChange
49
+ ? (0, dedicated_machines_1.setDedicatedRuntimeAgentBrowser)(leaseId, Boolean(flags.on), scope)
50
+ : (0, dedicated_machines_1.getDedicatedRuntimeAgentBrowser)(leaseId, scope));
51
+ if (flags.json) {
52
+ this.log(JSON.stringify(response, null, 2));
53
+ return;
54
+ }
55
+ this.log(`Agent browser on ${response.leaseId || leaseId}: ${(0, dedicated_machines_1.describeDedicatedAgentBrowser)(response, leaseId)}`);
56
+ if (wantsChange && response.changed === false) {
57
+ this.log(' Already set that way; nothing changed.');
58
+ }
59
+ else if (wantsChange && response.effectiveOnNextReconnect && response.offered === null) {
60
+ // The line above already names the restart when a daemon is connected.
61
+ this.log(` Applies when the machine's daemon next reconnects; \`skrr machines dedicated restart ${leaseId}\` makes that now.`);
62
+ }
63
+ }
64
+ }
65
+ exports.default = DedicatedMachinesAgentBrowser;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveDedicatedExecCommand = resolveDedicatedExecCommand;
4
4
  const core_1 = require("@oclif/core");
5
5
  const base_command_1 = require("../../../base-command");
6
+ const api_fetch_1 = require("../../../lib/api-fetch");
6
7
  const shell_quote_1 = require("../../../lib/shell-quote");
7
8
  const hosted_machines_1 = require("../../../lib/hosted-machines");
8
9
  const dedicated_machines_1 = require("../../../lib/dedicated-machines");
@@ -144,23 +145,68 @@ class DedicatedMachinesExec extends base_command_1.BaseCommand {
144
145
  if (timeoutMs !== undefined && timeoutMs > dedicated_machines_1.DEDICATED_EXEC_MAX_TIMEOUT_MS) {
145
146
  this.error(`--timeout is at most ${dedicated_machines_1.DEDICATED_EXEC_MAX_TIMEOUT_MS / 60000}m. For longer work, start it in the background (nohup … &) or give it to an agent.`, { exit: 2 });
146
147
  }
148
+ // A stopped machine that this command woke answers "starting" until it is ready. That is a normal
149
+ // moment, not a failure: say so once, wait it out (bounded), and run the command.
150
+ const WAKE_CODE_STARTING = 'DEDICATED_RUNTIME_STARTING';
151
+ const WAKE_WAIT_BOUND_MS = 180_000;
152
+ const wakeStartedAt = Date.now();
153
+ let announcedWake = false;
147
154
  let result;
148
- try {
149
- result = await (0, dedicated_exec_1.runDedicatedExec)(id, { command, ...(flags.cwd ? { cwd: flags.cwd } : {}), ...(timeoutMs ? { timeoutMs } : {}) }, { workspaceId: flags.workspace, ...(requestId ? { requestId } : {}) });
150
- }
151
- catch (err) {
152
- if (err instanceof dedicated_exec_1.DedicatedExecContactLostError ||
153
- err instanceof dedicated_exec_1.DedicatedExecStartUnconfirmedError ||
154
- err instanceof dedicated_exec_1.DedicatedExecIdempotencyUnsupportedError) {
155
- this.error(err.message, { exit: 1, code: err.code });
155
+ for (;;) {
156
+ try {
157
+ result = await (0, dedicated_exec_1.runDedicatedExec)(id, {
158
+ command,
159
+ ...(flags.cwd ? { cwd: flags.cwd } : {}),
160
+ ...(timeoutMs ? { timeoutMs } : {}),
161
+ }, { workspaceId: flags.workspace, ...(requestId ? { requestId } : {}) });
162
+ break;
156
163
  }
157
- // Keep the API status, request id and explicit retry decision together.
158
- if ((0, base_command_1.apiRefusal)(err).body?.retryable === true)
164
+ catch (err) {
165
+ const refusal = (0, base_command_1.apiRefusal)(err);
166
+ if (refusal.code === WAKE_CODE_STARTING) {
167
+ if (Date.now() - wakeStartedAt > WAKE_WAIT_BOUND_MS) {
168
+ this.error(`${id} is still starting after ${Math.round(WAKE_WAIT_BOUND_MS / 1000)}s. Nothing was run. Check it with \`${this.config.bin} machines dedicated show ${id}\` and run the command again.`, { exit: 1, code: WAKE_CODE_STARTING });
169
+ }
170
+ if (!announcedWake && !flags.json) {
171
+ // The API masks a 503's `message`; the sentence lives in details.wake.detail.
172
+ const wake = refusal.body?.details
173
+ ?.wake;
174
+ const sentence = typeof wake?.detail === 'string' && wake.detail ? wake.detail : `${id} is starting.`;
175
+ process.stderr.write(`${sentence} Waiting for it, then running your command…\n`);
176
+ announcedWake = true;
177
+ }
178
+ const retryAfter = Number(refusal.body?.retryAfterSeconds);
179
+ const waitMs = Math.min(Math.max(Number.isFinite(retryAfter) ? retryAfter * 1000 : 5000, 2000), 10_000);
180
+ await new Promise((resolve) => setTimeout(resolve, waitMs));
181
+ continue;
182
+ }
183
+ if (err instanceof dedicated_exec_1.DedicatedExecContactLostError ||
184
+ err instanceof dedicated_exec_1.DedicatedExecStartUnconfirmedError ||
185
+ err instanceof dedicated_exec_1.DedicatedExecIdempotencyUnsupportedError) {
186
+ this.error(err.message, { exit: 1, code: err.code });
187
+ }
188
+ // The other wake outcomes (stopping, refused, timed out) carry their sentence as `message` and no
189
+ // `error`, which the generic handler does not read ("An unexpected error occurred"). Print it, and
190
+ // keep the status and the retry decision with it.
191
+ if (refusal.code?.startsWith('DEDICATED_RUNTIME_') &&
192
+ refusal.message &&
193
+ !refusal.body?.error) {
194
+ this.failWithCliError({
195
+ message: refusal.message,
196
+ code: refusal.code,
197
+ status: err instanceof api_fetch_1.ApiFetchError ? err.status : undefined,
198
+ exit: 1,
199
+ retryable: refusal.body?.retryable === true,
200
+ });
201
+ }
202
+ // Keep the API status, request id and explicit retry decision together.
203
+ if ((0, base_command_1.apiRefusal)(err).body?.retryable === true)
204
+ this.handleApiError(err);
205
+ const message = (0, dedicated_machines_1.formatDedicatedRuntimeApiError)(err);
206
+ if (message)
207
+ this.error(message, { exit: 1, code: (0, dedicated_machines_1.dedicatedRuntimeApiErrorCode)(err) });
159
208
  this.handleApiError(err);
160
- const message = (0, dedicated_machines_1.formatDedicatedRuntimeApiError)(err);
161
- if (message)
162
- this.error(message, { exit: 1, code: (0, dedicated_machines_1.dedicatedRuntimeApiErrorCode)(err) });
163
- this.handleApiError(err);
209
+ }
164
210
  }
165
211
  if (flags.json) {
166
212
  this.log(JSON.stringify(result, null, 2));
@@ -33,6 +33,7 @@ class DedicatedMachines extends core_1.Command {
33
33
  '<%= config.bin %> machines dedicated snapshot <lease-id> --wait',
34
34
  '<%= config.bin %> machines dedicated grow <lease-id> --storage-gb 200',
35
35
  '<%= config.bin %> machines dedicated spending-limit <lease-id> --cents 30000',
36
+ '<%= config.bin %> machines dedicated power set <lease-id> --policy manual',
36
37
  '<%= config.bin %> machines dedicated health-check <lease-id>',
37
38
  '<%= config.bin %> machines dedicated incident-close <lease-id>',
38
39
  '<%= config.bin %> machines dedicated service create <lease-id> --name worker -- node dist/worker.js',
@@ -41,6 +42,7 @@ class DedicatedMachines extends core_1.Command {
41
42
  ];
42
43
  async run() {
43
44
  const rows = [
45
+ ['power', 'when the machine may stop and start by itself (set)'],
44
46
  ['catalog', 'sizes, storage bounds and prices create accepts'],
45
47
  ['create', 'request a Dedicated Runtime'],
46
48
  ['list', 'list Dedicated Runtime leases'],
@@ -0,0 +1,13 @@
1
+ import { DedicatedLeaseCommand } from '../../../../lib/dedicated-lease-command';
2
+ /** `skrr machines dedicated power explain` — the latest PowerDecision, with the fix last. */
3
+ export default class DedicatedMachinesPowerExplain extends DedicatedLeaseCommand {
4
+ static description: string;
5
+ static examples: string[];
6
+ static args: {
7
+ lease: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
8
+ };
9
+ static flags: {
10
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,36 @@
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_power_1 = require("../../../../lib/dedicated-power");
6
+ /** `skrr machines dedicated power explain` — the latest PowerDecision, with the fix last. */
7
+ class DedicatedMachinesPowerExplain extends dedicated_lease_command_1.DedicatedLeaseCommand {
8
+ static description = 'Explain why a Dedicated Runtime stayed on, stopped or woke: the latest decision, its gate and reason, and what you can do next. Read-only.';
9
+ static examples = [
10
+ '<%= config.bin %> machines dedicated power explain <lease-id>',
11
+ '<%= config.bin %> machines dedicated power explain self --json',
12
+ ];
13
+ static args = {
14
+ lease: core_1.Args.string({
15
+ description: dedicated_lease_command_1.DEDICATED_LEASE_ARG_DESCRIPTION,
16
+ required: true,
17
+ ignoreStdin: true,
18
+ }),
19
+ };
20
+ static flags = {
21
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
22
+ };
23
+ async run() {
24
+ this.requireAuth();
25
+ const { args, flags } = await this.parse(DedicatedMachinesPowerExplain);
26
+ const leaseId = await this.resolveLeaseArg(args.lease);
27
+ const summary = await this.callDedicated(() => (0, dedicated_power_1.getDedicatedPowerSummary)(leaseId, this.scopeFrom(flags)));
28
+ if (flags.json) {
29
+ this.log(JSON.stringify(summary, null, 2));
30
+ return;
31
+ }
32
+ for (const line of (0, dedicated_power_1.describePowerExplanation)(summary))
33
+ this.log(line);
34
+ }
35
+ }
36
+ exports.default = DedicatedMachinesPowerExplain;
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ /**
3
+ * `skrr machines dedicated power` — when a Dedicated Runtime may stop and start
4
+ * on its own. `set` is the standing policy; more verbs arrive with the power card.
5
+ */
6
+ export default class DedicatedMachinesPower extends Command {
7
+ static description: string;
8
+ static examples: string[];
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ /**
5
+ * `skrr machines dedicated power` — when a Dedicated Runtime may stop and start
6
+ * on its own. `set` is the standing policy; more verbs arrive with the power card.
7
+ */
8
+ class DedicatedMachinesPower extends core_1.Command {
9
+ static description = 'Power policy of a Dedicated Runtime — when it may stop and start on its own. Files are preserved across stops.\n\nSubcommands:\n show state, policy, holders, usage, next wake\n explain why it stayed on, stopped or woke, and the fix\n set always_on | on_demand | manual (+ --idle-after, --budget-hours)\n keep-awake --for <duration> | --until <iso> | --clear';
10
+ static examples = [
11
+ '<%= config.bin %> machines dedicated power set <lease-id> --policy manual',
12
+ '<%= config.bin %> machines dedicated power set <lease-id> --policy on_demand --idle-after 60',
13
+ ];
14
+ async run() {
15
+ this.log('skrr machines dedicated power commands:');
16
+ this.log(' skrr machines dedicated power show state, policy, holders, usage, next wake');
17
+ this.log(' skrr machines dedicated power explain why it stayed on, stopped or woke, and the fix');
18
+ this.log(' skrr machines dedicated power set always_on | on_demand | manual (+ --idle-after)');
19
+ this.log(' skrr machines dedicated power keep-awake --for <duration> | --until <iso> | --clear');
20
+ this.log('');
21
+ this.log('Every command takes a lease id (or `self` on the machine) and --json.');
22
+ }
23
+ }
24
+ exports.default = DedicatedMachinesPower;
@@ -0,0 +1,20 @@
1
+ import { DedicatedLeaseCommand } from '../../../../lib/dedicated-lease-command';
2
+ /**
3
+ * `skrr machines dedicated power keep-awake` — a temporary override that forbids
4
+ * AUTOMATIC stop. It is not a policy, it expires by itself, and it never starts a
5
+ * machine (on a stopped machine it means "do not auto-stop once running").
6
+ */
7
+ export default class DedicatedMachinesPowerKeepAwake extends DedicatedLeaseCommand {
8
+ static description: string;
9
+ static examples: string[];
10
+ static args: {
11
+ lease: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
12
+ };
13
+ static flags: {
14
+ for: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
+ until: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
16
+ clear: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
17
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
18
+ };
19
+ run(): Promise<void>;
20
+ }
@@ -0,0 +1,69 @@
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_keep_awake_1 = require("../../../../lib/dedicated-keep-awake");
6
+ /**
7
+ * `skrr machines dedicated power keep-awake` — a temporary override that forbids
8
+ * AUTOMATIC stop. It is not a policy, it expires by itself, and it never starts a
9
+ * machine (on a stopped machine it means "do not auto-stop once running").
10
+ */
11
+ class DedicatedMachinesPowerKeepAwake extends dedicated_lease_command_1.DedicatedLeaseCommand {
12
+ static description = 'Keep a Dedicated Runtime from stopping on its own for a while: --for 2h, --until <iso> or --clear. It expires by itself, never starts the machine and does not change the power policy. Files are preserved across stops.';
13
+ static examples = [
14
+ '<%= config.bin %> machines dedicated power keep-awake <lease-id> --for 2h',
15
+ '<%= config.bin %> machines dedicated power keep-awake <lease-id> --until 2026-10-10T18:00:00Z',
16
+ '<%= config.bin %> machines dedicated power keep-awake <lease-id> --clear --json',
17
+ ];
18
+ static args = {
19
+ lease: core_1.Args.string({
20
+ description: dedicated_lease_command_1.DEDICATED_LEASE_ARG_DESCRIPTION,
21
+ required: true,
22
+ ignoreStdin: true,
23
+ }),
24
+ };
25
+ static flags = {
26
+ for: core_1.Flags.string({
27
+ description: 'How long, such as 90m, 2h or 3d (5 minutes to 7 days). A bare number is minutes.',
28
+ exclusive: ['until', 'clear'],
29
+ }),
30
+ until: core_1.Flags.string({
31
+ description: 'Keep awake until this ISO 8601 date (5 minutes to 7 days from now).',
32
+ exclusive: ['for', 'clear'],
33
+ }),
34
+ clear: core_1.Flags.boolean({
35
+ description: 'Cancel keep-awake so the machine follows its power policy again.',
36
+ exclusive: ['for', 'until'],
37
+ }),
38
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
39
+ };
40
+ async run() {
41
+ this.requireAuth();
42
+ const { args, flags } = await this.parse(DedicatedMachinesPowerKeepAwake);
43
+ if (!flags.for && !flags.until && !flags.clear) {
44
+ this.error('Choose --for <duration>, --until <iso-date> or --clear.', { exit: 2 });
45
+ }
46
+ let request = null;
47
+ try {
48
+ if (flags.for)
49
+ request = { forMinutes: (0, dedicated_keep_awake_1.parseKeepAwakeDuration)(flags.for) };
50
+ else if (flags.until)
51
+ request = { until: (0, dedicated_keep_awake_1.parseKeepAwakeUntil)(flags.until) };
52
+ }
53
+ catch (err) {
54
+ this.error(err.message, { exit: 2 });
55
+ }
56
+ const leaseId = await this.resolveLeaseArg(args.lease);
57
+ const scope = this.scopeFrom(flags);
58
+ const response = await this.callDedicated(() => request
59
+ ? (0, dedicated_keep_awake_1.setDedicatedKeepAwake)(leaseId, request, scope)
60
+ : (0, dedicated_keep_awake_1.clearDedicatedKeepAwake)(leaseId, scope));
61
+ if (flags.json) {
62
+ this.log(JSON.stringify({ ok: true, ...response }, null, 2));
63
+ return;
64
+ }
65
+ this.log(`Dedicated Runtime ${response.leaseId} ${(0, dedicated_keep_awake_1.describeKeepAwake)(response.keepAwake)}.`);
66
+ this.log('Nothing was started or stopped.');
67
+ }
68
+ }
69
+ exports.default = DedicatedMachinesPowerKeepAwake;
@@ -0,0 +1,23 @@
1
+ import { DedicatedLeaseCommand } from '../../../../lib/dedicated-lease-command';
2
+ /**
3
+ * `skrr machines dedicated power set` — the standing power policy.
4
+ *
5
+ * Changing the policy starts and stops nothing; it records what the platform may
6
+ * do on its own from now on. Machines that never had a policy set stay
7
+ * `always_on`.
8
+ */
9
+ export default class DedicatedMachinesPowerSet extends DedicatedLeaseCommand {
10
+ static description: string;
11
+ static examples: string[];
12
+ static args: {
13
+ lease: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
14
+ };
15
+ static flags: {
16
+ policy: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
17
+ 'idle-after': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
18
+ 'budget-hours': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
19
+ 'no-budget': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
20
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
21
+ };
22
+ run(): Promise<void>;
23
+ }
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const data_provider_1 = require("@skrr-ai/data-provider");
5
+ const dedicated_lease_command_1 = require("../../../../lib/dedicated-lease-command");
6
+ const dedicated_power_1 = require("../../../../lib/dedicated-power");
7
+ /**
8
+ * `skrr machines dedicated power set` — the standing power policy.
9
+ *
10
+ * Changing the policy starts and stops nothing; it records what the platform may
11
+ * do on its own from now on. Machines that never had a policy set stay
12
+ * `always_on`.
13
+ */
14
+ class DedicatedMachinesPowerSet extends dedicated_lease_command_1.DedicatedLeaseCommand {
15
+ static description = 'Set when a Dedicated Runtime may stop and start on its own: always_on, on_demand or manual. Changing the policy starts and stops nothing. Files are preserved across stops.';
16
+ static examples = [
17
+ '<%= config.bin %> machines dedicated power set <lease-id> --policy manual',
18
+ '<%= config.bin %> machines dedicated power set <lease-id> --policy on_demand --idle-after 60',
19
+ '<%= config.bin %> machines dedicated power set <lease-id> --budget-hours 200',
20
+ '<%= config.bin %> machines dedicated power set <lease-id> --no-budget',
21
+ '<%= config.bin %> machines dedicated power set self --policy always_on --json',
22
+ ];
23
+ static args = {
24
+ lease: core_1.Args.string({
25
+ description: dedicated_lease_command_1.DEDICATED_LEASE_ARG_DESCRIPTION,
26
+ required: true,
27
+ ignoreStdin: true,
28
+ }),
29
+ };
30
+ static flags = {
31
+ policy: core_1.Flags.string({
32
+ description: 'always_on: never stops by itself (default). on_demand: stops when idle, starts when work arrives. manual: only you start and stop it.',
33
+ options: [...data_provider_1.DEDICATED_POWER_POLICIES],
34
+ }),
35
+ 'idle-after': core_1.Flags.integer({
36
+ description: `Minutes idle before an on_demand machine stops (${data_provider_1.DEDICATED_POWER_IDLE_AFTER_MINUTES_MIN}-${data_provider_1.DEDICATED_POWER_IDLE_AFTER_MINUTES_MAX}). on_demand only.`,
37
+ min: data_provider_1.DEDICATED_POWER_IDLE_AFTER_MINUTES_MIN,
38
+ max: data_provider_1.DEDICATED_POWER_IDLE_AFTER_MINUTES_MAX,
39
+ }),
40
+ 'budget-hours': core_1.Flags.string({
41
+ description: `Hard monthly compute-hour budget (greater than 0, at most ${data_provider_1.DEDICATED_POWER_BUDGET_HOURS_MAX}). At the budget, automatic starts are refused until the month resets or you raise it. A running machine is never stopped by it, and your own start is never blocked.`,
42
+ exclusive: ['no-budget'],
43
+ }),
44
+ 'no-budget': core_1.Flags.boolean({
45
+ description: 'Remove the monthly compute-hour budget (no limit).',
46
+ exclusive: ['budget-hours'],
47
+ }),
48
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
49
+ };
50
+ async run() {
51
+ this.requireAuth();
52
+ const { args, flags } = await this.parse(DedicatedMachinesPowerSet);
53
+ let budget;
54
+ if (flags['no-budget'])
55
+ budget = null;
56
+ else if (flags['budget-hours'] !== undefined) {
57
+ const raw = flags['budget-hours'].trim();
58
+ budget = /^\d+(\.\d+)?$/.test(raw) ? Number(raw) : Number.NaN;
59
+ if (!(budget > 0) || budget > data_provider_1.DEDICATED_POWER_BUDGET_HOURS_MAX) {
60
+ this.error(`--budget-hours must be a number greater than 0 and at most ${data_provider_1.DEDICATED_POWER_BUDGET_HOURS_MAX}. Use --no-budget to remove the budget.`, { exit: 2 });
61
+ }
62
+ }
63
+ if (flags.policy === undefined && flags['idle-after'] === undefined && budget === undefined) {
64
+ this.error('Nothing to change. Pass --policy <always_on|on_demand|manual>, --idle-after <minutes> (on_demand only), or --budget-hours <n> / --no-budget.', { exit: 2 });
65
+ }
66
+ if (flags['idle-after'] !== undefined &&
67
+ flags.policy !== undefined &&
68
+ flags.policy !== 'on_demand') {
69
+ this.error('--idle-after applies to --policy on_demand only.', { exit: 2 });
70
+ }
71
+ const leaseId = await this.resolveLeaseArg(args.lease);
72
+ const outcome = await this.callDedicated(() => (0, dedicated_power_1.setDedicatedPowerPolicy)(leaseId, {
73
+ ...(flags.policy ? { policy: flags.policy } : {}),
74
+ ...(flags['idle-after'] !== undefined ? { idleAfterMinutes: flags['idle-after'] } : {}),
75
+ ...(budget !== undefined ? { budgetHoursPerMonth: budget } : {}),
76
+ }, this.scopeFrom(flags)));
77
+ if (!outcome.ok) {
78
+ const { refusal } = outcome;
79
+ if (flags.json) {
80
+ this.log(JSON.stringify({ ok: false, ...refusal }, null, 2));
81
+ }
82
+ else {
83
+ this.log(`on_demand is not available for ${leaseId}: ${refusal.reason}`);
84
+ this.log(` ${refusal.detail}`);
85
+ this.log(` Fix: ${refusal.fix}`);
86
+ this.log(' The power policy was not changed.');
87
+ }
88
+ this.exit(1);
89
+ }
90
+ const { response } = outcome;
91
+ if (flags.json) {
92
+ this.log(JSON.stringify({ ok: true, ...response }, null, 2));
93
+ return;
94
+ }
95
+ const verb = response.changed ? 'set to' : 'already';
96
+ // Whether anything will actually stop the machine depends on the platform, not on this write: ask, so
97
+ // the sentence below is true. Best effort: a failed read leaves the neutral wording.
98
+ const autoStopMode = await (0, dedicated_power_1.getDedicatedPowerSummary)(leaseId, this.scopeFrom(flags))
99
+ .then((summary) => summary.autoStopMode)
100
+ .catch(() => undefined);
101
+ this.log(`Dedicated Runtime ${response.leaseId} power policy ${verb} ${(0, dedicated_power_1.describePowerPolicy)(response.power, autoStopMode)}.`);
102
+ this.log((0, dedicated_power_1.describeBudget)(response.power));
103
+ this.log('Nothing was started or stopped.');
104
+ }
105
+ }
106
+ exports.default = DedicatedMachinesPowerSet;
@@ -0,0 +1,13 @@
1
+ import { DedicatedLeaseCommand } from '../../../../lib/dedicated-lease-command';
2
+ /** `skrr machines dedicated power show` — the read-only power card. */
3
+ export default class DedicatedMachinesPowerShow extends DedicatedLeaseCommand {
4
+ static description: string;
5
+ static examples: string[];
6
+ static args: {
7
+ lease: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
8
+ };
9
+ static flags: {
10
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,36 @@
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_power_1 = require("../../../../lib/dedicated-power");
6
+ /** `skrr machines dedicated power show` — the read-only power card. */
7
+ class DedicatedMachinesPowerShow extends dedicated_lease_command_1.DedicatedLeaseCommand {
8
+ static description = 'Show a Dedicated Runtime power state: policy, why it is on or off, who is holding it, this month hours and cost, and the next expected wake. Read-only.';
9
+ static examples = [
10
+ '<%= config.bin %> machines dedicated power show <lease-id>',
11
+ '<%= config.bin %> machines dedicated power show self --json',
12
+ ];
13
+ static args = {
14
+ lease: core_1.Args.string({
15
+ description: dedicated_lease_command_1.DEDICATED_LEASE_ARG_DESCRIPTION,
16
+ required: true,
17
+ ignoreStdin: true,
18
+ }),
19
+ };
20
+ static flags = {
21
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
22
+ };
23
+ async run() {
24
+ this.requireAuth();
25
+ const { args, flags } = await this.parse(DedicatedMachinesPowerShow);
26
+ const leaseId = await this.resolveLeaseArg(args.lease);
27
+ const summary = await this.callDedicated(() => (0, dedicated_power_1.getDedicatedPowerSummary)(leaseId, this.scopeFrom(flags)));
28
+ if (flags.json) {
29
+ this.log(JSON.stringify(summary, null, 2));
30
+ return;
31
+ }
32
+ for (const line of (0, dedicated_power_1.describePowerSummary)(summary))
33
+ this.log(line);
34
+ }
35
+ }
36
+ exports.default = DedicatedMachinesPowerShow;
@@ -6,7 +6,7 @@ const daemon_installer_1 = require("../../../lib/daemon-installer");
6
6
  const dedicated_machines_1 = require("../../../lib/dedicated-machines");
7
7
  const harnesses_1 = require("../../../lib/harnesses");
8
8
  class DedicatedMachinesShow extends dedicated_lease_command_1.DedicatedLeaseCommand {
9
- static description = 'Show one Dedicated Runtime lease: state, size, workspace, spend against the cap, health, deletion clock and the engines its daemon registered';
9
+ static description = 'Show one Dedicated Runtime lease: state, size, workspace, spend against the cap, health, deletion clock, whether its agents get a browser, and the engines its daemon registered';
10
10
  static examples = [
11
11
  '<%= config.bin %> machines dedicated show <lease-id>',
12
12
  '<%= config.bin %> machines dedicated show <lease-id> --json',
@@ -47,6 +47,17 @@ class DedicatedMachinesShow extends dedicated_lease_command_1.DedicatedLeaseComm
47
47
  // which is what `skrrd update --check` on the machine reports (OSK-12153).
48
48
  // Best-effort: an unreachable feed is said, never read as "none newer".
49
49
  const latestDaemonRelease = lease.health?.image ? await readLatestDaemonRelease() : null;
50
+ // Whether the agents on this machine get a browser (OSK-13809). Its own
51
+ // route, because the setting lives on the machine's allow-list, not the
52
+ // lease. Best-effort like the reads above, and an unreadable answer is
53
+ // printed as unknown, never as off.
54
+ let agentBrowser;
55
+ try {
56
+ agentBrowser = await (0, dedicated_machines_1.getDedicatedRuntimeAgentBrowser)(leaseId, this.scopeFrom(flags));
57
+ }
58
+ catch (err) {
59
+ agentBrowser = { error: err?.message || 'unreadable' };
60
+ }
50
61
  if (flags.json) {
51
62
  const engines = (0, dedicated_machines_1.dedicatedLeaseHarnesses)(lease, harnesses).map((harness) => ({
52
63
  harnessId: harness._id,
@@ -57,11 +68,15 @@ class DedicatedMachinesShow extends dedicated_lease_command_1.DedicatedLeaseComm
57
68
  this.log(JSON.stringify({
58
69
  ...response,
59
70
  harnesses: engines,
71
+ agentBrowser,
60
72
  ...(latestDaemonRelease ? { latestDaemonRelease } : {}),
61
73
  }, null, 2));
62
74
  return;
63
75
  }
64
- for (const line of (0, dedicated_machines_1.describeDedicatedLease)(lease, harnesses, { latestDaemonRelease })) {
76
+ for (const line of (0, dedicated_machines_1.describeDedicatedLease)(lease, harnesses, {
77
+ latestDaemonRelease,
78
+ agentBrowser,
79
+ })) {
65
80
  this.log(line);
66
81
  }
67
82
  }