@kici-dev/compiler 0.1.26 → 0.2.0
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/auth/headless-detect.d.ts +14 -5
- package/dist/auth/headless-detect.js +50 -9
- package/dist/cli-banner.d.ts +6 -3
- package/dist/cli-banner.js +13 -5
- package/dist/cli.js +180 -48
- package/dist/commands/check-mode.d.ts +1 -1
- package/dist/commands/compile.js +31 -7
- package/dist/commands/diagnostics.js +14 -2
- package/dist/commands/doctor.d.ts +64 -0
- package/dist/commands/doctor.js +413 -0
- package/dist/commands/endpoints.js +6 -0
- package/dist/commands/fixture.js +13 -0
- package/dist/commands/hook.js +3 -2
- package/dist/commands/index.d.ts +13 -1
- package/dist/commands/index.js +10 -3
- package/dist/commands/init-host-os.d.ts +34 -0
- package/dist/commands/init-host-os.js +44 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +160 -37
- package/dist/commands/local-trust-root.d.ts +6 -0
- package/dist/commands/local-trust-root.js +52 -0
- package/dist/commands/local.d.ts +65 -0
- package/dist/commands/local.js +206 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +41 -1
- package/dist/commands/logout.js +7 -0
- package/dist/commands/notifications.d.ts +61 -0
- package/dist/commands/notifications.js +274 -0
- package/dist/commands/preview.js +9 -2
- package/dist/commands/run-banner.d.ts +31 -0
- package/dist/commands/run-banner.js +25 -0
- package/dist/commands/run-routed.d.ts +53 -0
- package/dist/commands/run-routed.js +185 -0
- package/dist/commands/run.d.ts +0 -17
- package/dist/commands/run.js +44 -58
- package/dist/commands/runs/artifacts/download.d.ts +24 -0
- package/dist/commands/runs/artifacts/download.js +154 -0
- package/dist/commands/runs/artifacts/list.d.ts +5 -0
- package/dist/commands/runs/artifacts/list.js +47 -0
- package/dist/commands/runs/cancel.js +2 -2
- package/dist/commands/runs/list.js +8 -2
- package/dist/commands/secrets-list.d.ts +2 -2
- package/dist/commands/secrets-list.js +4 -4
- package/dist/commands/types.d.ts +3 -3
- package/dist/commands/types.js +4 -4
- package/dist/commands/verify-attestation.d.ts +3 -1
- package/dist/commands/verify-attestation.js +18 -7
- package/dist/errors/formatter.d.ts +14 -1
- package/dist/errors/formatter.js +13 -3
- package/dist/errors/index.d.ts +2 -1
- package/dist/errors/index.js +3 -2
- package/dist/errors/source-location.d.ts +20 -0
- package/dist/errors/source-location.js +45 -0
- package/dist/execution/executor.js +32 -12
- package/dist/fixtures/defaults/index.js +2 -1
- package/dist/generators/secrets-dts.d.ts +9 -9
- package/dist/generators/secrets-dts.js +12 -12
- package/dist/llm-context/llms-architecture.txt +50 -21
- package/dist/llm-context/llms-cli.txt +2667 -1454
- package/dist/llm-context/llms-features.txt +484 -414
- package/dist/llm-context/llms-full.txt +6703 -4687
- package/dist/llm-context/llms-getting-started.txt +311 -55
- package/dist/llm-context/llms-patterns.txt +17 -29
- package/dist/llm-context/llms-providers.txt +10 -1
- package/dist/llm-context/llms-sdk-runtime.txt +2013 -0
- package/dist/llm-context/llms-sdk.txt +596 -2157
- package/dist/llm-context/llms.txt +31 -17
- package/dist/local-plane/orchestrator-process.d.ts +70 -0
- package/dist/local-plane/orchestrator-process.js +129 -0
- package/dist/local-plane/os-mismatch-hint.d.ts +16 -0
- package/dist/local-plane/os-mismatch-hint.js +34 -0
- package/dist/local-plane/paths.d.ts +39 -0
- package/dist/local-plane/paths.js +54 -0
- package/dist/local-plane/plane-liveness.d.ts +68 -0
- package/dist/local-plane/plane-liveness.js +145 -0
- package/dist/local-plane/plane-manager.d.ts +193 -0
- package/dist/local-plane/plane-manager.js +480 -0
- package/dist/local-plane/plane-seed.d.ts +76 -0
- package/dist/local-plane/plane-seed.js +59 -0
- package/dist/local-plane/plane-trigger.d.ts +71 -0
- package/dist/local-plane/plane-trigger.js +110 -0
- package/dist/local-plane/platform-attach.d.ts +53 -0
- package/dist/local-plane/platform-attach.js +107 -0
- package/dist/local-plane/port-holder.d.ts +78 -0
- package/dist/local-plane/port-holder.js +227 -0
- package/dist/local-plane/postgres.d.ts +56 -0
- package/dist/local-plane/postgres.js +187 -0
- package/dist/local-plane/resolve-plane.d.ts +37 -0
- package/dist/local-plane/resolve-plane.js +76 -0
- package/dist/local-plane/run-follow.d.ts +61 -0
- package/dist/local-plane/run-follow.js +151 -0
- package/dist/local-plane/scaler-config.d.ts +68 -0
- package/dist/local-plane/scaler-config.js +132 -0
- package/dist/local-plane/secret-seed.d.ts +59 -0
- package/dist/local-plane/secret-seed.js +112 -0
- package/dist/local-plane/source-provider.d.ts +43 -0
- package/dist/local-plane/source-provider.js +159 -0
- package/dist/local-plane/trusted-routing.d.ts +32 -0
- package/dist/local-plane/trusted-routing.js +47 -0
- package/dist/lockfile/generator.d.ts +14 -1
- package/dist/lockfile/generator.js +103 -37
- package/dist/lockfile/index.d.ts +3 -1
- package/dist/lockfile/index.js +3 -2
- package/dist/lockfile/purity-diagnostics.d.ts +31 -0
- package/dist/lockfile/purity-diagnostics.js +52 -0
- package/dist/postinstall.js +2 -1
- package/dist/remote/artifact-extract.d.ts +8 -0
- package/dist/remote/artifact-extract.js +58 -0
- package/dist/remote/config.d.ts +21 -3
- package/dist/remote/config.js +24 -5
- package/dist/remote/dashboard-client.d.ts +46 -9
- package/dist/remote/dashboard-client.js +54 -11
- package/dist/remote/fs-case.d.ts +21 -0
- package/dist/remote/fs-case.js +45 -0
- package/dist/remote/history.d.ts +9 -3
- package/dist/remote/history.js +79 -10
- package/dist/remote/local-repo-identity.d.ts +1 -1
- package/dist/remote/local-repo-identity.js +2 -1
- package/dist/remote/notifications-client.d.ts +149 -0
- package/dist/remote/notifications-client.js +103 -0
- package/dist/remote/oauth.d.ts +13 -0
- package/dist/remote/oauth.js +31 -5
- package/dist/remote/output/summary.js +76 -14
- package/dist/remote/platform-client.d.ts +1 -1
- package/dist/remote/render.js +30 -9
- package/dist/{local-executor → remote}/secret-loader.d.ts +1 -1
- package/dist/{local-executor → remote}/secret-loader.js +4 -4
- package/dist/remote/secret-upload.d.ts +1 -1
- package/dist/remote/secret-upload.js +2 -2
- package/dist/remote/uploader.d.ts +1 -1
- package/dist/remote/uploader.js +7 -6
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +8 -8
- package/dist/templates/index.d.ts +1 -1
- package/dist/templates/index.js +2 -2
- package/dist/templates/package-json.d.ts +15 -0
- package/dist/templates/package-json.js +26 -5
- package/dist/test-runner/dry-run.d.ts +2 -1
- package/dist/test-runner/dry-run.js +18 -1
- package/dist/test-runner/event-types.d.ts +2 -0
- package/dist/test-runner/event-types.js +3 -0
- package/dist/test-runner/job-executor.d.ts +1 -0
- package/dist/test-runner/job-executor.js +82 -44
- package/dist/test-runner/output-formatter.d.ts +5 -2
- package/dist/test-runner/output-formatter.js +6 -4
- package/dist/test-runner/payload-builder.d.ts +7 -1
- package/dist/test-runner/payload-builder.js +11 -2
- package/dist/test-runner/rule-evaluator.d.ts +7 -3
- package/dist/test-runner/rule-evaluator.js +13 -12
- package/dist/{local-executor → test-runner}/runs-on-display.js +1 -1
- package/dist/test-runner/step-context.d.ts +23 -5
- package/dist/test-runner/step-context.js +29 -119
- package/dist/types.d.ts +26 -7
- package/dist/types.js +4 -2
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.js +2 -1
- package/dist/validation/typecheck.d.ts +28 -0
- package/dist/validation/typecheck.js +110 -0
- package/dist/validation/validator.d.ts +9 -4
- package/dist/validation/validator.js +38 -44
- package/package.json +13 -13
- package/sbom.spdx.json +9311 -1528
- package/dist/assets/api-TJJVHrjC.json +0 -118
- package/dist/assets/descriptor-BTtjzN9L.json +0 -1382
- package/dist/assets/package-BpQF9kR8.json +0 -74
- package/dist/assets/package-Ceo2h27X.json +0 -89
- package/dist/assets/source_context-D0atuL28.json +0 -20
- package/dist/assets/type-BFqO8SCZ.json +0 -202
- package/dist/commands/cancel.d.ts +0 -22
- package/dist/commands/detect-package-manager.d.ts +0 -42
- package/dist/commands/held-run-resolve.d.ts +0 -50
- package/dist/commands/status.d.ts +0 -34
- package/dist/commands/test.d.ts +0 -88
- package/dist/errors/codes.d.ts +0 -25
- package/dist/local-executor/dag-scheduler.d.ts +0 -44
- package/dist/local-executor/dag-scheduler.js +0 -183
- package/dist/local-executor/index.d.ts +0 -23
- package/dist/local-executor/index.js +0 -378
- package/dist/local-executor/job-runner.d.ts +0 -47
- package/dist/local-executor/job-runner.js +0 -411
- package/dist/local-executor/materializer.d.ts +0 -44
- package/dist/local-executor/materializer.js +0 -132
- package/dist/local-executor/output-streamer.d.ts +0 -31
- package/dist/local-executor/output-streamer.js +0 -168
- package/dist/local-executor/payload-generator.d.ts +0 -16
- package/dist/local-executor/payload-generator.js +0 -138
- package/dist/local-executor/picker.d.ts +0 -33
- package/dist/local-executor/picker.js +0 -109
- package/dist/local-executor/to-event-payload.d.ts +0 -16
- package/dist/local-executor/to-event-payload.js +0 -21
- package/dist/local-executor/types.d.ts +0 -93
- package/dist/local-executor/types.js +0 -2
- package/dist/local-executor/workflow-lock.d.ts +0 -82
- package/dist/local-executor/workflow-lock.js +0 -0
- package/dist/package-F7UXSDHW.json +0 -74
- package/dist/remote/client.d.ts +0 -210
- package/dist/remote/observer.d.ts +0 -81
- package/dist/test-runner/summary.d.ts +0 -7
- /package/dist/{local-executor → test-runner}/runs-on-display.d.ts +0 -0
package/dist/remote/history.js
CHANGED
|
@@ -5,6 +5,7 @@ import path from "node:path";
|
|
|
5
5
|
import pc from "picocolors";
|
|
6
6
|
import fs from "node:fs/promises";
|
|
7
7
|
import { formatDuration } from "@kici-dev/core";
|
|
8
|
+
import { ExecutionJobStatus, ExecutionRunStatus, toCanonicalStatus } from "@kici-dev/engine";
|
|
8
9
|
import picomatch from "picomatch";
|
|
9
10
|
//#region src/remote/history.ts
|
|
10
11
|
/**
|
|
@@ -95,7 +96,8 @@ var RunHistory = class {
|
|
|
95
96
|
for (const entry of entries) {
|
|
96
97
|
const id = entry.runId.padEnd(idWidth);
|
|
97
98
|
const fixture = entry.fixtureId.padEnd(fixtureWidth);
|
|
98
|
-
const
|
|
99
|
+
const statusPad = Math.max(0, 12 - statusLabelWidth(entry.status));
|
|
100
|
+
const status = formatStatus(entry.status) + " ".repeat(statusPad);
|
|
99
101
|
const duration = entry.durationMs ? formatDuration(entry.durationMs).padEnd(12) : "-".padEnd(12);
|
|
100
102
|
const started = formatRelativeTime(entry.startedAt);
|
|
101
103
|
lines.push(`${id}${fixture}${status}${duration}${started}`);
|
|
@@ -129,18 +131,85 @@ var RunHistory = class {
|
|
|
129
131
|
}
|
|
130
132
|
};
|
|
131
133
|
/**
|
|
132
|
-
*
|
|
134
|
+
* Short label and colour for every canonical status in the run-history table.
|
|
135
|
+
*
|
|
136
|
+
* Exhaustive by type, so a new engine status breaks this file's typecheck
|
|
137
|
+
* rather than making the history table print the literal string `undefined`.
|
|
138
|
+
*
|
|
139
|
+
* `label` and `color` are stored separately so the table's column width can be
|
|
140
|
+
* measured on the plain label: padding a colour-wrapped string measures the
|
|
141
|
+
* ANSI escape bytes too, which silently collapses the column.
|
|
133
142
|
*/
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
143
|
+
const STATUS_DISPLAY = Object.freeze({
|
|
144
|
+
[ExecutionRunStatus.enum.success]: {
|
|
145
|
+
label: "pass",
|
|
146
|
+
color: pc.green
|
|
147
|
+
},
|
|
148
|
+
[ExecutionRunStatus.enum.failed]: {
|
|
149
|
+
label: "fail",
|
|
150
|
+
color: pc.red
|
|
151
|
+
},
|
|
152
|
+
[ExecutionJobStatus.enum.timed_out_stale]: {
|
|
153
|
+
label: "timeout",
|
|
154
|
+
color: pc.red
|
|
155
|
+
},
|
|
156
|
+
[ExecutionJobStatus.enum.drift_dropped]: {
|
|
157
|
+
label: "dropped",
|
|
158
|
+
color: pc.red
|
|
159
|
+
},
|
|
160
|
+
[ExecutionJobStatus.enum.unroutable]: {
|
|
161
|
+
label: "unroutable",
|
|
162
|
+
color: pc.red
|
|
163
|
+
},
|
|
164
|
+
[ExecutionRunStatus.enum.cancelled]: {
|
|
165
|
+
label: "cancel",
|
|
166
|
+
color: pc.yellow
|
|
167
|
+
},
|
|
168
|
+
[ExecutionRunStatus.enum.cancelling]: {
|
|
169
|
+
label: "cancelling",
|
|
170
|
+
color: pc.yellow
|
|
171
|
+
},
|
|
172
|
+
[ExecutionJobStatus.enum.recovering]: {
|
|
173
|
+
label: "recovering",
|
|
174
|
+
color: pc.yellow
|
|
175
|
+
},
|
|
176
|
+
[ExecutionRunStatus.enum.held]: {
|
|
177
|
+
label: "held",
|
|
178
|
+
color: pc.yellow
|
|
179
|
+
},
|
|
180
|
+
[ExecutionRunStatus.enum.running]: {
|
|
181
|
+
label: "running",
|
|
182
|
+
color: pc.blue
|
|
183
|
+
},
|
|
184
|
+
[ExecutionJobStatus.enum.queued]: {
|
|
185
|
+
label: "queued",
|
|
186
|
+
color: pc.dim
|
|
187
|
+
},
|
|
188
|
+
[ExecutionRunStatus.enum.pending]: {
|
|
189
|
+
label: "pending",
|
|
190
|
+
color: pc.dim
|
|
191
|
+
},
|
|
192
|
+
[ExecutionJobStatus.enum.skipped]: {
|
|
193
|
+
label: "skipped",
|
|
194
|
+
color: pc.dim
|
|
141
195
|
}
|
|
196
|
+
});
|
|
197
|
+
/** The plain (uncoloured) width of a status cell, for column padding. */
|
|
198
|
+
function statusLabelWidth(status) {
|
|
199
|
+
const canonical = toCanonicalStatus(status.toLowerCase());
|
|
200
|
+
return canonical === void 0 ? status.length : STATUS_DISPLAY[canonical].label.length;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Format a run status with its colour and short label. A status this CLI does
|
|
204
|
+
* not recognise — a history file written by a newer version — renders verbatim.
|
|
205
|
+
*/
|
|
206
|
+
function formatStatus(status) {
|
|
207
|
+
const canonical = toCanonicalStatus(status.toLowerCase());
|
|
208
|
+
if (canonical === void 0) return pc.gray(status);
|
|
209
|
+
const { label, color } = STATUS_DISPLAY[canonical];
|
|
210
|
+
return color(label);
|
|
142
211
|
}
|
|
143
212
|
//#endregion
|
|
144
|
-
export { RunHistory };
|
|
213
|
+
export { RunHistory, formatStatus, statusLabelWidth };
|
|
145
214
|
|
|
146
215
|
//# sourceMappingURL=history.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
/** Git hosts whose origin URL we can turn into a real `owner/repo` + web link. */
|
|
3
3
|
export declare const RecognizedProvider: z.ZodEnum<{
|
|
4
|
+
bitbucket: "bitbucket";
|
|
4
5
|
github: "github";
|
|
5
6
|
gitlab: "gitlab";
|
|
6
|
-
bitbucket: "bitbucket";
|
|
7
7
|
}>;
|
|
8
8
|
export type RecognizedProvider = z.infer<typeof RecognizedProvider>;
|
|
9
9
|
/** The literal provider value stamped when no recognized git origin exists. */
|
|
@@ -29,7 +29,8 @@ function parseGitOrigin(url) {
|
|
|
29
29
|
const urlStyle = /^[a-z]+:\/\/(?:[^@/]+@)?([^/]+)\/(.+?)(?:\.git)?$/.exec(trimmed);
|
|
30
30
|
const match = scp ?? urlStyle;
|
|
31
31
|
if (!match) return null;
|
|
32
|
-
const
|
|
32
|
+
const host = match[1].toLowerCase();
|
|
33
|
+
const provider = HOST_PROVIDER[host];
|
|
33
34
|
if (!provider) return null;
|
|
34
35
|
const repoIdentifier = match[2].replace(/^\/+|\/+$/g, "");
|
|
35
36
|
if (!repoIdentifier.includes("/")) return null;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed client for the Platform's org-scoped notification API — the routes the
|
|
3
|
+
* dashboard Notifications tab uses (channels, subscriptions, and the Layer 1
|
|
4
|
+
* Slack-identity roster). Authenticated with the stored PAT + active org,
|
|
5
|
+
* exactly like {@link DashboardClient}, and reachable programmatically via the
|
|
6
|
+
* `kici notifications …` CLI.
|
|
7
|
+
*
|
|
8
|
+
* It composes a {@link DashboardClient} (same auth / org-scoped-URL / error
|
|
9
|
+
* mapping) rather than re-implementing the transport: every path here is
|
|
10
|
+
* relative to `/api/v1/orgs/:orgId/notifications/…`.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { DashboardClientError } from './dashboard-client.js';
|
|
14
|
+
/**
|
|
15
|
+
* Notification protocol enums mirrored from the hosted Platform's notification
|
|
16
|
+
* route contract. The public `kici` CLI cannot import the private Platform
|
|
17
|
+
* package, so these values are re-declared here and reused across the client,
|
|
18
|
+
* the command arg parsing, and their tests (the single source of truth on the
|
|
19
|
+
* CLI side).
|
|
20
|
+
*/
|
|
21
|
+
export declare const NotificationChannelKind: z.ZodEnum<{
|
|
22
|
+
email: "email";
|
|
23
|
+
slack: "slack";
|
|
24
|
+
}>;
|
|
25
|
+
export type NotificationChannelKind = z.infer<typeof NotificationChannelKind>;
|
|
26
|
+
export declare const NotificationSubLevel: z.ZodEnum<{
|
|
27
|
+
job: "job";
|
|
28
|
+
run: "run";
|
|
29
|
+
}>;
|
|
30
|
+
export type NotificationSubLevel = z.infer<typeof NotificationSubLevel>;
|
|
31
|
+
export declare const NotificationScopeKind: z.ZodEnum<{
|
|
32
|
+
actor: "actor";
|
|
33
|
+
org: "org";
|
|
34
|
+
team: "team";
|
|
35
|
+
user: "user";
|
|
36
|
+
}>;
|
|
37
|
+
export type NotificationScopeKind = z.infer<typeof NotificationScopeKind>;
|
|
38
|
+
export declare const RosterSubjectKind: z.ZodEnum<{
|
|
39
|
+
email: "email";
|
|
40
|
+
git_login: "git_login";
|
|
41
|
+
kici_user: "kici_user";
|
|
42
|
+
}>;
|
|
43
|
+
export type RosterSubjectKind = z.infer<typeof RosterSubjectKind>;
|
|
44
|
+
export declare const RosterInputForm: z.ZodEnum<{
|
|
45
|
+
email: "email";
|
|
46
|
+
id: "id";
|
|
47
|
+
username: "username";
|
|
48
|
+
}>;
|
|
49
|
+
export type RosterInputForm = z.infer<typeof RosterInputForm>;
|
|
50
|
+
/** A notification channel row as returned by the channels list route. */
|
|
51
|
+
export interface NotificationChannel {
|
|
52
|
+
id: string;
|
|
53
|
+
type: string;
|
|
54
|
+
name: string;
|
|
55
|
+
managed?: boolean;
|
|
56
|
+
created_at?: string;
|
|
57
|
+
}
|
|
58
|
+
/** A notification subscription row as returned by the subscriptions list route. */
|
|
59
|
+
export interface NotificationSubscription {
|
|
60
|
+
id: string;
|
|
61
|
+
level: string;
|
|
62
|
+
channel_id: string;
|
|
63
|
+
scope_type: string;
|
|
64
|
+
scope_id: string | null;
|
|
65
|
+
on_status: string[];
|
|
66
|
+
repo_glob: string | null;
|
|
67
|
+
workflow_glob: string | null;
|
|
68
|
+
job_glob: string | null;
|
|
69
|
+
mentions: string[] | null;
|
|
70
|
+
accumulate_for: number | null;
|
|
71
|
+
enabled: boolean;
|
|
72
|
+
source: string;
|
|
73
|
+
}
|
|
74
|
+
/** A Slack-identity roster row as returned by the roster list route. */
|
|
75
|
+
export interface SlackIdentity {
|
|
76
|
+
id: string;
|
|
77
|
+
connection_id: string;
|
|
78
|
+
subject_kind: string;
|
|
79
|
+
subject_value: string;
|
|
80
|
+
slack_member_id: string;
|
|
81
|
+
input_form: string;
|
|
82
|
+
status: string;
|
|
83
|
+
}
|
|
84
|
+
/** Body for creating a Slack channel. */
|
|
85
|
+
export interface CreateSlackChannelBody {
|
|
86
|
+
type: 'slack';
|
|
87
|
+
connection_id: string;
|
|
88
|
+
slack_channel_id: string;
|
|
89
|
+
name: string;
|
|
90
|
+
}
|
|
91
|
+
/** Body for creating an email channel. */
|
|
92
|
+
export interface CreateEmailChannelBody {
|
|
93
|
+
type: 'email';
|
|
94
|
+
name: string;
|
|
95
|
+
from_name?: string;
|
|
96
|
+
reply_to?: string;
|
|
97
|
+
}
|
|
98
|
+
export type CreateChannelBody = CreateSlackChannelBody | CreateEmailChannelBody;
|
|
99
|
+
/** Body for creating a subscription (mirrors the Platform create route schema). */
|
|
100
|
+
export interface CreateSubscriptionBody {
|
|
101
|
+
level: NotificationSubLevel;
|
|
102
|
+
channel_id: string;
|
|
103
|
+
scope_type: NotificationScopeKind;
|
|
104
|
+
scope_id?: string | null;
|
|
105
|
+
on_status: string[];
|
|
106
|
+
repo_glob?: string | null;
|
|
107
|
+
workflow_glob?: string | null;
|
|
108
|
+
job_glob?: string | null;
|
|
109
|
+
mentions?: string[] | null;
|
|
110
|
+
recipient_override?: string[] | null;
|
|
111
|
+
on_failure_class?: string[] | null;
|
|
112
|
+
accumulate_for?: number | null;
|
|
113
|
+
}
|
|
114
|
+
/** Body for adding a roster identity (mirrors the Platform add route schema). */
|
|
115
|
+
export interface AddIdentityBody {
|
|
116
|
+
connection_id: string;
|
|
117
|
+
subject_kind: RosterSubjectKind;
|
|
118
|
+
subject_value: string;
|
|
119
|
+
input_form: RosterInputForm;
|
|
120
|
+
value: string;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* PAT + org-scoped client for the notification routes. Construct via
|
|
124
|
+
* {@link NotificationsClient.load}, which reads `~/.kici/config` and resolves
|
|
125
|
+
* the target org (`--org` override or the saved active org).
|
|
126
|
+
*/
|
|
127
|
+
export declare class NotificationsClient {
|
|
128
|
+
private readonly dashboard;
|
|
129
|
+
private constructor();
|
|
130
|
+
/**
|
|
131
|
+
* Load the authenticated client. `opts.org` overrides the saved active org
|
|
132
|
+
* for this invocation; otherwise the saved `activeOrgId` is used. Throws a
|
|
133
|
+
* {@link DashboardClientError} when the PAT / endpoint / org is missing.
|
|
134
|
+
*/
|
|
135
|
+
static load(opts?: {
|
|
136
|
+
org?: string;
|
|
137
|
+
}): Promise<NotificationsClient>;
|
|
138
|
+
listChannels(): Promise<NotificationChannel[]>;
|
|
139
|
+
createChannel(body: CreateChannelBody): Promise<NotificationChannel>;
|
|
140
|
+
deleteChannel(id: string): Promise<void>;
|
|
141
|
+
listSubscriptions(): Promise<NotificationSubscription[]>;
|
|
142
|
+
createSubscription(body: CreateSubscriptionBody): Promise<NotificationSubscription>;
|
|
143
|
+
deleteSubscription(id: string): Promise<void>;
|
|
144
|
+
listIdentities(): Promise<SlackIdentity[]>;
|
|
145
|
+
addIdentity(body: AddIdentityBody): Promise<SlackIdentity>;
|
|
146
|
+
deleteIdentity(id: string): Promise<void>;
|
|
147
|
+
}
|
|
148
|
+
export { DashboardClientError };
|
|
149
|
+
//# sourceMappingURL=notifications-client.d.ts.map
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { loadGlobalConfig } from "./config.js";
|
|
3
|
+
import { DashboardClient, DashboardClientError } from "./dashboard-client.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
//#region src/remote/notifications-client.ts
|
|
6
|
+
/**
|
|
7
|
+
* Typed client for the Platform's org-scoped notification API — the routes the
|
|
8
|
+
* dashboard Notifications tab uses (channels, subscriptions, and the Layer 1
|
|
9
|
+
* Slack-identity roster). Authenticated with the stored PAT + active org,
|
|
10
|
+
* exactly like {@link DashboardClient}, and reachable programmatically via the
|
|
11
|
+
* `kici notifications …` CLI.
|
|
12
|
+
*
|
|
13
|
+
* It composes a {@link DashboardClient} (same auth / org-scoped-URL / error
|
|
14
|
+
* mapping) rather than re-implementing the transport: every path here is
|
|
15
|
+
* relative to `/api/v1/orgs/:orgId/notifications/…`.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Notification protocol enums mirrored from the hosted Platform's notification
|
|
19
|
+
* route contract. The public `kici` CLI cannot import the private Platform
|
|
20
|
+
* package, so these values are re-declared here and reused across the client,
|
|
21
|
+
* the command arg parsing, and their tests (the single source of truth on the
|
|
22
|
+
* CLI side).
|
|
23
|
+
*/
|
|
24
|
+
const NotificationChannelKind = z.enum(["slack", "email"]);
|
|
25
|
+
const NotificationSubLevel = z.enum(["run", "job"]);
|
|
26
|
+
const NotificationScopeKind = z.enum([
|
|
27
|
+
"org",
|
|
28
|
+
"team",
|
|
29
|
+
"user",
|
|
30
|
+
"actor"
|
|
31
|
+
]);
|
|
32
|
+
const RosterSubjectKind = z.enum([
|
|
33
|
+
"kici_user",
|
|
34
|
+
"git_login",
|
|
35
|
+
"email"
|
|
36
|
+
]);
|
|
37
|
+
const RosterInputForm = z.enum([
|
|
38
|
+
"id",
|
|
39
|
+
"username",
|
|
40
|
+
"email"
|
|
41
|
+
]);
|
|
42
|
+
const rowSchema = z.record(z.string(), z.unknown());
|
|
43
|
+
const channelsListSchema = z.object({ channels: z.array(rowSchema).default([]) });
|
|
44
|
+
const subscriptionsListSchema = z.object({ subscriptions: z.array(rowSchema).default([]) });
|
|
45
|
+
const identitiesListSchema = z.object({ identities: z.array(rowSchema).default([]) });
|
|
46
|
+
/**
|
|
47
|
+
* PAT + org-scoped client for the notification routes. Construct via
|
|
48
|
+
* {@link NotificationsClient.load}, which reads `~/.kici/config` and resolves
|
|
49
|
+
* the target org (`--org` override or the saved active org).
|
|
50
|
+
*/
|
|
51
|
+
var NotificationsClient = class NotificationsClient {
|
|
52
|
+
dashboard;
|
|
53
|
+
constructor(dashboard) {
|
|
54
|
+
this.dashboard = dashboard;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Load the authenticated client. `opts.org` overrides the saved active org
|
|
58
|
+
* for this invocation; otherwise the saved `activeOrgId` is used. Throws a
|
|
59
|
+
* {@link DashboardClientError} when the PAT / endpoint / org is missing.
|
|
60
|
+
*/
|
|
61
|
+
static async load(opts = {}) {
|
|
62
|
+
const config = await loadGlobalConfig();
|
|
63
|
+
const effective = opts.org ? {
|
|
64
|
+
...config,
|
|
65
|
+
activeOrgId: opts.org
|
|
66
|
+
} : config;
|
|
67
|
+
return new NotificationsClient(DashboardClient.fromConfig(effective));
|
|
68
|
+
}
|
|
69
|
+
async listChannels() {
|
|
70
|
+
const { channels } = channelsListSchema.parse(await this.dashboard.getJson("notifications/channels"));
|
|
71
|
+
return channels;
|
|
72
|
+
}
|
|
73
|
+
async createChannel(body) {
|
|
74
|
+
return await this.dashboard.postJson("notifications/channels", body);
|
|
75
|
+
}
|
|
76
|
+
async deleteChannel(id) {
|
|
77
|
+
await this.dashboard.deleteJson(`notifications/channels/${encodeURIComponent(id)}`);
|
|
78
|
+
}
|
|
79
|
+
async listSubscriptions() {
|
|
80
|
+
const { subscriptions } = subscriptionsListSchema.parse(await this.dashboard.getJson("notifications/subscriptions"));
|
|
81
|
+
return subscriptions;
|
|
82
|
+
}
|
|
83
|
+
async createSubscription(body) {
|
|
84
|
+
return await this.dashboard.postJson("notifications/subscriptions", body);
|
|
85
|
+
}
|
|
86
|
+
async deleteSubscription(id) {
|
|
87
|
+
await this.dashboard.deleteJson(`notifications/subscriptions/${encodeURIComponent(id)}`);
|
|
88
|
+
}
|
|
89
|
+
async listIdentities() {
|
|
90
|
+
const { identities } = identitiesListSchema.parse(await this.dashboard.getJson("notifications/slack/identities"));
|
|
91
|
+
return identities;
|
|
92
|
+
}
|
|
93
|
+
async addIdentity(body) {
|
|
94
|
+
return await this.dashboard.postJson("notifications/slack/identities", body);
|
|
95
|
+
}
|
|
96
|
+
async deleteIdentity(id) {
|
|
97
|
+
await this.dashboard.deleteJson(`notifications/slack/identities/${encodeURIComponent(id)}`);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
//#endregion
|
|
101
|
+
export { DashboardClientError, NotificationChannelKind, NotificationScopeKind, NotificationSubLevel, NotificationsClient, RosterInputForm, RosterSubjectKind };
|
|
102
|
+
|
|
103
|
+
//# sourceMappingURL=notifications-client.js.map
|
package/dist/remote/oauth.d.ts
CHANGED
|
@@ -4,6 +4,19 @@ interface PkceFlowOptions {
|
|
|
4
4
|
issuer: string;
|
|
5
5
|
/** OAuth client ID for the CLI application */
|
|
6
6
|
clientId: string;
|
|
7
|
+
/**
|
|
8
|
+
* Delay before the "still waiting" nudge is printed. A testing seam, not a
|
|
9
|
+
* user-facing knob — no CLI flag or env var sets it.
|
|
10
|
+
*/
|
|
11
|
+
nudgeAfterMs?: number;
|
|
12
|
+
/**
|
|
13
|
+
* How long to wait for the browser callback before giving up. A testing seam,
|
|
14
|
+
* not a user-facing knob — no CLI flag or env var sets it. The timeout message
|
|
15
|
+
* states five minutes literally, so a non-default value produces a message
|
|
16
|
+
* whose duration does not match; that is acceptable only because no user can
|
|
17
|
+
* set this. Promoting it to a real option means deriving the duration from it.
|
|
18
|
+
*/
|
|
19
|
+
timeoutMs?: number;
|
|
7
20
|
}
|
|
8
21
|
/** Options for the RFC 8628 device authorization flow. */
|
|
9
22
|
interface DeviceFlowOptions {
|
package/dist/remote/oauth.js
CHANGED
|
@@ -78,6 +78,22 @@ const SUCCESS_HTML = `<!DOCTYPE html>
|
|
|
78
78
|
</body>
|
|
79
79
|
</html>`;
|
|
80
80
|
/**
|
|
81
|
+
* Turn a callback-server `listen` failure into an actionable message.
|
|
82
|
+
*
|
|
83
|
+
* The wording differs by cause on purpose: naming `KICI_CALLBACK_PORT` when the
|
|
84
|
+
* port was ephemeral misdirects the user, and reporting "already in use" for a
|
|
85
|
+
* permission error is a false diagnosis.
|
|
86
|
+
*/
|
|
87
|
+
function describeListenFailure(err, listenPort) {
|
|
88
|
+
const escapes = "Retry with `kici login --device` (no local callback needed), or set KICI_CALLBACK_PORT to a free port your firewall allows.";
|
|
89
|
+
if (err.code === "EADDRINUSE") {
|
|
90
|
+
if (listenPort === 0) return `No local port was available for the login callback server. ${escapes}`;
|
|
91
|
+
return `Port ${listenPort} (KICI_CALLBACK_PORT) is already in use, so the login callback server could not start. ${escapes}`;
|
|
92
|
+
}
|
|
93
|
+
if (err.code === "EACCES") return `Permission denied binding port ${listenPort} (KICI_CALLBACK_PORT) for the login callback server — ports below 1024 need elevated privileges. ${escapes}`;
|
|
94
|
+
return `Could not start the local callback server on port ${listenPort}: ${err.message}. ${escapes}`;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
81
97
|
* PKCE authorization code flow with localhost callback.
|
|
82
98
|
*
|
|
83
99
|
* Spins up a temporary HTTP server on a random port, opens the browser
|
|
@@ -90,20 +106,20 @@ const SUCCESS_HTML = `<!DOCTYPE html>
|
|
|
90
106
|
* @returns OIDC access token
|
|
91
107
|
*/
|
|
92
108
|
async function pkceFlow(opts) {
|
|
93
|
-
const { issuer, clientId } = opts;
|
|
109
|
+
const { issuer, clientId, nudgeAfterMs = 9e4, timeoutMs = 300 * 1e3 } = opts;
|
|
94
110
|
let listenPort = 0;
|
|
95
111
|
const callbackPortEnv = process.env.KICI_CALLBACK_PORT;
|
|
96
112
|
if (callbackPortEnv) {
|
|
97
113
|
const parsed = parseInt(callbackPortEnv, 10);
|
|
98
|
-
if (isNaN(parsed) || parsed < 0) throw new Error(`KICI_CALLBACK_PORT must be a
|
|
114
|
+
if (isNaN(parsed) || parsed < 0 || parsed > 65535) throw new Error(`KICI_CALLBACK_PORT must be a port number between 0 and 65535, got: "${callbackPortEnv}"`);
|
|
99
115
|
listenPort = parsed;
|
|
100
116
|
}
|
|
101
117
|
const endpoints = await discoverOidcEndpoints(issuer);
|
|
102
118
|
const { verifier, challenge } = generatePkceChallenge();
|
|
103
119
|
const state = randomBytes(16).toString("hex");
|
|
104
|
-
const TIMEOUT_MS = 300 * 1e3;
|
|
105
120
|
return new Promise((resolve, reject) => {
|
|
106
121
|
let timer;
|
|
122
|
+
let nudgeTimer;
|
|
107
123
|
const server = createServer(async (req, res) => {
|
|
108
124
|
const url = new URL(req.url, `http://127.0.0.1`);
|
|
109
125
|
if (url.pathname !== "/callback") {
|
|
@@ -111,6 +127,7 @@ async function pkceFlow(opts) {
|
|
|
111
127
|
res.end("Not found");
|
|
112
128
|
return;
|
|
113
129
|
}
|
|
130
|
+
if (nudgeTimer) clearTimeout(nudgeTimer);
|
|
114
131
|
const code = url.searchParams.get("code");
|
|
115
132
|
const returnedState = url.searchParams.get("state");
|
|
116
133
|
const error = url.searchParams.get("error");
|
|
@@ -167,8 +184,13 @@ async function pkceFlow(opts) {
|
|
|
167
184
|
});
|
|
168
185
|
function cleanup() {
|
|
169
186
|
if (timer) clearTimeout(timer);
|
|
187
|
+
if (nudgeTimer) clearTimeout(nudgeTimer);
|
|
170
188
|
if (server.listening) server.close();
|
|
171
189
|
}
|
|
190
|
+
server.on("error", (err) => {
|
|
191
|
+
cleanup();
|
|
192
|
+
reject(new Error(describeListenFailure(err, listenPort)));
|
|
193
|
+
});
|
|
172
194
|
server.listen(listenPort, "127.0.0.1", () => {
|
|
173
195
|
const actualPort = server.address().port;
|
|
174
196
|
const redirectUri = `http://127.0.0.1:${actualPort}/callback`;
|
|
@@ -194,15 +216,19 @@ async function pkceFlow(opts) {
|
|
|
194
216
|
});
|
|
195
217
|
else {
|
|
196
218
|
console.log(pc.cyan(" Opening browser for authentication..."));
|
|
219
|
+
console.log(pc.dim(` If it does not open, visit:\n ${authUrl.toString()}`));
|
|
197
220
|
open(authUrl.toString()).catch(() => {
|
|
198
221
|
console.log(pc.yellow(` Could not open browser automatically. Please visit:\n ${authUrl.toString()}`));
|
|
199
222
|
});
|
|
200
223
|
}
|
|
201
224
|
});
|
|
225
|
+
nudgeTimer = setTimeout(() => {
|
|
226
|
+
console.log(pc.yellow(" Still waiting for the browser callback...\n If you are still signing in, ignore this. If your browser cannot reach the\n callback, press Ctrl+C and retry with `kici login --device`."));
|
|
227
|
+
}, nudgeAfterMs);
|
|
202
228
|
timer = setTimeout(() => {
|
|
203
229
|
cleanup();
|
|
204
|
-
reject(/* @__PURE__ */ new Error("Authentication timed out after 5 minutes.
|
|
205
|
-
},
|
|
230
|
+
reject(/* @__PURE__ */ new Error("Authentication timed out after 5 minutes. If your browser cannot reach the local callback, retry with `kici login --device` to authenticate without one."));
|
|
231
|
+
}, timeoutMs);
|
|
206
232
|
});
|
|
207
233
|
}
|
|
208
234
|
/** Sleep helper for device flow polling. */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "../../rolldown-runtime-ClRpJifh.js";
|
|
2
2
|
import pc from "picocolors";
|
|
3
3
|
import { formatDuration } from "@kici-dev/core";
|
|
4
|
+
import { ExecutionJobStatus, ExecutionRunStatus, toCanonicalStatus } from "@kici-dev/engine";
|
|
4
5
|
//#region src/remote/output/summary.ts
|
|
5
6
|
/**
|
|
6
7
|
* Completion summary output formatters.
|
|
@@ -73,25 +74,86 @@ function formatMultiFixtureSummary(results) {
|
|
|
73
74
|
parts.push(`${total} total`);
|
|
74
75
|
return `Fixtures: ${parts.join(", ")}`;
|
|
75
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Icon-and-label text plus colour for every canonical job status in the
|
|
79
|
+
* summary table.
|
|
80
|
+
*
|
|
81
|
+
* Exhaustive by type: a new engine status breaks this file's typecheck rather
|
|
82
|
+
* than printing an uncoloured raw enum spelling, which carries no severity
|
|
83
|
+
* signal for a status a user needs to spot (`timed_out_stale`, `drift_dropped`).
|
|
84
|
+
*
|
|
85
|
+
* One table, not two: the padding width reads the same `text` the renderer
|
|
86
|
+
* prints, so the icon column and the width reserved for it cannot disagree.
|
|
87
|
+
*/
|
|
88
|
+
const JOB_STATUS_DISPLAY = Object.freeze({
|
|
89
|
+
[ExecutionRunStatus.enum.success]: {
|
|
90
|
+
text: "✓ pass",
|
|
91
|
+
color: pc.green
|
|
92
|
+
},
|
|
93
|
+
[ExecutionRunStatus.enum.failed]: {
|
|
94
|
+
text: "✗ fail",
|
|
95
|
+
color: pc.red
|
|
96
|
+
},
|
|
97
|
+
[ExecutionJobStatus.enum.timed_out_stale]: {
|
|
98
|
+
text: "✗ timeout",
|
|
99
|
+
color: pc.red
|
|
100
|
+
},
|
|
101
|
+
[ExecutionJobStatus.enum.drift_dropped]: {
|
|
102
|
+
text: "✗ dropped",
|
|
103
|
+
color: pc.red
|
|
104
|
+
},
|
|
105
|
+
[ExecutionJobStatus.enum.unroutable]: {
|
|
106
|
+
text: "✗ unroutable",
|
|
107
|
+
color: pc.red
|
|
108
|
+
},
|
|
109
|
+
[ExecutionRunStatus.enum.cancelled]: {
|
|
110
|
+
text: "! cancel",
|
|
111
|
+
color: pc.yellow
|
|
112
|
+
},
|
|
113
|
+
[ExecutionRunStatus.enum.cancelling]: {
|
|
114
|
+
text: "! cancelling",
|
|
115
|
+
color: pc.yellow
|
|
116
|
+
},
|
|
117
|
+
[ExecutionJobStatus.enum.recovering]: {
|
|
118
|
+
text: "~ recovering",
|
|
119
|
+
color: pc.yellow
|
|
120
|
+
},
|
|
121
|
+
[ExecutionRunStatus.enum.held]: {
|
|
122
|
+
text: "~ held",
|
|
123
|
+
color: pc.yellow
|
|
124
|
+
},
|
|
125
|
+
[ExecutionRunStatus.enum.running]: {
|
|
126
|
+
text: "> running",
|
|
127
|
+
color: pc.cyan
|
|
128
|
+
},
|
|
129
|
+
[ExecutionJobStatus.enum.queued]: {
|
|
130
|
+
text: "- queued",
|
|
131
|
+
color: pc.dim
|
|
132
|
+
},
|
|
133
|
+
[ExecutionRunStatus.enum.pending]: {
|
|
134
|
+
text: "- pending",
|
|
135
|
+
color: pc.dim
|
|
136
|
+
},
|
|
137
|
+
[ExecutionJobStatus.enum.skipped]: {
|
|
138
|
+
text: "- skip",
|
|
139
|
+
color: pc.dim
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
/** The status cell's plain text \u2014 the padding width and the rendered cell share it. */
|
|
143
|
+
function statusDisplayText(status) {
|
|
144
|
+
const canonical = toCanonicalStatus(status.toLowerCase());
|
|
145
|
+
return canonical !== void 0 ? JOB_STATUS_DISPLAY[canonical].text : status;
|
|
146
|
+
}
|
|
76
147
|
/** Format a job status with icon and color. */
|
|
77
148
|
function formatJobStatus(status) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
case "cancelled": return pc.yellow("! cancel");
|
|
83
|
-
default: return status;
|
|
84
|
-
}
|
|
149
|
+
const canonical = toCanonicalStatus(status.toLowerCase());
|
|
150
|
+
if (canonical === void 0) return status;
|
|
151
|
+
const { text, color } = JOB_STATUS_DISPLAY[canonical];
|
|
152
|
+
return color(text);
|
|
85
153
|
}
|
|
86
154
|
/** Get the visual text length for a status (for padding). */
|
|
87
155
|
function statusTextLength(status) {
|
|
88
|
-
|
|
89
|
-
case "success": return 6;
|
|
90
|
-
case "failed": return 6;
|
|
91
|
-
case "skipped": return 6;
|
|
92
|
-
case "cancelled": return 8;
|
|
93
|
-
default: return status.length;
|
|
94
|
-
}
|
|
156
|
+
return statusDisplayText(status).length;
|
|
95
157
|
}
|
|
96
158
|
//#endregion
|
|
97
159
|
export { formatErrorHighlight, formatMultiFixtureSummary, formatSummary };
|
|
@@ -94,7 +94,7 @@ export interface PlatformTriggerResponse {
|
|
|
94
94
|
status: 'accepted' | 'rejected';
|
|
95
95
|
reason?: string;
|
|
96
96
|
jobIds?: string[];
|
|
97
|
-
/** User-visible warnings on acceptance (e.g. skipped non-test bound
|
|
97
|
+
/** User-visible warnings on acceptance (e.g. skipped non-test bound contexts). */
|
|
98
98
|
warnings?: string[];
|
|
99
99
|
}
|
|
100
100
|
export interface PlatformRunStatusResponse {
|
package/dist/remote/render.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
2
|
import pc from "picocolors";
|
|
3
3
|
import { formatDuration } from "@kici-dev/core";
|
|
4
|
+
import { ExecutionJobStatus, ExecutionRunStatus, toCanonicalStatus } from "@kici-dev/engine";
|
|
4
5
|
//#region src/remote/render.ts
|
|
5
6
|
/** Shared terminal-render helpers for the diagnostics + runs commands. */
|
|
6
7
|
const ANSI_SGR = /\[[0-9;]*m/g;
|
|
@@ -21,18 +22,38 @@ function relativeTime(iso, now = Date.now()) {
|
|
|
21
22
|
if (hr < 24) return `${hr}h ago`;
|
|
22
23
|
return `${Math.round(hr / 24)}d ago`;
|
|
23
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Terminal colour for every canonical status.
|
|
27
|
+
*
|
|
28
|
+
* Exhaustive by type: a new engine status breaks this file's typecheck rather
|
|
29
|
+
* than falling through to gray, which in a bare terminal reads as "nothing
|
|
30
|
+
* happened".
|
|
31
|
+
*
|
|
32
|
+
* `drift_dropped` is red here although the dashboard badges it gray. The
|
|
33
|
+
* dashboard pairs its colour with a "Drift dropped" label that carries the
|
|
34
|
+
* meaning; the CLI prints the bare status word, so colour is the only severity
|
|
35
|
+
* signal and a dropped job is a failure.
|
|
36
|
+
*/
|
|
37
|
+
const STATUS_COLORIZER = Object.freeze({
|
|
38
|
+
[ExecutionRunStatus.enum.success]: pc.green,
|
|
39
|
+
[ExecutionRunStatus.enum.failed]: pc.red,
|
|
40
|
+
[ExecutionJobStatus.enum.timed_out_stale]: pc.red,
|
|
41
|
+
[ExecutionJobStatus.enum.drift_dropped]: pc.red,
|
|
42
|
+
[ExecutionJobStatus.enum.unroutable]: pc.red,
|
|
43
|
+
[ExecutionRunStatus.enum.running]: pc.cyan,
|
|
44
|
+
[ExecutionJobStatus.enum.recovering]: pc.yellow,
|
|
45
|
+
[ExecutionRunStatus.enum.cancelling]: pc.yellow,
|
|
46
|
+
[ExecutionRunStatus.enum.cancelled]: pc.yellow,
|
|
47
|
+
[ExecutionRunStatus.enum.held]: pc.yellow,
|
|
48
|
+
[ExecutionRunStatus.enum.pending]: pc.dim,
|
|
49
|
+
[ExecutionJobStatus.enum.queued]: pc.dim,
|
|
50
|
+
[ExecutionJobStatus.enum.skipped]: pc.dim
|
|
51
|
+
});
|
|
24
52
|
/** Color a run/job/step status. picocolors disables itself for NO_COLOR / non-TTY. */
|
|
25
53
|
function colorStatus(status) {
|
|
26
54
|
if (!pc.isColorSupported) return status;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
case "failed":
|
|
30
|
-
case "error":
|
|
31
|
-
case "timed_out": return pc.red(status);
|
|
32
|
-
case "running": return pc.cyan(status);
|
|
33
|
-
case "cancelled": return pc.yellow(status);
|
|
34
|
-
default: return pc.gray(status);
|
|
35
|
-
}
|
|
55
|
+
const canonical = toCanonicalStatus(status.toLowerCase());
|
|
56
|
+
return canonical !== void 0 ? STATUS_COLORIZER[canonical](status) : pc.gray(status);
|
|
36
57
|
}
|
|
37
58
|
/** Width-aligned ASCII table with a bold header row. */
|
|
38
59
|
function renderTable(headers, rows) {
|
|
@@ -5,7 +5,7 @@ import type { ParsedSecrets } from '../test-runner/secrets-file.js';
|
|
|
5
5
|
* Merge order (lowest to highest priority):
|
|
6
6
|
* 1. .kici/.secrets (INI-style, backward compat)
|
|
7
7
|
* 2. .kici/.env.local (dotenv format)
|
|
8
|
-
* 3. .kici/secrets.yaml (YAML with
|
|
8
|
+
* 3. .kici/secrets.yaml (YAML with context scopes, merged flat)
|
|
9
9
|
* 4. --env KEY=VALUE CLI flags
|
|
10
10
|
*
|
|
11
11
|
* Note: process.env is NOT merged here -- it's handled at step-context level.
|