@skrr-ai/cli 0.1.91 → 0.1.93
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.d.ts +44 -0
- package/dist/base-command.js +96 -0
- package/dist/commands/agents/badge.d.ts +41 -0
- package/dist/commands/agents/badge.js +158 -0
- package/dist/commands/agents/create.d.ts +24 -0
- package/dist/commands/agents/create.js +212 -0
- package/dist/commands/agents/embed.d.ts +20 -0
- package/dist/commands/agents/embed.js +61 -0
- package/dist/commands/agents/share.d.ts +27 -0
- package/dist/commands/agents/share.js +100 -0
- package/dist/commands/agents/vanity.d.ts +21 -0
- package/dist/commands/agents/vanity.js +77 -0
- package/dist/commands/agents/visibility.d.ts +21 -1
- package/dist/commands/agents/visibility.js +112 -0
- package/dist/commands/commands.d.ts +1 -0
- package/dist/commands/commands.js +22 -9
- package/dist/commands/earnings/attributions.d.ts +17 -0
- package/dist/commands/earnings/attributions.js +82 -0
- package/dist/commands/earnings/index.js +2 -1
- package/dist/commands/generate-recovery-code.js +4 -3
- package/dist/commands/github/allow-tools.d.ts +1 -0
- package/dist/commands/github/app/install.d.ts +1 -0
- package/dist/commands/github/app/status.d.ts +1 -0
- package/dist/commands/github/connect.d.ts +1 -0
- package/dist/commands/github/connections.d.ts +1 -0
- package/dist/commands/github/disconnect.d.ts +1 -0
- package/dist/commands/github/finalize.d.ts +1 -0
- package/dist/commands/github/reconnect.d.ts +1 -0
- package/dist/commands/github/run.d.ts +1 -0
- package/dist/commands/github/tools.d.ts +1 -0
- package/dist/commands/integrations/connections/connect.d.ts +1 -0
- package/dist/commands/integrations/connections/disconnect.d.ts +1 -0
- package/dist/commands/integrations/connections/finalize.d.ts +1 -0
- package/dist/commands/integrations/connections/list.d.ts +1 -0
- package/dist/commands/integrations/connections/reconnect.d.ts +1 -0
- package/dist/commands/integrations/execute.d.ts +1 -0
- package/dist/commands/integrations/search.d.ts +1 -0
- package/dist/commands/integrations/toolkits.d.ts +1 -0
- package/dist/commands/integrations/tools/allow.d.ts +1 -0
- package/dist/commands/integrations/tools/list.d.ts +1 -0
- package/dist/commands/login.js +12 -0
- package/dist/commands/machines/dedicated/logs.d.ts +19 -0
- package/dist/commands/machines/dedicated/logs.js +103 -0
- package/dist/commands/machines/dedicated/power/index.js +3 -2
- package/dist/commands/machines/dedicated/power/set.js +1 -1
- package/dist/commands/machines/dedicated/power/waiting.d.ts +13 -0
- package/dist/commands/machines/dedicated/power/waiting.js +36 -0
- package/dist/commands/open.d.ts +24 -0
- package/dist/commands/open.js +74 -0
- package/dist/commands/projects/archive.d.ts +1 -0
- package/dist/commands/projects/archive.js +23 -0
- package/dist/commands/projects/delete.d.ts +1 -0
- package/dist/commands/projects/delete.js +23 -0
- package/dist/commands/projects/list.d.ts +3 -0
- package/dist/commands/projects/list.js +12 -2
- package/dist/commands/spaces/actions/add.js +4 -3
- package/dist/commands/spaces/actions/available.js +3 -2
- package/dist/commands/spaces/actions/list.js +5 -4
- package/dist/commands/spaces/actions/replace.js +6 -5
- package/dist/commands/spaces/archive.js +3 -2
- package/dist/commands/spaces/auto-executor/preview.js +4 -3
- package/dist/commands/spaces/auto-executor/run.js +4 -3
- package/dist/commands/spaces/auto-executor/runs.js +3 -2
- package/dist/commands/spaces/auto-executor/update.js +4 -3
- package/dist/commands/spaces/bootstrap.js +3 -2
- package/dist/commands/spaces/briefs/delete.js +3 -2
- package/dist/commands/spaces/briefs/get.js +3 -2
- package/dist/commands/spaces/briefs/list.js +3 -2
- package/dist/commands/spaces/briefs/set.js +5 -4
- package/dist/commands/spaces/capacity.js +5 -4
- package/dist/commands/spaces/conversations.js +3 -2
- package/dist/commands/spaces/cycles/create.js +3 -2
- package/dist/commands/spaces/cycles/graph.js +2 -1
- package/dist/commands/spaces/cycles/list.js +3 -2
- package/dist/commands/spaces/cycles/settings.js +4 -3
- package/dist/commands/spaces/cycles/show.js +3 -2
- package/dist/commands/spaces/cycles/update.js +3 -2
- package/dist/commands/spaces/delete.js +4 -3
- package/dist/commands/spaces/expertise-suggestions.js +4 -3
- package/dist/commands/spaces/files/delete.js +3 -2
- package/dist/commands/spaces/files/folders/create.js +3 -2
- package/dist/commands/spaces/files/folders/delete.js +3 -2
- package/dist/commands/spaces/files/folders/list.js +3 -2
- package/dist/commands/spaces/files/folders/update.js +3 -2
- package/dist/commands/spaces/files/list.js +3 -2
- package/dist/commands/spaces/files/move.js +3 -2
- package/dist/commands/spaces/files/rename.js +3 -2
- package/dist/commands/spaces/files/upload.js +6 -5
- package/dist/commands/spaces/github-automations/set.js +3 -2
- package/dist/commands/spaces/github-automations/show.js +3 -2
- package/dist/commands/spaces/goals.js +2 -1
- package/dist/commands/spaces/heartbeats/create.js +4 -3
- package/dist/commands/spaces/heartbeats/delete.js +4 -3
- package/dist/commands/spaces/heartbeats/list.js +4 -3
- package/dist/commands/spaces/heartbeats/status.js +3 -2
- package/dist/commands/spaces/heartbeats/update.js +4 -3
- package/dist/commands/spaces/insights.js +5 -4
- package/dist/commands/spaces/labels/add.js +4 -3
- package/dist/commands/spaces/labels/list.js +2 -1
- package/dist/commands/spaces/labels/remove.js +4 -3
- package/dist/commands/spaces/list.d.ts +3 -0
- package/dist/commands/spaces/list.js +11 -2
- package/dist/commands/spaces/live/cards/create.js +3 -2
- package/dist/commands/spaces/live/cards/list.js +3 -2
- package/dist/commands/spaces/live/cards/reorder.js +7 -2
- package/dist/commands/spaces/live/scene.js +4 -3
- package/dist/commands/spaces/members/add.js +7 -6
- package/dist/commands/spaces/members/list.js +4 -3
- package/dist/commands/spaces/members/remove.js +7 -6
- package/dist/commands/spaces/move.js +3 -2
- package/dist/commands/spaces/pin.js +5 -4
- package/dist/commands/spaces/preferences/show.js +4 -3
- package/dist/commands/spaces/preferences/tabs.js +4 -3
- package/dist/commands/spaces/revisions.js +3 -2
- package/dist/commands/spaces/room/ensure.js +5 -4
- package/dist/commands/spaces/room/messages.js +3 -2
- package/dist/commands/spaces/room/show.js +5 -4
- package/dist/commands/spaces/skills/add.js +4 -3
- package/dist/commands/spaces/skills/list.js +3 -2
- package/dist/commands/spaces/skills/pin.js +4 -3
- package/dist/commands/spaces/skills/remove.js +4 -3
- package/dist/commands/spaces/snapshot.js +3 -2
- package/dist/commands/spaces/states/archive.js +3 -2
- package/dist/commands/spaces/states/create.js +3 -2
- package/dist/commands/spaces/states/list.js +3 -2
- package/dist/commands/spaces/states/reorder.js +2 -1
- package/dist/commands/spaces/states/update.js +3 -2
- package/dist/commands/spaces/summary.js +4 -3
- package/dist/commands/spaces/tasks.d.ts +3 -0
- package/dist/commands/spaces/tasks.js +14 -3
- package/dist/commands/spaces/triggers/delete.js +5 -4
- package/dist/commands/spaces/triggers/set.js +4 -3
- package/dist/commands/spaces/triggers/show.js +4 -3
- package/dist/commands/spaces/unarchive.js +3 -2
- package/dist/commands/spaces/update.js +5 -4
- package/dist/commands/spaces/views/create.js +3 -2
- package/dist/commands/spaces/views/list.js +3 -2
- package/dist/commands/spaces/views/reorder.js +6 -3
- package/dist/commands/spaces/views/subscribe.js +2 -1
- package/dist/commands/spaces/views/subscriptions.js +1 -0
- package/dist/commands/spaces/views/unsubscribe.js +2 -1
- package/dist/commands/spaces/widgets/add.js +4 -3
- package/dist/commands/spaces/widgets/list.js +3 -2
- package/dist/commands/spaces/widgets/remove.js +5 -4
- package/dist/commands/spaces/work-graph.js +2 -1
- package/dist/commands/store/install.d.ts +1 -1
- package/dist/commands/store/install.js +24 -8
- package/dist/commands/store/show.d.ts +25 -0
- package/dist/commands/store/show.js +203 -0
- package/dist/commands/store/stats.d.ts +33 -0
- package/dist/commands/store/stats.js +258 -0
- package/dist/commands/tasks/actions/attach.js +1 -1
- package/dist/commands/tasks/actions/detach.js +4 -3
- package/dist/commands/tasks/activity.js +3 -2
- package/dist/commands/tasks/ancestors.js +2 -1
- package/dist/commands/tasks/approvals/create.js +2 -1
- package/dist/commands/tasks/approvals/delete.js +3 -2
- package/dist/commands/tasks/approvals/list.js +5 -4
- package/dist/commands/tasks/approvals/resolve.js +2 -1
- package/dist/commands/tasks/archive.js +3 -2
- package/dist/commands/tasks/assign.js +4 -3
- package/dist/commands/tasks/attachments/delete.js +3 -2
- package/dist/commands/tasks/attachments/download.d.ts +1 -0
- package/dist/commands/tasks/attachments/download.js +20 -1
- package/dist/commands/tasks/attachments/list.js +2 -1
- package/dist/commands/tasks/attachments/set-role.js +2 -1
- package/dist/commands/tasks/attachments/upload.js +2 -1
- package/dist/commands/tasks/bulk-update.d.ts +1 -0
- package/dist/commands/tasks/bulk-update.js +106 -15
- package/dist/commands/tasks/cancel-cascade.d.ts +1 -0
- package/dist/commands/tasks/cancel-cascade.js +13 -3
- package/dist/commands/tasks/cascade-status.js +2 -1
- package/dist/commands/tasks/chat/send.d.ts +44 -0
- package/dist/commands/tasks/chat/send.js +112 -0
- package/dist/commands/tasks/checkout.js +3 -2
- package/dist/commands/tasks/children.js +2 -1
- package/dist/commands/tasks/comments/add.js +7 -6
- package/dist/commands/tasks/comments/anchor.js +8 -7
- package/dist/commands/tasks/comments/delete.js +3 -2
- package/dist/commands/tasks/comments/list.js +2 -1
- package/dist/commands/tasks/comments/reopen.js +3 -2
- package/dist/commands/tasks/comments/resolve.js +3 -2
- package/dist/commands/tasks/create-tree.d.ts +63 -0
- package/dist/commands/tasks/create-tree.js +197 -4
- package/dist/commands/tasks/delete.js +5 -4
- package/dist/commands/tasks/descendants.js +2 -1
- package/dist/commands/tasks/dri-plan.js +3 -2
- package/dist/commands/tasks/dri-run.js +3 -2
- package/dist/commands/tasks/dri-status.js +2 -1
- package/dist/commands/tasks/duplicate-pipeline.js +2 -1
- package/dist/commands/tasks/execution-summary.js +2 -1
- package/dist/commands/tasks/execution-timeline.js +2 -1
- package/dist/commands/tasks/fork.js +1 -0
- package/dist/commands/tasks/forward.js +4 -3
- package/dist/commands/tasks/handover.js +1 -0
- package/dist/commands/tasks/interrupt.js +3 -2
- package/dist/commands/tasks/labels/attach.js +4 -3
- package/dist/commands/tasks/labels/detach.js +4 -3
- package/dist/commands/tasks/labels/suggest.js +5 -4
- package/dist/commands/tasks/list.d.ts +27 -1
- package/dist/commands/tasks/list.js +101 -3
- package/dist/commands/tasks/move.js +4 -3
- package/dist/commands/tasks/output.js +6 -5
- package/dist/commands/tasks/pause-schedule.js +3 -2
- package/dist/commands/tasks/promote.js +1 -0
- package/dist/commands/tasks/prompt-log.js +2 -1
- package/dist/commands/tasks/release.js +5 -4
- package/dist/commands/tasks/remind.js +2 -1
- package/dist/commands/tasks/replay.js +3 -2
- package/dist/commands/tasks/report.js +1 -0
- package/dist/commands/tasks/resume-schedule.js +3 -2
- package/dist/commands/tasks/retry-schedule.js +3 -2
- package/dist/commands/tasks/retry.js +10 -9
- package/dist/commands/tasks/revisions.js +2 -1
- package/dist/commands/tasks/runs.js +6 -5
- package/dist/commands/tasks/schedule.js +3 -2
- package/dist/commands/tasks/self-schedule.js +6 -5
- package/dist/commands/tasks/skills/pin.js +3 -2
- package/dist/commands/tasks/skills/unpin.js +3 -2
- package/dist/commands/tasks/snooze.js +6 -5
- package/dist/commands/tasks/start-all.js +5 -4
- package/dist/commands/tasks/subscribe.js +1 -0
- package/dist/commands/tasks/tags/add.js +4 -3
- package/dist/commands/tasks/tags/remove.js +4 -3
- package/dist/commands/tasks/timeline.js +3 -2
- package/dist/commands/tasks/today.d.ts +4 -1
- package/dist/commands/tasks/today.js +12 -2
- package/dist/commands/tasks/transcript.js +6 -5
- package/dist/commands/tasks/unschedule.js +3 -2
- package/dist/commands/tasks/unsnooze.js +3 -2
- package/dist/commands/tasks/unsubscribe.js +2 -1
- package/dist/commands/tasks/update.js +5 -4
- package/dist/commands/tasks/wait.js +5 -4
- package/dist/lib/agent-distribution.d.ts +37 -0
- package/dist/lib/agent-distribution.js +63 -0
- package/dist/lib/agent-ref.d.ts +69 -0
- package/dist/lib/agent-ref.js +168 -0
- package/dist/lib/api-fetch.d.ts +2 -0
- package/dist/lib/api-fetch.js +14 -3
- package/dist/lib/command-hygiene.d.ts +13 -0
- package/dist/lib/command-hygiene.js +62 -2
- package/dist/lib/dedicated-power.d.ts +16 -1
- package/dist/lib/dedicated-power.js +153 -2
- package/dist/lib/dry-run-plans.d.ts +50 -0
- package/dist/lib/dry-run-plans.js +85 -0
- package/dist/lib/json-output.d.ts +31 -0
- package/dist/lib/json-output.js +78 -0
- package/dist/lib/list-output.d.ts +75 -0
- package/dist/lib/list-output.js +266 -0
- package/dist/lib/machine-daemon-log.d.ts +36 -0
- package/dist/lib/machine-daemon-log.js +78 -0
- package/dist/lib/node-adapter.js +10 -1
- package/dist/lib/open-target.d.ts +12 -0
- package/dist/lib/open-target.js +108 -0
- package/dist/lib/rate-limit-retry.d.ts +45 -0
- package/dist/lib/rate-limit-retry.js +88 -0
- package/dist/lib/store-listing.d.ts +45 -0
- package/dist/lib/store-listing.js +186 -0
- package/dist/lib/task-batch.d.ts +67 -0
- package/dist/lib/task-batch.js +227 -0
- package/dist/lib/terminal-qr.d.ts +55 -0
- package/dist/lib/terminal-qr.js +119 -0
- package/dist/lib/web-url.d.ts +11 -0
- package/dist/lib/web-url.js +24 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.d.ts +68 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.js +47 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.d.ts +68 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.js +46 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +6615 -6112
- package/oclif.manifest.json +41499 -32585
- package/package.json +2 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type Attribution, type DistributionChannel, type ResolveAgentVanityResponse, type ResolveDistributionCodeResponse } from '@skrr-ai/data-provider';
|
|
2
|
+
/**
|
|
3
|
+
* THE ONE PLACE A STORE AGENT REFERENCE IS RESOLVED.
|
|
4
|
+
*
|
|
5
|
+
* `skrr store install|show|stats`, `skrr agents share|badge` and `skrr open`
|
|
6
|
+
* read the positional through `resolveAgentRef`, never by using the raw string
|
|
7
|
+
* as an id. Accepted, in this order:
|
|
8
|
+
*
|
|
9
|
+
* - an agent id, typed as-is (`agent_abc`) — no attribution: nobody shared it;
|
|
10
|
+
* - any first-party link `parseSkrrLink` recognises as an agent
|
|
11
|
+
* (`https://skrr.ai/a/<id>[/slug]`, `/store/agents/<id>`, `/agent/<id>`,
|
|
12
|
+
* `skrr://agent/<id>`), keeping the link's own `?s=` / `?ch=`;
|
|
13
|
+
* - a first-party link that carries only a share code (`/?s=<code>`), or
|
|
14
|
+
* names something the CLI cannot look up locally but carries a code — the
|
|
15
|
+
* code is resolved through the server (`resolveDistributionCode`);
|
|
16
|
+
* - a vanity address, `@handle/agent-slug` or `…/@handle/agent-slug` — the
|
|
17
|
+
* alias is resolved through the server's public vanity endpoint (a retired
|
|
18
|
+
* handle or slug still resolves; agent-distribution-2026-10-08, "Vanity
|
|
19
|
+
* URLs"). A vanity link that also carries a code is resolved by its code,
|
|
20
|
+
* which names the agent exactly.
|
|
21
|
+
*
|
|
22
|
+
* Link recognition is data-provider's (`inspectSkrrLink`, principle 5): no
|
|
23
|
+
* regex here decides what a URL names.
|
|
24
|
+
*
|
|
25
|
+
* Attribution belongs to the SHARER's channel. A pasted link keeps the `ch` it
|
|
26
|
+
* was minted with; a bare id carries none, and this never invents one (no
|
|
27
|
+
* `ch=cli` for an id someone typed — that would credit a share nobody made).
|
|
28
|
+
*/
|
|
29
|
+
export type ResolvedAgentRef = {
|
|
30
|
+
agentId: string;
|
|
31
|
+
/**
|
|
32
|
+
* How it was given: an id, a link naming the agent, a share code the server
|
|
33
|
+
* resolved, or a vanity alias the server resolved.
|
|
34
|
+
*/
|
|
35
|
+
source: 'id' | 'link' | 'code' | 'vanity';
|
|
36
|
+
attribution: Attribution;
|
|
37
|
+
};
|
|
38
|
+
export type AgentRefErrorCode = 'AGENT_REF_EMPTY' | 'AGENT_REF_UNSUPPORTED' | 'AGENT_REF_FOREIGN' | 'AGENT_REF_NOT_AN_AGENT' | 'AGENT_REF_VANITY_UNRESOLVED' | 'AGENT_REF_CODE_UNRESOLVED';
|
|
39
|
+
export declare class AgentRefError extends Error {
|
|
40
|
+
readonly code: AgentRefErrorCode;
|
|
41
|
+
constructor(message: string, code: AgentRefErrorCode);
|
|
42
|
+
}
|
|
43
|
+
export type AgentRefOptions = {
|
|
44
|
+
/** The configured deployment; its hosts count as first-party besides the built-in list. */
|
|
45
|
+
baseURL?: string;
|
|
46
|
+
/** How a share code is resolved. Defaults to the anonymous public resolve endpoint. */
|
|
47
|
+
resolveCode?: (code: string) => Promise<ResolveDistributionCodeResponse | null>;
|
|
48
|
+
/** How a vanity alias is resolved. Defaults to the anonymous public vanity endpoint. */
|
|
49
|
+
resolveVanity?: (handle: string, slug: string) => Promise<ResolveAgentVanityResponse | null>;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* The built-in first-party hosts plus every origin the configured deployment
|
|
53
|
+
* serves (a dev or self-hosted `baseURL` is first-party for its own user).
|
|
54
|
+
*/
|
|
55
|
+
export declare function cliFirstPartyHosts(baseURL?: string): string[];
|
|
56
|
+
export declare function resolveAgentRef(input: string, options?: AgentRefOptions): Promise<ResolvedAgentRef>;
|
|
57
|
+
/**
|
|
58
|
+
* The canonical public address of a resolved agent, keeping the attribution it
|
|
59
|
+
* arrived with — what a command prints when it echoes a link back (an install
|
|
60
|
+
* command, an `open`), so following the echo credits the same share.
|
|
61
|
+
*/
|
|
62
|
+
export declare function attributedListingUrl(baseURL: string, ref: Pick<ResolvedAgentRef, 'agentId' | 'attribution'>): string;
|
|
63
|
+
/** The install body fields an attribution maps to; empty for an unattributed ref. */
|
|
64
|
+
export declare function installAttribution(attribution: Attribution): {
|
|
65
|
+
distributionCode?: string;
|
|
66
|
+
channel?: DistributionChannel;
|
|
67
|
+
};
|
|
68
|
+
/** Quote a URL for a POSIX shell: `?` and `&` in an attributed link are metacharacters. */
|
|
69
|
+
export declare function shellQuote(value: string): string;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AgentRefError = void 0;
|
|
4
|
+
exports.cliFirstPartyHosts = cliFirstPartyHosts;
|
|
5
|
+
exports.resolveAgentRef = resolveAgentRef;
|
|
6
|
+
exports.attributedListingUrl = attributedListingUrl;
|
|
7
|
+
exports.installAttribution = installAttribution;
|
|
8
|
+
exports.shellQuote = shellQuote;
|
|
9
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
10
|
+
const http_error_1 = require("./http-error");
|
|
11
|
+
const web_url_1 = require("./web-url");
|
|
12
|
+
class AgentRefError extends Error {
|
|
13
|
+
code;
|
|
14
|
+
constructor(message, code) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.name = 'AgentRefError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.AgentRefError = AgentRefError;
|
|
21
|
+
/**
|
|
22
|
+
* An agent id is a single opaque token (`agent_…` today). Anything with a
|
|
23
|
+
* slash, a colon, whitespace or a dot is a link, a path or a typo — none of
|
|
24
|
+
* which may be sent to the API as if it were an id, because the server would
|
|
25
|
+
* answer "not found" and the person would conclude the agent does not exist.
|
|
26
|
+
*/
|
|
27
|
+
const AGENT_ID_TOKEN = /^[A-Za-z0-9_-]+$/;
|
|
28
|
+
function hostOf(origin) {
|
|
29
|
+
try {
|
|
30
|
+
return new URL(origin).host.toLowerCase();
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The built-in first-party hosts plus every origin the configured deployment
|
|
38
|
+
* serves (a dev or self-hosted `baseURL` is first-party for its own user).
|
|
39
|
+
*/
|
|
40
|
+
function cliFirstPartyHosts(baseURL) {
|
|
41
|
+
const hosts = new Set(data_provider_1.FIRST_PARTY_HOSTS.map((host) => host.toLowerCase()));
|
|
42
|
+
if (baseURL) {
|
|
43
|
+
for (const origin of [baseURL, ...(0, web_url_1.firstPartyWebOrigins)(baseURL)]) {
|
|
44
|
+
const host = hostOf(origin);
|
|
45
|
+
if (host) {
|
|
46
|
+
hosts.add(host);
|
|
47
|
+
if (!host.startsWith('www.'))
|
|
48
|
+
hosts.add(`www.${host}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return [...hosts];
|
|
53
|
+
}
|
|
54
|
+
async function defaultResolveCode(code) {
|
|
55
|
+
try {
|
|
56
|
+
return await data_provider_1.dataService.resolveDistributionCode(code);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
if ((0, http_error_1.httpStatusOf)(err) === 404)
|
|
60
|
+
return null;
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function defaultResolveVanity(handle, slug) {
|
|
65
|
+
try {
|
|
66
|
+
return await data_provider_1.dataService.resolveAgentVanity({ handle, slug });
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
if ((0, http_error_1.httpStatusOf)(err) === 404)
|
|
70
|
+
return null;
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function resolveByVanity(value, handle, slug, attribution, options) {
|
|
75
|
+
const resolved = await (options.resolveVanity ?? defaultResolveVanity)(handle, slug);
|
|
76
|
+
if (resolved?.entity?.kind !== 'agent' || !resolved.entity.id) {
|
|
77
|
+
throw new AgentRefError(`No public agent answers to "${value}". The publisher may have unpublished it; their ` +
|
|
78
|
+
`page lists what they publish: skrr open ${(0, data_provider_1.entityPath)({ kind: 'publisher', handle })}`, 'AGENT_REF_VANITY_UNRESOLVED');
|
|
79
|
+
}
|
|
80
|
+
// An alias is an address, not a share: it carries no attribution of its own.
|
|
81
|
+
return { agentId: resolved.entity.id, source: 'vanity', attribution };
|
|
82
|
+
}
|
|
83
|
+
function withChannel(attribution, channel) {
|
|
84
|
+
if (attribution.channel)
|
|
85
|
+
return attribution;
|
|
86
|
+
const normalized = (0, data_provider_1.normalizeDistributionChannel)(channel);
|
|
87
|
+
return normalized ? { ...attribution, channel: normalized } : attribution;
|
|
88
|
+
}
|
|
89
|
+
async function resolveByCode(value, attribution, options) {
|
|
90
|
+
const code = attribution.code;
|
|
91
|
+
const resolved = await (options.resolveCode ?? defaultResolveCode)(code);
|
|
92
|
+
if (!resolved?.entity) {
|
|
93
|
+
throw new AgentRefError(`The share code in "${value}" does not point at a public agent: it may have been ` +
|
|
94
|
+
'unpublished, or the link was copied incompletely.', 'AGENT_REF_CODE_UNRESOLVED');
|
|
95
|
+
}
|
|
96
|
+
if (resolved.entity.kind !== 'agent') {
|
|
97
|
+
throw new AgentRefError(`"${value}" is a link to a ${resolved.entity.kind.replace(/_/g, ' ')}, not an agent.`, 'AGENT_REF_NOT_AN_AGENT');
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
agentId: resolved.entity.id,
|
|
101
|
+
source: 'code',
|
|
102
|
+
// The link's own `ch` wins; the code's minted channel fills a link without one.
|
|
103
|
+
attribution: withChannel(attribution, resolved.channel),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async function resolveAgentRef(input, options = {}) {
|
|
107
|
+
const value = String(input ?? '').trim();
|
|
108
|
+
if (!value) {
|
|
109
|
+
throw new AgentRefError(`Name the agent: pass its id (agent_…) or a ${data_provider_1.BRAND.displayName} link to it.`, 'AGENT_REF_EMPTY');
|
|
110
|
+
}
|
|
111
|
+
if (AGENT_ID_TOKEN.test(value)) {
|
|
112
|
+
return { agentId: value, source: 'id', attribution: {} };
|
|
113
|
+
}
|
|
114
|
+
const inspected = (0, data_provider_1.inspectSkrrLink)(value, {
|
|
115
|
+
firstPartyHosts: cliFirstPartyHosts(options.baseURL),
|
|
116
|
+
});
|
|
117
|
+
if (!inspected) {
|
|
118
|
+
throw /^[a-z][a-z0-9+.-]*:\/\//i.test(value)
|
|
119
|
+
? new AgentRefError(`"${value}" is not a ${data_provider_1.BRAND.displayName} link, so it was not followed. Pass an agent ` +
|
|
120
|
+
`id or a link on ${data_provider_1.BRAND.displayName}'s own site.`, 'AGENT_REF_FOREIGN')
|
|
121
|
+
: unsupported(value);
|
|
122
|
+
}
|
|
123
|
+
const { link, attribution } = inspected;
|
|
124
|
+
switch (link.kind) {
|
|
125
|
+
case 'agent':
|
|
126
|
+
case 'store_agent':
|
|
127
|
+
case 'agent_owner':
|
|
128
|
+
return { agentId: link.agentId, source: 'link', attribution };
|
|
129
|
+
case 'agent_vanity':
|
|
130
|
+
// A code on the link names the agent exactly; a bare alias is resolved
|
|
131
|
+
// by the server's vanity store.
|
|
132
|
+
if (attribution.code)
|
|
133
|
+
return resolveByCode(value, attribution, options);
|
|
134
|
+
return resolveByVanity(value, link.handle, link.slug, attribution, options);
|
|
135
|
+
case 'unknown':
|
|
136
|
+
if (attribution.code)
|
|
137
|
+
return resolveByCode(value, attribution, options);
|
|
138
|
+
throw unsupported(value);
|
|
139
|
+
default:
|
|
140
|
+
throw new AgentRefError(`"${value}" is a link to a ${link.kind.replace(/_/g, ' ')}, not an agent.`, 'AGENT_REF_NOT_AN_AGENT');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function unsupported(value) {
|
|
144
|
+
return new AgentRefError(`"${value}" is not an agent id or a link to an agent. Pass the id (agent_…) or its ` +
|
|
145
|
+
'listing link (…/a/<id>).', 'AGENT_REF_UNSUPPORTED');
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The canonical public address of a resolved agent, keeping the attribution it
|
|
149
|
+
* arrived with — what a command prints when it echoes a link back (an install
|
|
150
|
+
* command, an `open`), so following the echo credits the same share.
|
|
151
|
+
*/
|
|
152
|
+
function attributedListingUrl(baseURL, ref) {
|
|
153
|
+
return (0, data_provider_1.buildShareUrl)((0, web_url_1.webOrigin)(baseURL), { kind: 'agent', id: ref.agentId }, {
|
|
154
|
+
code: ref.attribution.code,
|
|
155
|
+
channel: ref.attribution.channel,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/** The install body fields an attribution maps to; empty for an unattributed ref. */
|
|
159
|
+
function installAttribution(attribution) {
|
|
160
|
+
return {
|
|
161
|
+
...(attribution.code ? { distributionCode: attribution.code } : {}),
|
|
162
|
+
...(attribution.channel ? { channel: attribution.channel } : {}),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/** Quote a URL for a POSIX shell: `?` and `&` in an attributed link are metacharacters. */
|
|
166
|
+
function shellQuote(value) {
|
|
167
|
+
return /^[A-Za-z0-9_@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
|
|
168
|
+
}
|
package/dist/lib/api-fetch.d.ts
CHANGED
|
@@ -37,6 +37,8 @@ export declare class ApiFetchError extends Error {
|
|
|
37
37
|
* attributed by guesswork — see `node-adapter.ts`.
|
|
38
38
|
*/
|
|
39
39
|
readonly requestId?: string;
|
|
40
|
+
/** Milliseconds the server asked us to wait (`Retry-After`) on a 429. */
|
|
41
|
+
retryAfterMs?: number;
|
|
40
42
|
/**
|
|
41
43
|
* Set on a 401 when this CLI's own refresh was refused AND the local
|
|
42
44
|
* daemon, asked for a hand-off, refused too (OSK-12474). The daemon's reason
|
package/dist/lib/api-fetch.js
CHANGED
|
@@ -47,6 +47,7 @@ const daemonBroker_1 = require("./daemonBroker");
|
|
|
47
47
|
const dpop_auth_1 = require("./dpop-auth");
|
|
48
48
|
const workspace_header_1 = require("./workspace-header");
|
|
49
49
|
const non_json_response_1 = require("./non-json-response");
|
|
50
|
+
const rate_limit_retry_1 = require("./rate-limit-retry");
|
|
50
51
|
class ApiFetchError extends Error {
|
|
51
52
|
status;
|
|
52
53
|
body;
|
|
@@ -63,6 +64,8 @@ class ApiFetchError extends Error {
|
|
|
63
64
|
* attributed by guesswork — see `node-adapter.ts`.
|
|
64
65
|
*/
|
|
65
66
|
requestId;
|
|
67
|
+
/** Milliseconds the server asked us to wait (`Retry-After`) on a 429. */
|
|
68
|
+
retryAfterMs;
|
|
66
69
|
/**
|
|
67
70
|
* Set on a 401 when this CLI's own refresh was refused AND the local
|
|
68
71
|
* daemon, asked for a hand-off, refused too (OSK-12474). The daemon's reason
|
|
@@ -186,13 +189,19 @@ async function apiFetch(pathOrUrl, opts = {}) {
|
|
|
186
189
|
// OSK-12020 — a fresh proof per attempt for a DPoP-bound hand-off token
|
|
187
190
|
// (the 401 retry below re-enters here and gets its own). No-op otherwise.
|
|
188
191
|
Object.assign(headers, await (0, dpop_auth_1.dpopHeadersFor)(credential.token, method, url));
|
|
189
|
-
|
|
192
|
+
const sent = (0, workspace_header_1.withWorkspaceHeader)(headers);
|
|
193
|
+
// E6: a 429 on a GET or an idempotency-keyed write is retried (bounded,
|
|
194
|
+
// jittered, honouring Retry-After). The last 429's wait is kept for the error.
|
|
195
|
+
const { response, retryAfterMs } = await (0, rate_limit_retry_1.fetchWithRateLimitRetry)(() => fetch(url, {
|
|
190
196
|
method,
|
|
191
|
-
headers:
|
|
197
|
+
headers: sent,
|
|
192
198
|
body,
|
|
193
199
|
...(opts.signal ? { signal: opts.signal } : {}),
|
|
194
|
-
});
|
|
200
|
+
}), { method, headers: sent, signal: opts.signal });
|
|
201
|
+
lastRetryAfterMs = retryAfterMs;
|
|
202
|
+
return response;
|
|
195
203
|
};
|
|
204
|
+
let lastRetryAfterMs;
|
|
196
205
|
let res = await fetchWithCredential(cred);
|
|
197
206
|
let brokerFailure = null;
|
|
198
207
|
if (res.status === 401 && delegatedCli) {
|
|
@@ -271,6 +280,8 @@ async function apiFetch(pathOrUrl, opts = {}) {
|
|
|
271
280
|
const error = new ApiFetchError(`HTTP ${res.status} ${res.statusText} — ${method} ${pathOrUrl}`, res.status, text, code, method, res.headers.get('x-request-id') || undefined);
|
|
272
281
|
if (brokerFailure)
|
|
273
282
|
error.brokerFailure = brokerFailure;
|
|
283
|
+
if (res.status === 429 && lastRetryAfterMs !== undefined)
|
|
284
|
+
error.retryAfterMs = lastRetryAfterMs;
|
|
274
285
|
throw error;
|
|
275
286
|
}
|
|
276
287
|
// 204/205 carry no body by definition; an empty body has no content-type
|
|
@@ -26,6 +26,8 @@ export type CommandHygieneReport = {
|
|
|
26
26
|
domains: number;
|
|
27
27
|
budgetErrors: number;
|
|
28
28
|
};
|
|
29
|
+
/** The verb rules the findings below are measured against (P8). */
|
|
30
|
+
namingGrammar: readonly string[];
|
|
29
31
|
issues: CommandHygieneIssue[];
|
|
30
32
|
};
|
|
31
33
|
export declare function auditCommands({ rootDir, manifest, }: {
|
|
@@ -37,3 +39,14 @@ export declare function auditCommands({ rootDir, manifest, }: {
|
|
|
37
39
|
*/
|
|
38
40
|
manifest?: CommandManifest;
|
|
39
41
|
}): CommandHygieneReport;
|
|
42
|
+
/**
|
|
43
|
+
* The domains an agent drives most. A missing description or `--json` output
|
|
44
|
+
* here is a build error (P10); elsewhere it stays a warning until that domain's
|
|
45
|
+
* offenders are fixed, so the gate can ratchet outward one domain at a time.
|
|
46
|
+
*/
|
|
47
|
+
export declare const ENFORCED_HYGIENE_DOMAINS: readonly ["tasks", "spaces", "projects"];
|
|
48
|
+
/**
|
|
49
|
+
* The verb grammar `commands --audit` checks, stated once so a reader of the
|
|
50
|
+
* report sees the rule and not only the findings it produced.
|
|
51
|
+
*/
|
|
52
|
+
export declare const NAMING_GRAMMAR: readonly ["Verbs: list, show, create, update, delete, archive, unarchive, move. A reversible state flip is its own verb, never a flag on its inverse.", "Scope: a list verb takes its parent scope as an optional filter flag; a verb that cannot work without a scope says so in its description.", "Output: every command in tasks, spaces and projects takes --json and has a description (audit errors)."];
|
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.NAMING_GRAMMAR = exports.ENFORCED_HYGIENE_DOMAINS = void 0;
|
|
36
37
|
exports.auditCommands = auditCommands;
|
|
37
38
|
const fs = __importStar(require("node:fs"));
|
|
38
39
|
const path = __importStar(require("node:path"));
|
|
@@ -120,6 +121,32 @@ function auditCommands({ rootDir, manifest, }) {
|
|
|
120
121
|
});
|
|
121
122
|
}
|
|
122
123
|
}
|
|
124
|
+
// Without a generated manifest (a source checkout, most CI jobs) the
|
|
125
|
+
// manifest rules below never run, so the P10 gate for tasks/spaces/projects
|
|
126
|
+
// would pass by not looking. Read the same two facts off the source.
|
|
127
|
+
if (!manifest && isEnforcedDomain(command)) {
|
|
128
|
+
// A spread of a shared flag set (`...paginatedExportFlags(...)`) may carry
|
|
129
|
+
// --json from another file; only the manifest can tell, so do not guess.
|
|
130
|
+
const spreadsSharedFlags = /\.\.\.[\w.]*Flags\b/.test(source);
|
|
131
|
+
if (!hasJson && !spreadsSharedFlags && isMachineRelevantCommand(command)) {
|
|
132
|
+
issues.push({
|
|
133
|
+
code: 'JSON_SUCCESS_OUTPUT_MISSING',
|
|
134
|
+
severity: 'error',
|
|
135
|
+
command,
|
|
136
|
+
file: rel,
|
|
137
|
+
message: 'Machine-relevant command has no --json success-output flag. Keep human-only commands intentional.',
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (!/static (?:override )?description\s*=/.test(source)) {
|
|
141
|
+
issues.push({
|
|
142
|
+
code: 'COMMAND_DESCRIPTION_MISSING',
|
|
143
|
+
severity: 'error',
|
|
144
|
+
command,
|
|
145
|
+
file: rel,
|
|
146
|
+
message: 'Command is missing a description.',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
123
150
|
if (hasFromJson && !hasJson) {
|
|
124
151
|
issues.push({
|
|
125
152
|
code: 'FROM_JSON_WITHOUT_JSON_OUTPUT',
|
|
@@ -153,7 +180,7 @@ function auditCommands({ rootDir, manifest, }) {
|
|
|
153
180
|
if (!command?.description?.trim()) {
|
|
154
181
|
issues.push({
|
|
155
182
|
code: 'COMMAND_DESCRIPTION_MISSING',
|
|
156
|
-
severity: 'warning',
|
|
183
|
+
severity: isEnforcedDomain(id) ? 'error' : 'warning',
|
|
157
184
|
command: id,
|
|
158
185
|
message: 'Command is missing a description in the manifest.',
|
|
159
186
|
});
|
|
@@ -161,11 +188,22 @@ function auditCommands({ rootDir, manifest, }) {
|
|
|
161
188
|
if (!hasJsonFlag(command?.flags) && isMachineRelevantCommand(id)) {
|
|
162
189
|
issues.push({
|
|
163
190
|
code: 'JSON_SUCCESS_OUTPUT_MISSING',
|
|
164
|
-
severity: 'warning',
|
|
191
|
+
severity: isEnforcedDomain(id) ? 'error' : 'warning',
|
|
165
192
|
command: id,
|
|
166
193
|
message: 'Machine-relevant command has no --json success-output flag. Keep human-only commands intentional.',
|
|
167
194
|
});
|
|
168
195
|
}
|
|
196
|
+
// P8: a state flip is a verb (`archive` / `unarchive`), not a flag on its
|
|
197
|
+
// inverse. `spaces unarchive` follows the grammar; `tasks archive
|
|
198
|
+
// --unarchive` and `projects archive --unarchive` do not.
|
|
199
|
+
if (isEnforcedDomain(id) && hasFlag(command?.flags, 'unarchive')) {
|
|
200
|
+
issues.push({
|
|
201
|
+
code: 'VERB_GRAMMAR_INVERSE_AS_FLAG',
|
|
202
|
+
severity: 'warning',
|
|
203
|
+
command: id,
|
|
204
|
+
message: `Naming grammar: a state flip is its own verb (\`${id.replace(/:archive$/, ':unarchive').replace(/:/g, ' ')}\`), not --unarchive on the forward verb. Keep the flag as a deprecated alias when adding the verb.`,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
169
207
|
}
|
|
170
208
|
}
|
|
171
209
|
const errors = issues.filter((issue) => issue.severity === 'error').length;
|
|
@@ -190,6 +228,7 @@ function auditCommands({ rootDir, manifest, }) {
|
|
|
190
228
|
domains: (0, usage_discovery_1.usageDomains)(manifestForCatalog).length,
|
|
191
229
|
budgetErrors: usageBudgetIssues.length,
|
|
192
230
|
},
|
|
231
|
+
namingGrammar: exports.NAMING_GRAMMAR,
|
|
193
232
|
issues,
|
|
194
233
|
};
|
|
195
234
|
}
|
|
@@ -213,6 +252,27 @@ function commandIdFromRelativePath(relativePath) {
|
|
|
213
252
|
function hasJsonFlag(flags) {
|
|
214
253
|
return Boolean(flags && typeof flags === 'object' && 'json' in flags);
|
|
215
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* The domains an agent drives most. A missing description or `--json` output
|
|
257
|
+
* here is a build error (P10); elsewhere it stays a warning until that domain's
|
|
258
|
+
* offenders are fixed, so the gate can ratchet outward one domain at a time.
|
|
259
|
+
*/
|
|
260
|
+
exports.ENFORCED_HYGIENE_DOMAINS = ['tasks', 'spaces', 'projects'];
|
|
261
|
+
function isEnforcedDomain(id) {
|
|
262
|
+
return exports.ENFORCED_HYGIENE_DOMAINS.some((domain) => id === domain || id.startsWith(`${domain}:`));
|
|
263
|
+
}
|
|
264
|
+
function hasFlag(flags, name) {
|
|
265
|
+
return Boolean(flags && typeof flags === 'object' && name in flags);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* The verb grammar `commands --audit` checks, stated once so a reader of the
|
|
269
|
+
* report sees the rule and not only the findings it produced.
|
|
270
|
+
*/
|
|
271
|
+
exports.NAMING_GRAMMAR = [
|
|
272
|
+
'Verbs: list, show, create, update, delete, archive, unarchive, move. A reversible state flip is its own verb, never a flag on its inverse.',
|
|
273
|
+
'Scope: a list verb takes its parent scope as an optional filter flag; a verb that cannot work without a scope says so in its description.',
|
|
274
|
+
'Output: every command in tasks, spaces and projects takes --json and has a description (audit errors).',
|
|
275
|
+
];
|
|
216
276
|
function isMachineRelevantCommand(id) {
|
|
217
277
|
return !(id === 'login' ||
|
|
218
278
|
id === 'logout' ||
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type DedicatedRuntimePowerSummary, type DedicatedPowerPolicy, type DedicatedRuntimePowerPolicyState, type OnDemandIneligibleError, type SetDedicatedRuntimePowerPolicyResponse } from '@skrr-ai/data-provider';
|
|
1
|
+
import { type DedicatedRuntimePowerSummary, type DedicatedRuntimeWaitingWork, type DedicatedPowerPolicy, type DedicatedRuntimePowerPolicyState, type OnDemandIneligibleError, type SetDedicatedRuntimePowerPolicyResponse } from '@skrr-ai/data-provider';
|
|
2
2
|
import { type WhenOptions } from './format';
|
|
3
3
|
import { type DedicatedRuntimeScope } from './dedicated-machines';
|
|
4
4
|
/**
|
|
@@ -33,6 +33,16 @@ export declare function describePolicyWords(policy: DedicatedPowerPolicy, idleAf
|
|
|
33
33
|
export declare function describePowerPolicy(power: DedicatedRuntimePowerPolicyState, autoStopMode?: 'off' | 'canary' | 'on'): string;
|
|
34
34
|
/** `GET /api/machines/dedicated/:leaseId/power` — the read-only power card. */
|
|
35
35
|
export declare function getDedicatedPowerSummary(leaseId: string, scope?: DedicatedRuntimeScope): Promise<DedicatedRuntimePowerSummary>;
|
|
36
|
+
/** `GET /api/machines/dedicated/:leaseId/power/waiting` — work waiting for this machine. */
|
|
37
|
+
export declare function getDedicatedWaitingWork(leaseId: string, scope?: DedicatedRuntimeScope): Promise<DedicatedRuntimeWaitingWork>;
|
|
38
|
+
/** The lines of `power waiting`. An unreadable source is said, never folded into "nothing waiting". */
|
|
39
|
+
export declare function describeWaitingWork(waiting: DedicatedRuntimeWaitingWork, when?: WhenOptions): string[];
|
|
40
|
+
/** Last wake timing. A wake that never became assignable shows the phases it reached and no latency. */
|
|
41
|
+
export declare function describeLastWakeTiming(wake: DedicatedRuntimePowerSummary['lastWake']): string[];
|
|
42
|
+
/** on_demand availability, so a plan does not need a failed `power set` to find out. */
|
|
43
|
+
export declare function describeOnDemandAvailability(onDemand: DedicatedRuntimePowerSummary['onDemand']): string[];
|
|
44
|
+
/** Pre-warm lines: only a PAUSED pre-warm is in the summary, so silence here is not "pre-warm is on". */
|
|
45
|
+
export declare function describePrewarm(prewarm: DedicatedRuntimePowerSummary['prewarm'], when?: WhenOptions): string[];
|
|
36
46
|
type PowerDecisionView = NonNullable<DedicatedRuntimePowerSummary['decision']>;
|
|
37
47
|
/** The stay/stop/wake decision in words: the shared reason copy backs the server's detail. */
|
|
38
48
|
export declare function describePowerDecisionLines(decision: PowerDecisionView): {
|
|
@@ -53,6 +63,11 @@ export declare function describeLastAutoStopLines(last: DedicatedRuntimePowerSum
|
|
|
53
63
|
};
|
|
54
64
|
/** The latest wake decision and who asked, as lines; empty when there is none. */
|
|
55
65
|
export declare function describeLastWakeDecisionLines(wake: DedicatedRuntimePowerSummary['lastWakeDecision'], when?: WhenOptions): string[];
|
|
66
|
+
/**
|
|
67
|
+
* The announced-but-not-yet-done stop, in the shared words (`describePendingStop`). Empty when the
|
|
68
|
+
* summary carries none, which is also what an older server sends: absent is not "no stop coming".
|
|
69
|
+
*/
|
|
70
|
+
export declare function describePendingStopLines(summary: Pick<DedicatedRuntimePowerSummary, 'leaseId' | 'pendingStop'>, when?: WhenOptions): string[];
|
|
56
71
|
/** The lines of `power show`. */
|
|
57
72
|
export declare function describePowerSummary(summary: DedicatedRuntimePowerSummary, when?: WhenOptions): string[];
|
|
58
73
|
/** The lines of `power explain`; the fix is always last. */
|