@kici-dev/compiler 0.1.27 → 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.js +120 -11
- package/dist/commands/compile.js +28 -4
- 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 +8 -0
- package/dist/commands/index.js +5 -1
- 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 +159 -36
- package/dist/commands/local.d.ts +28 -2
- package/dist/commands/local.js +74 -5
- package/dist/commands/login.js +1 -1
- package/dist/commands/notifications.d.ts +61 -0
- package/dist/commands/notifications.js +274 -0
- package/dist/commands/preview.js +8 -1
- package/dist/commands/run-routed.js +10 -1
- package/dist/commands/run.js +41 -12
- 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/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 +25 -5
- package/dist/fixtures/defaults/index.js +2 -1
- package/dist/llm-context/llms-architecture.txt +48 -19
- package/dist/llm-context/llms-cli.txt +2461 -1582
- package/dist/llm-context/llms-features.txt +178 -106
- package/dist/llm-context/llms-full.txt +6124 -4423
- package/dist/llm-context/llms-getting-started.txt +306 -42
- package/dist/llm-context/llms-patterns.txt +13 -7
- package/dist/llm-context/llms-sdk-runtime.txt +2013 -0
- package/dist/llm-context/llms-sdk.txt +591 -2152
- package/dist/llm-context/llms.txt +30 -16
- package/dist/local-plane/orchestrator-process.d.ts +12 -7
- package/dist/local-plane/orchestrator-process.js +28 -14
- 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/plane-liveness.d.ts +68 -0
- package/dist/local-plane/plane-liveness.js +145 -0
- package/dist/local-plane/plane-manager.d.ts +60 -18
- package/dist/local-plane/plane-manager.js +210 -70
- package/dist/local-plane/plane-trigger.d.ts +13 -4
- package/dist/local-plane/plane-trigger.js +27 -14
- package/dist/local-plane/platform-attach.js +1 -5
- 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 +15 -3
- package/dist/local-plane/postgres.js +34 -12
- package/dist/local-plane/run-follow.d.ts +20 -0
- package/dist/local-plane/run-follow.js +51 -4
- package/dist/local-plane/scaler-config.d.ts +28 -14
- package/dist/local-plane/scaler-config.js +59 -41
- package/dist/local-plane/source-provider.js +4 -10
- package/dist/lockfile/generator.d.ts +14 -1
- package/dist/lockfile/generator.js +99 -33
- 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 +39 -2
- package/dist/remote/dashboard-client.js +47 -4
- 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/render.js +30 -9
- package/dist/remote/uploader.js +5 -4
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +6 -6
- 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 +81 -43
- 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/test-runner/step-context.d.ts +23 -5
- package/dist/test-runner/step-context.js +28 -118
- package/dist/types.d.ts +21 -2
- 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 +12 -15
- package/sbom.spdx.json +1322 -1964
- 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/index.d.ts +0 -23
- package/dist/local-executor/job-runner.d.ts +0 -47
- package/dist/local-executor/materializer.d.ts +0 -44
- package/dist/local-executor/output-streamer.d.ts +0 -31
- package/dist/local-executor/payload-generator.d.ts +0 -16
- package/dist/local-executor/picker.d.ts +0 -33
- package/dist/local-executor/runs-on-display.d.ts +0 -9
- package/dist/local-executor/secret-loader.d.ts +0 -18
- package/dist/local-executor/to-event-payload.d.ts +0 -16
- package/dist/local-executor/types.d.ts +0 -93
- package/dist/local-executor/workflow-lock.d.ts +0 -82
- 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/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 };
|
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) {
|
package/dist/remote/uploader.js
CHANGED
|
@@ -4,9 +4,9 @@ import path from "node:path";
|
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import { formatBytes, sha256, sha256File } from "@kici-dev/core";
|
|
6
6
|
import { execSync } from "node:child_process";
|
|
7
|
-
import os from "node:os";
|
|
8
|
-
import picomatch from "picomatch";
|
|
9
7
|
import { create } from "tar";
|
|
8
|
+
import { makeTempDir } from "@kici-dev/core/tmp";
|
|
9
|
+
import picomatch from "picomatch";
|
|
10
10
|
//#region src/remote/uploader.ts
|
|
11
11
|
/** Size threshold for warning (50MB) */
|
|
12
12
|
const SIZE_WARN_THRESHOLD = 50 * 1024 * 1024;
|
|
@@ -168,14 +168,15 @@ async function createOverlayTarball(repoRoot, options) {
|
|
|
168
168
|
const modifiedFiles = workingTreeFiles.filter((f) => !untrackedSet.has(f));
|
|
169
169
|
const checksums = {};
|
|
170
170
|
await Promise.all(existingFiles.map(async (file) => {
|
|
171
|
-
|
|
171
|
+
const fullPath = path.join(repoRoot, file);
|
|
172
|
+
checksums[file] = await sha256File(fullPath);
|
|
172
173
|
}));
|
|
173
174
|
const manifest = {
|
|
174
175
|
sha,
|
|
175
176
|
deletions: deletedFiles,
|
|
176
177
|
checksums
|
|
177
178
|
};
|
|
178
|
-
const tmpDir = await
|
|
179
|
+
const { path: tmpDir } = await makeTempDir("overlay", { persist: true });
|
|
179
180
|
const manifestPath = path.join(tmpDir, "manifest.json");
|
|
180
181
|
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
181
182
|
const manifestRelDir = ".kici-overlay-tmp";
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* picked up by Claude Code, Cursor, Aider, and other coding agents that scan
|
|
5
5
|
* the working tree for an authoring context file.
|
|
6
6
|
*/
|
|
7
|
-
export declare const agentsMdTemplate = "# KiCI workflow authoring guide\n\nThis project uses KiCI \u2014 a TypeScript-native CI/CD workflow engine \u2014 instead\nof YAML-based CI. Workflows live in `.kici/workflows/*.ts`, are compiled\ninto a portable lock file, and executed by self-hosted agents.\n\n## Where the API surface lives\n\n- Public SDK types: `node_modules/@kici-dev/sdk/dist/index.d.ts` \u2014 read this\n for the canonical signatures of `workflow`, `job`, `step`, `pr`,\n `push`, `schedule`, `
|
|
7
|
+
export declare const agentsMdTemplate = "# KiCI workflow authoring guide\n\nThis project uses KiCI \u2014 a TypeScript-native CI/CD workflow engine \u2014 instead\nof YAML-based CI. Workflows live in `.kici/workflows/*.ts`, are compiled\ninto a portable lock file, and executed by self-hosted agents.\n\n## Where the API surface lives\n\n- Public SDK types: `node_modules/@kici-dev/sdk/dist/index.d.ts` \u2014 read this\n for the canonical signatures of `workflow`, `job`, `step`, `pr`,\n `push`, `schedule`, `rule`, `dynamicJob`, etc.\n- Bundled offline reference for coding agents: `kici docs llm` prints the\n full markdown documentation bundle to stdout. `kici docs llm --index`\n prints just the curated link index (llms.txt format).\n- Online docs:\n - <https://kici.dev/docs/> \u2014 published docs site.\n - <https://kici.dev/llms.txt> \u2014 curated index for LLM consumers.\n - <https://kici.dev/llms-full.txt> \u2014 full markdown bundle.\n - Key pages: `user/sdk-reference`, `user/workflow-patterns`,\n `user/testing-guide`, `user/hooks`, `user/secrets`.\n\n## The five core patterns\n\n1. **Push trigger** \u2014 `on: push({ branches: 'main' })`. Pair with `paths`\n to scope to subtrees.\n\n ```ts\n import { workflow, job, step, push } from '@kici-dev/sdk';\n\n export default workflow('build', {\n on: push({ branches: 'main' }),\n jobs: [\n job('build', {\n runsOn: 'kici:os:linux',\n steps: [step('install', async ({ $ }) => { await $`pnpm install`; })],\n }),\n ],\n });\n ```\n\n `kici:os:linux` targets any agent reporting that OS \u2014 every agent\n self-reports `kici:os:` / `kici:arch:` / `kici:host:`. Use a custom label\n (e.g. `'gpu'`, `'prod-pool'`) to target a specific agent pool your scaler\n defines.\n\n2. **PR + matrix** \u2014 `pr({ target: 'main' })` plus a matrix over node\n versions. The matrix expands at dispatch time.\n\n ```ts\n import { workflow, job, step, pr } from '@kici-dev/sdk';\n\n export default workflow('test-matrix', {\n on: pr({ target: 'main' }),\n jobs: [\n job('test', {\n runsOn: 'kici:os:linux',\n matrix: { node: ['20', '22', '24'] },\n steps: [\n step('test', async ({ $, matrix }) => {\n await $`echo testing on node ${matrix!.node}`;\n await $`pnpm install`;\n await $`pnpm test`;\n }),\n ],\n }),\n ],\n });\n ```\n\n3. **Lifecycle hooks** \u2014 `onFailure` / `onSuccess` / `onCancel` on a\n job or workflow run after the main steps in their own scope.\n\n4. **Secrets** \u2014 declared scopes resolve at dispatch:\n\n ```ts\n step('deploy', async ({ $, secrets }) => {\n await secrets.expose('DEPLOY_TOKEN');\n await $`./scripts/deploy.sh`;\n });\n ```\n\n Run `kici secrets list` to enumerate the contexts available for testing.\n\n5. **Dynamic jobs** \u2014 `dynamicJob` and `dynamicGroup` build the DAG at\n runtime from a step's outputs. Don't try to compute job names at top level;\n the lock file would be wrong.\n\n## Anti-patterns\n\n- **Do NOT write `.yml` / `.yaml` CI files** \u2014 KiCI replaces that entire\n layer. There is no compatibility shim.\n- **Do NOT `import` from any `@kici-dev/*` package's `/dist/...`\n subpath** \u2014 those are not part of the public API and break across versions.\n Import from the package root.\n- **Do NOT `await` outside step bodies.** The top-level workflow file is\n loaded by the compiler synchronously; async I/O at module scope means the\n lock file emits before it resolves and the workflow appears empty.\n- **Do NOT mutate shared variables between jobs.** Each job runs in its own\n agent process. Use `needs` + step outputs to thread values.\n- **Do NOT hand-edit `kici.lock.json`.** Regenerate it via `kici compile`.\n\n## Local commands a coding agent should run\n\n| Command | Purpose |\n| ------------------------------- | ------------------------------------------- |\n| `pnpm kici compile --check` | Validate workflow source without writing. |\n| `pnpm kici preview pr:open --debug` | Preview which workflows match an event. |\n| `pnpm kici run push --local` | Execute a workflow locally (this machine as an ephemeral agent). |\n| `pnpm kici docs llm` | Print the full LLM documentation bundle. |\n| `pnpm kici docs llm --index` | Print the curated link index. |\n\nIf `pnpm kici` isn't in scripts, fall back to `npx kici`.\n\n## Loop\n\n1. Read the SDK types from `node_modules/@kici-dev/sdk/dist/index.d.ts`.\n2. Pipe `kici docs llm` into the agent's context if it doesn't already have\n the full bundle.\n3. Edit a workflow under `.kici/workflows/`.\n4. Run `kici compile --check` (zero exit means valid).\n5. Run `kici preview <event>` to preview matching.\n6. Run `kici run <event> --local` to execute locally before pushing.\n";
|
|
8
8
|
//# sourceMappingURL=agents-md.d.ts.map
|
|
@@ -16,7 +16,7 @@ into a portable lock file, and executed by self-hosted agents.
|
|
|
16
16
|
|
|
17
17
|
- Public SDK types: \`node_modules/@kici-dev/sdk/dist/index.d.ts\` — read this
|
|
18
18
|
for the canonical signatures of \`workflow\`, \`job\`, \`step\`, \`pr\`,
|
|
19
|
-
\`push\`, \`schedule\`, \`
|
|
19
|
+
\`push\`, \`schedule\`, \`rule\`, \`dynamicJob\`, etc.
|
|
20
20
|
- Bundled offline reference for coding agents: \`kici docs llm\` prints the
|
|
21
21
|
full markdown documentation bundle to stdout. \`kici docs llm --index\`
|
|
22
22
|
prints just the curated link index (llms.txt format).
|
|
@@ -55,20 +55,19 @@ into a portable lock file, and executed by self-hosted agents.
|
|
|
55
55
|
versions. The matrix expands at dispatch time.
|
|
56
56
|
|
|
57
57
|
\`\`\`ts
|
|
58
|
-
import { workflow, job, step, pr
|
|
58
|
+
import { workflow, job, step, pr } from '@kici-dev/sdk';
|
|
59
59
|
|
|
60
60
|
export default workflow('test-matrix', {
|
|
61
61
|
on: pr({ target: 'main' }),
|
|
62
62
|
jobs: [
|
|
63
63
|
job('test', {
|
|
64
64
|
runsOn: 'kici:os:linux',
|
|
65
|
-
|
|
65
|
+
matrix: { node: ['20', '22', '24'] },
|
|
66
66
|
steps: [
|
|
67
67
|
step('test', async ({ $, matrix }) => {
|
|
68
|
-
await $\`node
|
|
68
|
+
await $\`echo testing on node \${matrix!.node}\`;
|
|
69
69
|
await $\`pnpm install\`;
|
|
70
70
|
await $\`pnpm test\`;
|
|
71
|
-
return { node: matrix.node };
|
|
72
71
|
}),
|
|
73
72
|
],
|
|
74
73
|
}),
|
|
@@ -83,7 +82,8 @@ into a portable lock file, and executed by self-hosted agents.
|
|
|
83
82
|
|
|
84
83
|
\`\`\`ts
|
|
85
84
|
step('deploy', async ({ $, secrets }) => {
|
|
86
|
-
await
|
|
85
|
+
await secrets.expose('DEPLOY_TOKEN');
|
|
86
|
+
await $\`./scripts/deploy.sh\`;
|
|
87
87
|
});
|
|
88
88
|
\`\`\`
|
|
89
89
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { helloWorldWorkflow } from './workflows/hello-world.js';
|
|
7
7
|
export { prChecksWorkflow } from './workflows/pr-checks.js';
|
|
8
|
-
export { generatePackageJson } from './package-json.js';
|
|
8
|
+
export { generatePackageJson, sdkDependencyRange } from './package-json.js';
|
|
9
9
|
export { tsconfigTemplate } from './tsconfig-json.js';
|
|
10
10
|
export { agentsMdTemplate } from './agents-md.js';
|
|
11
11
|
/**
|
package/dist/templates/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { agentsMdTemplate } from "./agents-md.js";
|
|
|
3
3
|
import { helloWorldWorkflow } from "./workflows/hello-world.js";
|
|
4
4
|
import { prChecksWorkflow } from "./workflows/pr-checks.js";
|
|
5
5
|
import { tsconfigTemplate } from "./tsconfig-json.js";
|
|
6
|
-
import { generatePackageJson } from "./package-json.js";
|
|
6
|
+
import { generatePackageJson, sdkDependencyRange } from "./package-json.js";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
//#region src/templates/index.ts
|
|
@@ -43,6 +43,6 @@ const templates = {
|
|
|
43
43
|
tsconfig: tsconfigTemplate
|
|
44
44
|
};
|
|
45
45
|
//#endregion
|
|
46
|
-
export { agentsMdTemplate, generatePackageJson, helloWorldWorkflow, prChecksWorkflow, templates, tsconfigTemplate, workflowPaths, workflows };
|
|
46
|
+
export { agentsMdTemplate, generatePackageJson, helloWorldWorkflow, prChecksWorkflow, sdkDependencyRange, templates, tsconfigTemplate, workflowPaths, workflows };
|
|
47
47
|
|
|
48
48
|
//# sourceMappingURL=index.js.map
|
|
@@ -6,6 +6,21 @@
|
|
|
6
6
|
* (or a private Verdaccio instance when .npmrc scopes the registry).
|
|
7
7
|
* The compiler is invoked via npx (not installed as a dependency).
|
|
8
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* The npm version range the scaffold pins `@kici-dev/sdk` to.
|
|
11
|
+
*
|
|
12
|
+
* @param devMode - When true, a prerelease-compatible range (`>=0.0.1-0`) so
|
|
13
|
+
* npm resolves Verdaccio's prerelease builds (e.g. 0.0.1-2856). Semver
|
|
14
|
+
* `^0.0.1` does NOT match prereleases, causing 404s on Verdaccio.
|
|
15
|
+
*/
|
|
16
|
+
export declare function sdkDependencyRange(devMode?: boolean): string;
|
|
17
|
+
/**
|
|
18
|
+
* The TypeScript range scaffolded into a `.kici` workspace. Pinned to the major
|
|
19
|
+
* the compiler is built against so `kici compile --check` (and the `typecheck`
|
|
20
|
+
* script) run the same tsc the compiler expects. Same range in dev and prod
|
|
21
|
+
* mode — TypeScript is a public npm package, not a Verdaccio prerelease.
|
|
22
|
+
*/
|
|
23
|
+
export declare const TYPESCRIPT_RANGE = "^6.0.3";
|
|
9
24
|
/**
|
|
10
25
|
* Generate package.json content for .kici/ directory
|
|
11
26
|
*
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
2
|
//#region src/templates/package-json.ts
|
|
3
|
-
const sdkVersion = "0.
|
|
3
|
+
const sdkVersion = "0.2.0";
|
|
4
|
+
/**
|
|
5
|
+
* The npm version range the scaffold pins `@kici-dev/sdk` to.
|
|
6
|
+
*
|
|
7
|
+
* @param devMode - When true, a prerelease-compatible range (`>=0.0.1-0`) so
|
|
8
|
+
* npm resolves Verdaccio's prerelease builds (e.g. 0.0.1-2856). Semver
|
|
9
|
+
* `^0.0.1` does NOT match prereleases, causing 404s on Verdaccio.
|
|
10
|
+
*/
|
|
11
|
+
function sdkDependencyRange(devMode = false) {
|
|
12
|
+
return devMode ? ">=0.0.1-0" : `^${sdkVersion}`;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The TypeScript range scaffolded into a `.kici` workspace. Pinned to the major
|
|
16
|
+
* the compiler is built against so `kici compile --check` (and the `typecheck`
|
|
17
|
+
* script) run the same tsc the compiler expects. Same range in dev and prod
|
|
18
|
+
* mode — TypeScript is a public npm package, not a Verdaccio prerelease.
|
|
19
|
+
*/
|
|
20
|
+
const TYPESCRIPT_RANGE = "^6.0.3";
|
|
4
21
|
/**
|
|
5
22
|
* Generate package.json content for .kici/ directory
|
|
6
23
|
*
|
|
@@ -10,7 +27,7 @@ const sdkVersion = "0.1.27";
|
|
|
10
27
|
* @returns JSON string with proper formatting (2-space indent, trailing newline)
|
|
11
28
|
*/
|
|
12
29
|
function generatePackageJson(devMode = false) {
|
|
13
|
-
|
|
30
|
+
const pkg = {
|
|
14
31
|
name: "@kici-dev/workflows",
|
|
15
32
|
private: true,
|
|
16
33
|
type: "module",
|
|
@@ -18,10 +35,14 @@ function generatePackageJson(devMode = false) {
|
|
|
18
35
|
compile: "npx --yes kici@latest compile",
|
|
19
36
|
typecheck: "tsc --noEmit"
|
|
20
37
|
},
|
|
21
|
-
devDependencies: {
|
|
22
|
-
|
|
38
|
+
devDependencies: {
|
|
39
|
+
"@kici-dev/sdk": sdkDependencyRange(devMode),
|
|
40
|
+
typescript: TYPESCRIPT_RANGE
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
return JSON.stringify(pkg, null, 2) + "\n";
|
|
23
44
|
}
|
|
24
45
|
//#endregion
|
|
25
|
-
export { generatePackageJson };
|
|
46
|
+
export { TYPESCRIPT_RANGE, generatePackageJson, sdkDependencyRange };
|
|
26
47
|
|
|
27
48
|
//# sourceMappingURL=package-json.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LockWorkflow } from '../types.js';
|
|
2
|
+
import type { JobPurityWarning } from '../lockfile/purity-diagnostics.js';
|
|
2
3
|
import type { WorkflowDecision } from '@kici-dev/engine';
|
|
3
4
|
interface DryRunOptions {
|
|
4
5
|
workflow?: string;
|
|
@@ -7,6 +8,6 @@ interface DryRunOptions {
|
|
|
7
8
|
/**
|
|
8
9
|
* Display dry-run output showing what would execute.
|
|
9
10
|
*/
|
|
10
|
-
export declare function displayDryRun(workflows: readonly LockWorkflow[], decisions: WorkflowDecision[], options: DryRunOptions): void;
|
|
11
|
+
export declare function displayDryRun(workflows: readonly LockWorkflow[], decisions: WorkflowDecision[], options: DryRunOptions, purityWarnings?: JobPurityWarning[]): void;
|
|
11
12
|
export {};
|
|
12
13
|
//# sourceMappingURL=dry-run.d.ts.map
|
|
@@ -3,11 +3,26 @@ import pc from "picocolors";
|
|
|
3
3
|
import { logger } from "@kici-dev/core";
|
|
4
4
|
//#region src/test-runner/dry-run.ts
|
|
5
5
|
/**
|
|
6
|
+
* Print the injected `__init__` job line for each impure dynamic value on a job,
|
|
7
|
+
* so the ~5-10s init-job cost is visible before the first run. Returns the number
|
|
8
|
+
* of lines rendered so the caller can count the jobs it actually surfaced.
|
|
9
|
+
*/
|
|
10
|
+
function renderJobInitWarnings(purityWarnings, workflowName, jobName) {
|
|
11
|
+
let rendered = 0;
|
|
12
|
+
for (const w of purityWarnings) {
|
|
13
|
+
if (w.workflowName !== workflowName || w.jobName !== jobName) continue;
|
|
14
|
+
logger.info(pc.yellow(` ⚠ __init__ job required (~5-10s): ${w.field} is not pure — ${w.reason}`));
|
|
15
|
+
rendered++;
|
|
16
|
+
}
|
|
17
|
+
return rendered;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
6
20
|
* Display dry-run output showing what would execute.
|
|
7
21
|
*/
|
|
8
|
-
function displayDryRun(workflows, decisions, options) {
|
|
22
|
+
function displayDryRun(workflows, decisions, options, purityWarnings = []) {
|
|
9
23
|
logger.info(pc.bold("\n🔍 DRY RUN - No commands will be executed\n"));
|
|
10
24
|
const matchedWorkflows = decisions.filter((d) => d.matched);
|
|
25
|
+
const injectedInitJobs = /* @__PURE__ */ new Set();
|
|
11
26
|
if (matchedWorkflows.length === 0) {
|
|
12
27
|
logger.info(pc.yellow("No workflows matched the event.\n"));
|
|
13
28
|
displayDecisionSummary(decisions);
|
|
@@ -33,6 +48,7 @@ function displayDryRun(workflows, decisions, options) {
|
|
|
33
48
|
else logger.info(pc.gray(` matrix: [dynamic]`));
|
|
34
49
|
logger.info(pc.gray(` steps (${job.steps.length}):`));
|
|
35
50
|
for (const step of job.steps) logger.info(pc.gray(` - ${step.name}`));
|
|
51
|
+
if (renderJobInitWarnings(purityWarnings, decision.workflowName, job.name) > 0) injectedInitJobs.add(`${decision.workflowName} ${job.name}`);
|
|
36
52
|
}
|
|
37
53
|
const dynamicJobs = workflow.jobs.filter((j) => j._type === "dynamic");
|
|
38
54
|
if (dynamicJobs.length > 0) {
|
|
@@ -41,6 +57,7 @@ function displayDryRun(workflows, decisions, options) {
|
|
|
41
57
|
}
|
|
42
58
|
logger.info("");
|
|
43
59
|
}
|
|
60
|
+
if (injectedInitJobs.size > 0) logger.info(pc.yellow(`⚠ ${injectedInitJobs.size} __init__ job(s) will be injected for impure dynamic values (~5-10s each).`));
|
|
44
61
|
displayDecisionSummary(decisions);
|
|
45
62
|
logger.info(pc.green("✓ Dry run complete\n"));
|
|
46
63
|
}
|
|
@@ -169,6 +169,7 @@ function parseEventArg(arg) {
|
|
|
169
169
|
workflowName: "test",
|
|
170
170
|
status: "cancelled"
|
|
171
171
|
};
|
|
172
|
+
case "workflows_failed_batch": return { type: "workflows_failed_batch" };
|
|
172
173
|
case "job_complete": return {
|
|
173
174
|
type: "job_complete",
|
|
174
175
|
workflowName: "test",
|
|
@@ -256,6 +257,7 @@ function triggerToEventArg(trigger) {
|
|
|
256
257
|
const status = trigger.status?.[0];
|
|
257
258
|
return status ? `workflow_complete:${status}` : "workflow_complete";
|
|
258
259
|
}
|
|
260
|
+
case "workflows_failed_batch": return "workflows_failed_batch";
|
|
259
261
|
case "job_complete": {
|
|
260
262
|
const status = trigger.status?.[0];
|
|
261
263
|
return status ? `job_complete:${status}` : "job_complete";
|
|
@@ -317,6 +319,7 @@ function triggerSummary(trigger) {
|
|
|
317
319
|
case "webhook": return `webhook(${joinList(trigger.events)})`;
|
|
318
320
|
case "kici_event": return `kici_event(${trigger.eventName})`;
|
|
319
321
|
case "workflow_complete": return `workflow_complete(${trigger.name ? `${trigger.name}` : "*"}${trigger.status?.length ? `, ${joinList(trigger.status)}` : ""})`;
|
|
322
|
+
case "workflows_failed_batch": return `workflows_failed_batch(${trigger.name ? `${trigger.name}` : "*"}, ${trigger.accumulateFor}ms)`;
|
|
320
323
|
case "job_complete": return `job_complete(${trigger.workflow ?? "*"}${trigger.job ? `.${trigger.job}` : ""}${trigger.status?.length ? `, ${joinList(trigger.status)}` : ""})`;
|
|
321
324
|
case "generic_webhook": return `webhook(${trigger.source})`;
|
|
322
325
|
case "schedule": return `schedule('${trigger.cronExpression}')`;
|