@orchestraworks/cli 0.5.1 → 0.5.3
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/README.md +1 -1
- package/dist/cli/api/compute-provider-check.d.ts +29 -0
- package/dist/cli/api/compute-provider-check.js +207 -0
- package/dist/cli/api/tail.d.ts +66 -0
- package/dist/cli/api/tail.js +564 -0
- package/dist/cli/main.d.ts +5 -1
- package/dist/cli/main.js +22 -0
- package/dist/constructs/agent.d.ts +10 -0
- package/dist/constructs/agent.js +39 -4
- package/dist/constructs/environment.d.ts +29 -1
- package/dist/constructs/environment.js +28 -1
- package/dist/constructs/skill.d.ts +6 -1
- package/dist/constructs/skill.js +21 -2
- package/dist/engine/reconcile.js +15 -1
- package/dist/generated/cli-commands.json +876 -1
- package/dist/generated/managed-skills.d.ts +2 -0
- package/dist/generated/managed-skills.js +13 -0
- package/dist/index.d.ts +1 -1
- package/docs/REFERENCE.md +21 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/ApiKey.d.ts +6 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/ApiKey.js +2 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/ComputeProvider.d.ts +3 -3
- package/node_modules/@orchestraworks/client/dist/esm/models/CreateApiKeyRequest.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/CreateApiKeyRequest.js +2 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/CreateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/CreateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/Environment.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/Environment.js +5 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHook.d.ts +38 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHook.js +45 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooks.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooks.js +44 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooksRequest.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooksRequest.js +44 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentProvisionSpec.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentProvisionSpecRequest.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentSnapshot.d.ts +19 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentSnapshot.js +7 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/Machine.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/Machine.js +2 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/UpdateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/UpdateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/index.d.ts +3 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/index.js +3 -0
- package/node_modules/@orchestraworks/client/dist/models/ApiKey.d.ts +6 -0
- package/node_modules/@orchestraworks/client/dist/models/ApiKey.js +2 -0
- package/node_modules/@orchestraworks/client/dist/models/ComputeProvider.d.ts +3 -3
- package/node_modules/@orchestraworks/client/dist/models/CreateApiKeyRequest.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/models/CreateApiKeyRequest.js +2 -0
- package/node_modules/@orchestraworks/client/dist/models/CreateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/models/CreateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/models/Environment.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/models/Environment.js +5 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHook.d.ts +38 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHook.js +52 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooks.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooks.js +51 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooksRequest.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooksRequest.js +51 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentProvisionSpec.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentProvisionSpecRequest.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentSnapshot.d.ts +19 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentSnapshot.js +7 -0
- package/node_modules/@orchestraworks/client/dist/models/Machine.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/models/Machine.js +2 -0
- package/node_modules/@orchestraworks/client/dist/models/UpdateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/models/UpdateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/models/index.d.ts +3 -0
- package/node_modules/@orchestraworks/client/dist/models/index.js +3 -0
- package/node_modules/@orchestraworks/client/package.json +1 -1
- package/package.json +4 -4
- package/skills/orchestra/SKILL.md +167 -42
- package/skills/orchestra-fdk/SKILL.md +112 -545
- package/skills/orchestra-fdk/references/authoring.md +130 -3
- package/skills/orchestra-fdk/references/environment.md +352 -43
- package/skills/orchestra-fdk/references/integrations/analytics.md +18 -0
- package/skills/orchestra-fdk/references/integrations/ci-cd.md +20 -0
- package/skills/orchestra-fdk/references/integrations/cloud.md +19 -0
- package/skills/orchestra-fdk/references/integrations/code-repo.md +76 -0
- package/skills/orchestra-fdk/references/integrations/databases.md +22 -0
- package/skills/orchestra-fdk/references/integrations/dependencies.md +29 -0
- package/skills/orchestra-fdk/references/integrations/design.md +18 -0
- package/skills/orchestra-fdk/references/integrations/feature-flags.md +19 -0
- package/skills/orchestra-fdk/references/integrations/incident.md +29 -0
- package/skills/orchestra-fdk/references/integrations/issue-tracker.md +65 -0
- package/skills/orchestra-fdk/references/integrations/knowledge-base.md +43 -0
- package/skills/orchestra-fdk/references/integrations/messaging.md +38 -0
- package/skills/orchestra-fdk/references/integrations/observability.md +36 -0
- package/skills/orchestra-fdk/references/integrations/secrets-managers.md +25 -0
- package/skills/orchestra-fdk/references/integrations/support-desk.md +31 -0
- package/skills/orchestra-fdk/references/phases/0-start.md +62 -0
- package/skills/orchestra-fdk/references/phases/1-discover.md +111 -0
- package/skills/orchestra-fdk/references/phases/2-plan.md +157 -0
- package/skills/orchestra-fdk/references/phases/3-connect.md +99 -0
- package/skills/orchestra-fdk/references/phases/4-build.md +159 -0
- package/skills/orchestra-fdk/references/phases/5-prove.md +107 -0
- package/skills/orchestra-fdk/references/phases/6-handover.md +42 -0
- package/skills/orchestra-fdk/references/troubleshooting.md +128 -0
- package/templates/bug-fix/agents/bugfix.md +1 -1
- package/templates/bug-fix/main.ts +1 -1
- package/templates/engineering-team/README.md +45 -181
- package/templates/engineering-team/agents/engineer-agent.md +10 -7
- package/templates/engineering-team/agents/manager-agent.md +23 -120
- package/templates/engineering-team/inputs.json +1 -3
- package/templates/engineering-team/lib/environment.ts +10 -90
- package/templates/engineering-team/lib/inputs.ts +5 -97
- package/templates/engineering-team/lib/setup.sh +5 -5
- package/templates/engineering-team/main.ts +22 -69
- package/templates/todo-factory/agents/bugfix.md +1 -1
- package/templates/todo-factory/main.ts +1 -1
- package/templates/engineering-team/agents/engineer-bare.md +0 -22
- package/templates/engineering-team/onboarding/create-score-metrics.sh +0 -33
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ The full guide to every construct, secrets, connections and troubleshooting is [
|
|
|
20
20
|
```bash
|
|
21
21
|
npm install -g @orchestraworks/cli # the CLI, on your path as `orchestra`
|
|
22
22
|
npm install @orchestraworks/cli # the current release
|
|
23
|
-
npm install @orchestraworks/cli@0.5.
|
|
23
|
+
npm install @orchestraworks/cli@0.5.3 # this exact release
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Then `import { Factory, Agent, … } from "@orchestraworks/cli"` normally — the package `exports` entry resolves
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { FetchAPI } from "@orchestraworks/client";
|
|
2
|
+
import { type CliIo } from "../core/output.js";
|
|
3
|
+
import type { Profile } from "../core/profile.js";
|
|
4
|
+
export interface ComputeProviderCheckOptions {
|
|
5
|
+
output?: string;
|
|
6
|
+
profile?: string;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
org?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Every seam a test replaces; production leaves them all undefined. */
|
|
11
|
+
export interface ComputeProviderCheckDeps {
|
|
12
|
+
env?: NodeJS.ProcessEnv;
|
|
13
|
+
io?: CliIo;
|
|
14
|
+
fetchApi?: FetchAPI;
|
|
15
|
+
loadProfile?: (name?: string) => Profile | undefined;
|
|
16
|
+
/** Milliseconds. */
|
|
17
|
+
now?: () => number;
|
|
18
|
+
onExitCode?: (code: number) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare class ComputeProviderCheckUsageError extends Error {
|
|
21
|
+
constructor(message: string);
|
|
22
|
+
}
|
|
23
|
+
/** Named, so the shared mapper prints its message as the error line. */
|
|
24
|
+
export declare class ComputeProviderCheckFailed extends Error {
|
|
25
|
+
constructor(message: string);
|
|
26
|
+
}
|
|
27
|
+
export declare function computeProviderCheckCommand(id: string, options?: ComputeProviderCheckOptions, deps?: ComputeProviderCheckDeps): Promise<void>;
|
|
28
|
+
/** The two largest units of a duration in milliseconds; a negative one, from clock skew, reads as zero. */
|
|
29
|
+
export declare function formatAge(ms: number): string;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// One read of a compute provider, shown so a person installing a Launcher can see why it does not work. It
|
|
2
|
+
// adds no wire shape of its own: it dispatches through the same generated row `orchestra compute-providers
|
|
3
|
+
// get` uses, prints that read, and judges it. The exit code is the judgment, so a script can wait on it:
|
|
4
|
+
// 0 when the Launcher polls, its protocol was accepted and every target serves; 1 otherwise, with one line
|
|
5
|
+
// naming each failure on stderr while stdout keeps the read.
|
|
6
|
+
import { findCommand } from "../../generated/cli-commands.js";
|
|
7
|
+
import { CLI_DISPATCH } from "../../generated/cli-dispatch.js";
|
|
8
|
+
import { authFlagsFrom, platformTargetFrom, resolveAuthWithWarnings } from "../core/auth.js";
|
|
9
|
+
import { runCommand, settleExitCode } from "../core/errors.js";
|
|
10
|
+
import { defaultIo, parseOutputMode, printRedactionNotes, printResponse, printWarnings, writeLines, } from "../core/output.js";
|
|
11
|
+
import { createPlatformApis } from "../core/platform-client.js";
|
|
12
|
+
import { redact } from "../core/redaction.js";
|
|
13
|
+
const NOUN = "compute-providers";
|
|
14
|
+
export class ComputeProviderCheckUsageError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "ComputeProviderCheckUsageError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Named, so the shared mapper prints its message as the error line. */
|
|
21
|
+
export class ComputeProviderCheckFailed extends Error {
|
|
22
|
+
constructor(message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = "ComputeProviderCheckFailed";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function computeProviderCheckCommand(id, options = {}, deps = {}) {
|
|
28
|
+
const io = deps.io ?? defaultIo;
|
|
29
|
+
const ctx = { notFound: { resource: "compute provider", key: id } };
|
|
30
|
+
const code = await runCommand(() => check(id, options, deps, ctx), ctx, io);
|
|
31
|
+
settleExitCode(code, deps.onExitCode);
|
|
32
|
+
}
|
|
33
|
+
/** Throws on every failure, a Launcher that does not work included; the caller owns reporting and the exit code. */
|
|
34
|
+
async function check(id, options, deps, ctx) {
|
|
35
|
+
const env = deps.env ?? process.env;
|
|
36
|
+
const io = deps.io ?? defaultIo;
|
|
37
|
+
const now = deps.now ?? (() => Date.now());
|
|
38
|
+
const mode = parseOutputMode(options.output, (message) => new ComputeProviderCheckUsageError(message));
|
|
39
|
+
ctx.mode = mode;
|
|
40
|
+
const row = getRow();
|
|
41
|
+
const dispatch = CLI_DISPATCH[row.operationId];
|
|
42
|
+
if (dispatch === undefined) {
|
|
43
|
+
throw new Error(`this orchestra build has no dispatch entry for operation '${row.operationId}'.`);
|
|
44
|
+
}
|
|
45
|
+
const { auth, warnings } = await resolveAuthWithWarnings(env, authFlagsFrom(options), deps.loadProfile !== undefined ? { loadProfile: deps.loadProfile } : {});
|
|
46
|
+
printWarnings(warnings, io);
|
|
47
|
+
ctx.provider = auth.provider;
|
|
48
|
+
ctx.baseUrl = auth.baseUrl;
|
|
49
|
+
const platformTarget = platformTargetFrom(auth);
|
|
50
|
+
const apis = createPlatformApis(platformTarget, deps.fetchApi, { warn: (lines) => printWarnings(lines, io) });
|
|
51
|
+
const organizationId = platformTarget.organizationId;
|
|
52
|
+
const response = await dispatch(apis, {
|
|
53
|
+
pathParams: { [row.positionals[0]?.param ?? "id"]: id },
|
|
54
|
+
query: {},
|
|
55
|
+
...(organizationId !== undefined ? { organizationId } : {}),
|
|
56
|
+
});
|
|
57
|
+
const text = await response.raw.text();
|
|
58
|
+
const body = text.trim() === "" ? undefined : JSON.parse(text);
|
|
59
|
+
// The judgment reads the raw body and the printed lines read the redacted one, as every read command does.
|
|
60
|
+
const redaction = redact(body, row.responseSchema, { reveal: false });
|
|
61
|
+
if (mode === "json") {
|
|
62
|
+
printResponse(redaction.rendered, { mode, io, redaction });
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
writeLines(io, "out", renderReport(viewOf(redaction.rendered), now()));
|
|
66
|
+
printRedactionNotes(redaction, io);
|
|
67
|
+
}
|
|
68
|
+
const failures = judge(viewOf(body), now());
|
|
69
|
+
if (failures.length > 0) {
|
|
70
|
+
throw new ComputeProviderCheckFailed(`${describe(viewOf(body))} does not work: ${failures.join("; ")}.`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function getRow() {
|
|
74
|
+
const row = findCommand(NOUN, "get");
|
|
75
|
+
if (row === undefined) {
|
|
76
|
+
throw new Error(`this orchestra build has no \`${NOUN} get\` command to read.`);
|
|
77
|
+
}
|
|
78
|
+
return row;
|
|
79
|
+
}
|
|
80
|
+
/** Each reason the Launcher does not work, in the order a person fixes them. Empty means it works. */
|
|
81
|
+
function judge(provider, nowMs) {
|
|
82
|
+
if (provider.kind === "managed") {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
const failures = [];
|
|
86
|
+
if (provider.protocolRefusal !== undefined) {
|
|
87
|
+
failures.push(`the platform refused the Launcher's protocol: ${provider.protocolRefusal}`);
|
|
88
|
+
}
|
|
89
|
+
if (provider.state === "never_connected" || provider.lastPollAt === undefined) {
|
|
90
|
+
failures.push("the Launcher has never polled");
|
|
91
|
+
}
|
|
92
|
+
else if (provider.state !== "connected") {
|
|
93
|
+
const age = ageOf(provider.lastPollAt, nowMs);
|
|
94
|
+
failures.push(`the Launcher is ${provider.state ?? "in an unknown state"}: its last poll was ${age} ago`);
|
|
95
|
+
}
|
|
96
|
+
if (provider.state === "connected" && provider.targets.length === 0) {
|
|
97
|
+
failures.push("the Launcher reported no targets");
|
|
98
|
+
}
|
|
99
|
+
for (const target of provider.targets) {
|
|
100
|
+
if (target.refusedReason !== undefined) {
|
|
101
|
+
failures.push(`target ${target.kind} ${target.place}: ${target.refusedReason}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return failures;
|
|
105
|
+
}
|
|
106
|
+
function renderReport(provider, nowMs) {
|
|
107
|
+
const lines = [field("compute provider", describe(provider))];
|
|
108
|
+
if (provider.kind === "managed") {
|
|
109
|
+
lines.push(field("kind", "managed: this deployment runs it, so there is no Launcher to check"));
|
|
110
|
+
return lines.join("\n");
|
|
111
|
+
}
|
|
112
|
+
lines.push(field("state", provider.state ?? "unknown"));
|
|
113
|
+
lines.push(field("last poll", provider.lastPollAt === undefined ? "never" : `${provider.lastPollAt} (${ageOf(provider.lastPollAt, nowMs)} ago)`));
|
|
114
|
+
const version = provider.protocolVersion;
|
|
115
|
+
lines.push(field("protocol", version === undefined ? "none reported" : `version ${String(version)}`));
|
|
116
|
+
if (provider.protocolRefusal !== undefined) {
|
|
117
|
+
lines.push(field("protocol refusal", provider.protocolRefusal));
|
|
118
|
+
}
|
|
119
|
+
const health = provider.health;
|
|
120
|
+
lines.push(field("health", health === undefined
|
|
121
|
+
? "none reported"
|
|
122
|
+
: `orders held ${String(health.ordersHeld)}, cloud errors ${String(health.cloudErrors)}, ` +
|
|
123
|
+
`reports pending ${String(health.reportsPending)}`));
|
|
124
|
+
if (provider.targets.length === 0) {
|
|
125
|
+
lines.push(field("targets", "none reported"));
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
lines.push("targets");
|
|
129
|
+
const kindWidth = Math.max(...provider.targets.map((target) => target.kind.length));
|
|
130
|
+
const placeWidth = Math.max(...provider.targets.map((target) => target.place.length));
|
|
131
|
+
for (const target of provider.targets) {
|
|
132
|
+
const result = target.refusedReason === undefined ? "passed" : `failed: ${target.refusedReason}`;
|
|
133
|
+
lines.push(` ${target.kind.padEnd(kindWidth)} ${target.place.padEnd(placeWidth)} ${result}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const failures = judge(provider, nowMs);
|
|
137
|
+
lines.push(field("result", failures.length === 0 ? "working" : "not working"));
|
|
138
|
+
return lines.join("\n");
|
|
139
|
+
}
|
|
140
|
+
const LABEL_WIDTH = 18;
|
|
141
|
+
function field(label, value) {
|
|
142
|
+
return `${label.padEnd(LABEL_WIDTH)}${value}`;
|
|
143
|
+
}
|
|
144
|
+
function describe(provider) {
|
|
145
|
+
return provider.name === "" ? provider.id : `${provider.name} (${provider.id})`;
|
|
146
|
+
}
|
|
147
|
+
function ageOf(isoInstant, nowMs) {
|
|
148
|
+
const at = Date.parse(isoInstant);
|
|
149
|
+
return Number.isNaN(at) ? "an unknown time" : formatAge(nowMs - at);
|
|
150
|
+
}
|
|
151
|
+
/** The two largest units of a duration in milliseconds; a negative one, from clock skew, reads as zero. */
|
|
152
|
+
export function formatAge(ms) {
|
|
153
|
+
const seconds = Math.max(0, Math.floor(ms / 1000));
|
|
154
|
+
const days = Math.floor(seconds / 86_400);
|
|
155
|
+
const hours = Math.floor((seconds % 86_400) / 3600);
|
|
156
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
157
|
+
const rest = seconds % 60;
|
|
158
|
+
if (days > 0)
|
|
159
|
+
return `${days}d ${hours}h`;
|
|
160
|
+
if (hours > 0)
|
|
161
|
+
return `${hours}h ${minutes}m`;
|
|
162
|
+
if (minutes > 0)
|
|
163
|
+
return `${minutes}m ${rest}s`;
|
|
164
|
+
return `${rest}s`;
|
|
165
|
+
}
|
|
166
|
+
/** A field of the wrong type reads as absent, so an odd body is judged not working rather than crashing the read. */
|
|
167
|
+
function viewOf(body) {
|
|
168
|
+
const record = asRecord(body);
|
|
169
|
+
const listed = record["targets"];
|
|
170
|
+
const targets = Array.isArray(listed) ? listed.map((entry) => targetOf(asRecord(entry))) : [];
|
|
171
|
+
const health = asRecord(record["health"]);
|
|
172
|
+
return {
|
|
173
|
+
id: stringOf(record["id"]) ?? "",
|
|
174
|
+
kind: stringOf(record["kind"]),
|
|
175
|
+
name: stringOf(record["name"]) ?? "",
|
|
176
|
+
state: stringOf(record["state"]),
|
|
177
|
+
lastPollAt: stringOf(record["lastPollAt"]),
|
|
178
|
+
protocolVersion: record["protocolVersion"] ?? undefined,
|
|
179
|
+
protocolRefusal: stringOf(record["protocolRefusal"]),
|
|
180
|
+
health: record["health"] === undefined || record["health"] === null
|
|
181
|
+
? undefined
|
|
182
|
+
: {
|
|
183
|
+
ordersHeld: health["ordersHeld"],
|
|
184
|
+
cloudErrors: health["cloudErrors"],
|
|
185
|
+
reportsPending: health["reportsPending"],
|
|
186
|
+
},
|
|
187
|
+
targets,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/** The place as the Launcher wrote it, or the fields it is made of when it wrote none. */
|
|
191
|
+
function targetOf(record) {
|
|
192
|
+
const written = stringOf(record["place"]);
|
|
193
|
+
const parts = ["subscription", "resourceGroup", "cluster", "namespace"]
|
|
194
|
+
.map((key) => stringOf(record[key]))
|
|
195
|
+
.filter((part) => part !== undefined);
|
|
196
|
+
return {
|
|
197
|
+
kind: stringOf(record["kind"]) ?? "unknown",
|
|
198
|
+
place: written ?? (parts.length > 0 ? parts.join("/") : "(no place)"),
|
|
199
|
+
refusedReason: stringOf(record["refusedReason"]),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function asRecord(value) {
|
|
203
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
204
|
+
}
|
|
205
|
+
function stringOf(value) {
|
|
206
|
+
return typeof value === "string" ? value : undefined;
|
|
207
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { FetchAPI } from "@orchestraworks/client";
|
|
2
|
+
import { type CliIo } from "../core/output.js";
|
|
3
|
+
import type { Profile } from "../core/profile.js";
|
|
4
|
+
/** Seconds. The first pause after a failed read, doubled per failure up to {@link RETRY_MAX_SECONDS}. */
|
|
5
|
+
export declare const RETRY_FIRST_SECONDS = 0.5;
|
|
6
|
+
export declare const RETRY_MAX_SECONDS = 8;
|
|
7
|
+
/** Seconds. The pause while no turn is open, doubled per empty pass up to {@link IDLE_MAX_SECONDS}. */
|
|
8
|
+
export declare const IDLE_FIRST_SECONDS = 1;
|
|
9
|
+
/** The platform's own waiting-read budget, so an idle follow reacts no slower than a running one. */
|
|
10
|
+
export declare const IDLE_MAX_SECONDS = 5;
|
|
11
|
+
/**
|
|
12
|
+
* `turn`: the row can change while its turn is open, or may be part of a turn no read has seen end.
|
|
13
|
+
* `background`: the row's turn has ended, but background work it names still updates it in place.
|
|
14
|
+
*/
|
|
15
|
+
export type ItemState = "final" | "turn" | "background";
|
|
16
|
+
export declare class TailUsageError extends Error {
|
|
17
|
+
constructor(message: string);
|
|
18
|
+
}
|
|
19
|
+
export interface TailCommandOptions {
|
|
20
|
+
/** Start after this item; omitted prints the items that already exist first. */
|
|
21
|
+
after?: string;
|
|
22
|
+
untilSettled?: boolean;
|
|
23
|
+
output?: string;
|
|
24
|
+
reveal?: boolean;
|
|
25
|
+
profile?: string;
|
|
26
|
+
baseUrl?: string;
|
|
27
|
+
org?: string;
|
|
28
|
+
}
|
|
29
|
+
/** Every seam a test replaces; production leaves them all undefined. */
|
|
30
|
+
export interface TailDeps {
|
|
31
|
+
env?: NodeJS.ProcessEnv;
|
|
32
|
+
io?: CliIo;
|
|
33
|
+
fetchApi?: FetchAPI;
|
|
34
|
+
loadProfile?: (name?: string) => Profile | undefined;
|
|
35
|
+
sleep?: (seconds: number, signal: AbortSignal) => Promise<void>;
|
|
36
|
+
/** Stops the command cleanly. Omitted, Ctrl-C does. */
|
|
37
|
+
signal?: AbortSignal;
|
|
38
|
+
onExitCode?: (code: number) => void;
|
|
39
|
+
}
|
|
40
|
+
type Json = Record<string, unknown>;
|
|
41
|
+
/** The bounds of one waiting read, compared between passes to tell a stale answer from a new event. */
|
|
42
|
+
interface WaitBounds {
|
|
43
|
+
waitForItem: string;
|
|
44
|
+
waitForAttempt: number;
|
|
45
|
+
waitForSeq: number;
|
|
46
|
+
}
|
|
47
|
+
export declare function tailCommand(id: string, options?: TailCommandOptions, deps?: TailDeps): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* The state of each row, from the row's own fields and the read it came in. One read is one snapshot, so a
|
|
50
|
+
* prompt in it that shows its turn ended means that turn's rows in the same read are as they will stay.
|
|
51
|
+
* A row of a turn whose prompt is not in the read, that no earlier read saw end, and that the session read
|
|
52
|
+
* did not name, counts as changing; its turn is returned in `unseenTurns` for the caller to look up.
|
|
53
|
+
*/
|
|
54
|
+
export declare function classifyItems(window: readonly Json[], endedTurns: Set<string>, openTurnId: string | undefined): {
|
|
55
|
+
states: ItemState[];
|
|
56
|
+
unseenTurns: Set<string>;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* The read answers once the prompt's recorded position reaches `waitForSeq - 1`, so one past the recorded
|
|
60
|
+
* event waits for the next one. A prompt that has not started a run yet carries no attempt: its first run is
|
|
61
|
+
* attempt 1, and the read waits for that run's first event.
|
|
62
|
+
*/
|
|
63
|
+
export declare function waitBoundsFor(promptId: string, prompt: Json): WaitBounds;
|
|
64
|
+
/** Messages and thoughts in full; every other item on one line, from its own fields. */
|
|
65
|
+
export declare function itemLine(item: Json): string;
|
|
66
|
+
export {};
|