@kici-dev/compiler 0.7.0 → 0.8.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/cli.js +2 -2
- package/dist/commands/local.d.ts +9 -2
- package/dist/commands/local.js +14 -4
- package/dist/commands/report/identity.js +1 -1
- package/dist/commands/run-routed.js +3 -0
- package/dist/commands/run.js +5 -2
- package/dist/commands/runs/logs.js +3 -2
- package/dist/llm-context/llms-architecture.txt +1 -1
- package/dist/llm-context/llms-cli-remote.txt +13 -1
- package/dist/llm-context/llms-cli.txt +4 -2
- package/dist/llm-context/llms-features-execution.txt +1 -1
- package/dist/llm-context/llms-full.txt +32 -7
- package/dist/llm-context/llms-getting-started.txt +2 -2
- package/dist/llm-context/llms-sdk-runtime.txt +11 -0
- package/dist/llm-context/llms.txt +1 -1
- package/dist/local-plane/orchestrator-process.js +3 -0
- package/dist/local-plane/paths.d.ts +1 -0
- package/dist/local-plane/paths.js +1 -0
- package/dist/local-plane/plane-log.d.ts +27 -0
- package/dist/local-plane/plane-log.js +39 -0
- package/dist/local-plane/plane-manager.js +2 -2
- package/dist/local-plane/plane-trigger.d.ts +28 -0
- package/dist/local-plane/plane-trigger.js +57 -2
- package/dist/local-plane/postgres.js +9 -6
- package/dist/local-plane/run-follow.js +2 -1
- package/dist/remote/output/streaming.d.ts +12 -0
- package/dist/remote/output/streaming.js +20 -1
- package/dist/remote/platform-client.d.ts +2 -0
- package/dist/templates/package-json.d.ts +9 -7
- package/dist/templates/package-json.js +11 -9
- package/package.json +6 -6
- package/sbom.spdx.json +123 -123
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { EventLogStatus } from "@kici-dev/engine";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
4
|
import { AdminApiClient } from "@kici-dev/orchestrator";
|
|
4
5
|
//#region src/local-plane/plane-trigger.ts
|
|
@@ -15,6 +16,9 @@ import { AdminApiClient } from "@kici-dev/orchestrator";
|
|
|
15
16
|
* The source's bundle hot-reload is debounced, so a first trigger can land
|
|
16
17
|
* before the plane has registered the (re-pointed) local source. This resends
|
|
17
18
|
* the webhook after a grace window until a run appears or the timeout elapses.
|
|
19
|
+
* When the budget still runs out, the timeout is explained rather than merely
|
|
20
|
+
* reported: the plane's own Raft role and its event-log record for this
|
|
21
|
+
* delivery decide which cause is named.
|
|
18
22
|
*/
|
|
19
23
|
/**
|
|
20
24
|
* Build the GitHub-shaped webhook request the plane's local provider normalizer
|
|
@@ -62,6 +66,50 @@ async function sendLocalTrigger(planeUrl, req) {
|
|
|
62
66
|
deliveryId
|
|
63
67
|
};
|
|
64
68
|
}
|
|
69
|
+
/** Raft role the plane reports, or null when `/cluster/health` cannot be read. */
|
|
70
|
+
async function readPlaneRole(client) {
|
|
71
|
+
try {
|
|
72
|
+
const health = await client.get("/cluster/health");
|
|
73
|
+
return typeof health.role === "string" ? health.role : null;
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** The plane's own record of this delivery, or null when there is none to read. */
|
|
79
|
+
async function readDelivery(client, orgId, deliveryId) {
|
|
80
|
+
try {
|
|
81
|
+
const qs = new URLSearchParams({
|
|
82
|
+
deliveryId,
|
|
83
|
+
orgId,
|
|
84
|
+
limit: "1"
|
|
85
|
+
});
|
|
86
|
+
return (await client.get(`/api/v1/admin/event-log?${qs}`)).deliveries?.[0] ?? null;
|
|
87
|
+
} catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Explain a trigger timeout in one line, from what the plane itself recorded.
|
|
93
|
+
*
|
|
94
|
+
* Ordered most-specific-first, and every branch is a fact read back off the
|
|
95
|
+
* plane rather than an inference: the Raft role it reports, then the status it
|
|
96
|
+
* wrote for THIS delivery, then the delivery id + log path so the developer has
|
|
97
|
+
* a thread to pull even when neither surface answered.
|
|
98
|
+
*/
|
|
99
|
+
async function diagnoseTriggerTimeout(client, ctx) {
|
|
100
|
+
const role = await readPlaneRole(client);
|
|
101
|
+
if (role !== null && role !== "leader") return `plane is not leader yet (election grace period) — it reports Raft role "${role}". A single-node plane should elect itself within seconds; check ${ctx.logPath ?? "the plane log (`kici local logs`)"} for "self-electing as leader".`;
|
|
102
|
+
const delivery = ctx.deliveryId ? await readDelivery(client, ctx.orgId, ctx.deliveryId) : null;
|
|
103
|
+
if (delivery?.status === EventLogStatus.enum.lockfile_missing) {
|
|
104
|
+
const where = ctx.repoBasePath ? ` in ${ctx.repoBasePath}` : "";
|
|
105
|
+
return `no kici.lock.json at ${ctx.sha}${where} — the plane resolved no lock file for this commit, so nothing matched. Make sure .kici/kici.lock.json is committed or present in the working tree the run packs.`;
|
|
106
|
+
}
|
|
107
|
+
if (delivery?.status) {
|
|
108
|
+
const detail = delivery.errorMessage ? ` (${delivery.errorMessage})` : "";
|
|
109
|
+
return `the plane recorded delivery ${ctx.deliveryId} as "${delivery.status}"${detail} but created no run.`;
|
|
110
|
+
}
|
|
111
|
+
return `no run appeared for ${ctx.deliveryId ? `delivery ${ctx.deliveryId}` : "this trigger — the plane never accepted the webhook (no delivery id came back)"}${ctx.logPath ? ` — see ${ctx.logPath}` : ""}`;
|
|
112
|
+
}
|
|
65
113
|
/**
|
|
66
114
|
* Trigger the run and resolve its runId. Sends the synthetic push, then polls
|
|
67
115
|
* the admin runs list filtered by this webhook's routing-key-scoped delivery id
|
|
@@ -90,7 +138,14 @@ async function triggerRun(planeUrl, adminToken, input, opts = {}) {
|
|
|
90
138
|
}
|
|
91
139
|
await sleep(pollIntervalMs);
|
|
92
140
|
}
|
|
93
|
-
|
|
141
|
+
const cause = await diagnoseTriggerTimeout(client, {
|
|
142
|
+
deliveryId,
|
|
143
|
+
orgId: input.orgId,
|
|
144
|
+
sha: input.sha,
|
|
145
|
+
...opts.repoBasePath !== void 0 && { repoBasePath: opts.repoBasePath },
|
|
146
|
+
...opts.logPath !== void 0 && { logPath: opts.logPath }
|
|
147
|
+
});
|
|
148
|
+
throw new Error(`offline run: ${cause}`);
|
|
94
149
|
}
|
|
95
150
|
/** Return the run created by this webhook delivery, or null when none yet. */
|
|
96
151
|
async function findRunByDelivery(client, deliveryId) {
|
|
@@ -105,6 +160,6 @@ function sleep(ms) {
|
|
|
105
160
|
return new Promise((r) => setTimeout(r, ms));
|
|
106
161
|
}
|
|
107
162
|
//#endregion
|
|
108
|
-
export { buildLocalTriggerRequest, sendLocalTrigger, triggerRun };
|
|
163
|
+
export { buildLocalTriggerRequest, diagnoseTriggerTimeout, sendLocalTrigger, triggerRun };
|
|
109
164
|
|
|
110
165
|
//# sourceMappingURL=plane-trigger.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
2
|
import { planePaths, planePorts } from "./paths.js";
|
|
3
|
+
import { rotatePlaneLogIfOversized } from "./plane-log.js";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import fs from "node:fs";
|
|
@@ -104,14 +105,13 @@ async function embeddedClusterIsServing(port) {
|
|
|
104
105
|
/**
|
|
105
106
|
* Start a detached embedded postmaster via `pg_ctl` so it survives the exit of
|
|
106
107
|
* this CLI process (embedded-postgres's in-process server is killed by its own
|
|
107
|
-
* exit hook, so it cannot back a warm plane).
|
|
108
|
-
*
|
|
108
|
+
* exit hook, so it cannot back a warm plane). The caller decides whether a
|
|
109
|
+
* cluster is already serving; this always starts one.
|
|
109
110
|
*/
|
|
110
111
|
async function defaultEmbeddedDaemon(port) {
|
|
111
|
-
const { pgData,
|
|
112
|
-
if (await embeddedClusterIsServing(port)) return;
|
|
112
|
+
const { pgData, pgLogFile } = planePaths();
|
|
113
113
|
const pgCtl = resolvePgCtl();
|
|
114
|
-
await $`${pgCtl} -D ${pgData} -o ${`-p ${port}`} -l ${
|
|
114
|
+
await $`${pgCtl} -D ${pgData} -o ${`-p ${port}`} -l ${pgLogFile} -w start`.quiet();
|
|
115
115
|
}
|
|
116
116
|
/** Stop the detached embedded postmaster (handle-independent, reads the data dir). */
|
|
117
117
|
async function stopEmbeddedDaemon() {
|
|
@@ -141,7 +141,10 @@ async function startPlanePostgres(opts = {}) {
|
|
|
141
141
|
const url = `postgres://kici:kici@127.0.0.1:${port}/kici_local`;
|
|
142
142
|
if (!(opts.forcePodman || process.env.KICI_LOCAL_PG_MODE === "podman")) try {
|
|
143
143
|
await ensureEmbeddedCluster(port);
|
|
144
|
-
await
|
|
144
|
+
if (!await embeddedClusterIsServing(port)) {
|
|
145
|
+
rotatePlaneLogIfOversized(planePaths().pgLogFile);
|
|
146
|
+
await embeddedDaemon(port);
|
|
147
|
+
}
|
|
145
148
|
return {
|
|
146
149
|
url,
|
|
147
150
|
kind: "embedded",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { unwrapStoredLogLine } from "../remote/output/streaming.js";
|
|
2
3
|
import { ExecutionJobStatus, ExecutionRunStatus, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES } from "@kici-dev/engine";
|
|
3
4
|
import { AdminApiClient } from "@kici-dev/orchestrator";
|
|
4
5
|
//#region src/local-plane/run-follow.ts
|
|
@@ -131,7 +132,7 @@ async function drainLogs(client, runId, cursors, onLine) {
|
|
|
131
132
|
const qs = cursor ? `?cursor=${encodeURIComponent(cursor)}` : "";
|
|
132
133
|
const page = await client.get(`/api/v1/admin/runs/${runId}/jobs/${job.jobId}/steps/${step.stepIndex}/logs${qs}`);
|
|
133
134
|
for (const l of page.lines) {
|
|
134
|
-
onLine(l.value);
|
|
135
|
+
onLine(unwrapStoredLogLine(l.value));
|
|
135
136
|
emitted++;
|
|
136
137
|
}
|
|
137
138
|
cursor = page.nextCursor ?? String(page.totalLines);
|
|
@@ -7,6 +7,18 @@
|
|
|
7
7
|
* - Prints step transition headers
|
|
8
8
|
* - Tracks elapsed time with in-place status updates
|
|
9
9
|
*/
|
|
10
|
+
/**
|
|
11
|
+
* The text a stored log line carries.
|
|
12
|
+
*
|
|
13
|
+
* The orchestrator stores every step log line as a JSON envelope —
|
|
14
|
+
* `{"ts":…,"level":"stdout","msg":"…","meta":{}}` — and the Platform relay
|
|
15
|
+
* returns those envelopes verbatim, so a run's log stream is the envelope
|
|
16
|
+
* stream. The dashboard unwraps `msg` before rendering; the terminal must too,
|
|
17
|
+
* or the developer watching `kici run remote` reads raw JSON. A line that is
|
|
18
|
+
* not an envelope (an orchestrator phase marker, a plain line from an older
|
|
19
|
+
* store) passes through unchanged.
|
|
20
|
+
*/
|
|
21
|
+
export declare function unwrapStoredLogLine(line: string): string;
|
|
10
22
|
export declare class StreamingFormatter {
|
|
11
23
|
/** Color assignment per job name. */
|
|
12
24
|
private readonly jobColors;
|
|
@@ -19,6 +19,25 @@ const COLOR_PALETTE = [
|
|
|
19
19
|
pc.magenta,
|
|
20
20
|
pc.cyan
|
|
21
21
|
];
|
|
22
|
+
/**
|
|
23
|
+
* The text a stored log line carries.
|
|
24
|
+
*
|
|
25
|
+
* The orchestrator stores every step log line as a JSON envelope —
|
|
26
|
+
* `{"ts":…,"level":"stdout","msg":"…","meta":{}}` — and the Platform relay
|
|
27
|
+
* returns those envelopes verbatim, so a run's log stream is the envelope
|
|
28
|
+
* stream. The dashboard unwraps `msg` before rendering; the terminal must too,
|
|
29
|
+
* or the developer watching `kici run remote` reads raw JSON. A line that is
|
|
30
|
+
* not an envelope (an orchestrator phase marker, a plain line from an older
|
|
31
|
+
* store) passes through unchanged.
|
|
32
|
+
*/
|
|
33
|
+
function unwrapStoredLogLine(line) {
|
|
34
|
+
if (!line.startsWith("{")) return line;
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(line);
|
|
37
|
+
if (typeof parsed === "object" && parsed !== null && typeof parsed.msg === "string") return parsed.msg;
|
|
38
|
+
} catch {}
|
|
39
|
+
return line;
|
|
40
|
+
}
|
|
22
41
|
var StreamingFormatter = class {
|
|
23
42
|
/** Color assignment per job name. */
|
|
24
43
|
jobColors = /* @__PURE__ */ new Map();
|
|
@@ -119,6 +138,6 @@ var StreamingFormatter = class {
|
|
|
119
138
|
}
|
|
120
139
|
};
|
|
121
140
|
//#endregion
|
|
122
|
-
export { StreamingFormatter };
|
|
141
|
+
export { StreamingFormatter, unwrapStoredLogLine };
|
|
123
142
|
|
|
124
143
|
//# sourceMappingURL=streaming.js.map
|
|
@@ -106,6 +106,8 @@ export interface PlatformRunStatusResponse {
|
|
|
106
106
|
status: string;
|
|
107
107
|
exitCode?: number | null;
|
|
108
108
|
errorMessage?: string | null;
|
|
109
|
+
/** Absent or null from an orchestrator that does not report it. */
|
|
110
|
+
durationMs?: number | null;
|
|
109
111
|
}>;
|
|
110
112
|
done: boolean;
|
|
111
113
|
}
|
|
@@ -7,11 +7,14 @@
|
|
|
7
7
|
* The compiler is invoked via npx (not installed as a dependency).
|
|
8
8
|
*/
|
|
9
9
|
/**
|
|
10
|
-
* The npm version
|
|
10
|
+
* The npm version spec the scaffold pins `@kici-dev/sdk` to.
|
|
11
11
|
*
|
|
12
|
-
* @param devMode - When true,
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* @param devMode - When true, the `latest` dist-tag, so npm resolves whatever
|
|
13
|
+
* build the dev registry (Verdaccio) currently publishes. Dev builds are
|
|
14
|
+
* prereleases such as `0.8.0-9726`, and no semver range reaches them: a
|
|
15
|
+
* prerelease only satisfies a comparator with the same major.minor.patch, so
|
|
16
|
+
* `^0.0.1` misses every one and `>=0.0.1-0` misses every one past 0.0.1.
|
|
17
|
+
* A dist-tag is resolved by name, never by range, so it follows the counter.
|
|
15
18
|
*/
|
|
16
19
|
export declare function sdkDependencyRange(devMode?: boolean): string;
|
|
17
20
|
/**
|
|
@@ -24,9 +27,8 @@ export declare const TYPESCRIPT_RANGE = "^6.0.3";
|
|
|
24
27
|
/**
|
|
25
28
|
* Generate package.json content for .kici/ directory
|
|
26
29
|
*
|
|
27
|
-
* @param devMode - When true,
|
|
28
|
-
*
|
|
29
|
-
* Semver `^0.0.1` does NOT match prereleases, causing 404s on Verdaccio.
|
|
30
|
+
* @param devMode - When true, pins the SDK to the `latest` dist-tag so npm
|
|
31
|
+
* resolves the dev registry's newest prerelease build (see sdkDependencyRange).
|
|
30
32
|
* @returns JSON string with proper formatting (2-space indent, trailing newline)
|
|
31
33
|
*/
|
|
32
34
|
export declare function generatePackageJson(devMode?: boolean): string;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
2
|
//#region src/templates/package-json.ts
|
|
3
|
-
const sdkVersion = "0.
|
|
3
|
+
const sdkVersion = "0.8.0";
|
|
4
4
|
/**
|
|
5
|
-
* The npm version
|
|
5
|
+
* The npm version spec the scaffold pins `@kici-dev/sdk` to.
|
|
6
6
|
*
|
|
7
|
-
* @param devMode - When true,
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* @param devMode - When true, the `latest` dist-tag, so npm resolves whatever
|
|
8
|
+
* build the dev registry (Verdaccio) currently publishes. Dev builds are
|
|
9
|
+
* prereleases such as `0.8.0-9726`, and no semver range reaches them: a
|
|
10
|
+
* prerelease only satisfies a comparator with the same major.minor.patch, so
|
|
11
|
+
* `^0.0.1` misses every one and `>=0.0.1-0` misses every one past 0.0.1.
|
|
12
|
+
* A dist-tag is resolved by name, never by range, so it follows the counter.
|
|
10
13
|
*/
|
|
11
14
|
function sdkDependencyRange(devMode = false) {
|
|
12
|
-
return devMode ? "
|
|
15
|
+
return devMode ? "latest" : `^${sdkVersion}`;
|
|
13
16
|
}
|
|
14
17
|
/**
|
|
15
18
|
* The TypeScript range scaffolded into a `.kici` workspace. Pinned to the major
|
|
@@ -21,9 +24,8 @@ const TYPESCRIPT_RANGE = "^6.0.3";
|
|
|
21
24
|
/**
|
|
22
25
|
* Generate package.json content for .kici/ directory
|
|
23
26
|
*
|
|
24
|
-
* @param devMode - When true,
|
|
25
|
-
*
|
|
26
|
-
* Semver `^0.0.1` does NOT match prereleases, causing 404s on Verdaccio.
|
|
27
|
+
* @param devMode - When true, pins the SDK to the `latest` dist-tag so npm
|
|
28
|
+
* resolves the dev registry's newest prerelease build (see sdkDependencyRange).
|
|
27
29
|
* @returns JSON string with proper formatting (2-space indent, trailing newline)
|
|
28
30
|
*/
|
|
29
31
|
function generatePackageJson(devMode = false) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kici-dev/compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Compiler and CLI for KiCI workflows. Compiles `.kici/workflows/*.ts` to a `kici.lock.json` file consumed by the orchestrator and agents, and runs workflows locally or against a remote orchestrator.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ci",
|
|
@@ -61,17 +61,17 @@
|
|
|
61
61
|
"yaml": "^2.9.0",
|
|
62
62
|
"zod": "^4.4.3",
|
|
63
63
|
"zx": "^8.8.5",
|
|
64
|
-
"@kici-dev/agent": "0.
|
|
65
|
-
"@kici-dev/
|
|
66
|
-
"@kici-dev/
|
|
67
|
-
"@kici-dev/
|
|
64
|
+
"@kici-dev/agent": "0.8.0",
|
|
65
|
+
"@kici-dev/core": "0.8.0",
|
|
66
|
+
"@kici-dev/engine": "0.8.0",
|
|
67
|
+
"@kici-dev/orchestrator": "0.8.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/archiver": "^8.0.0",
|
|
71
71
|
"jszip": "^3.10.1"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
|
-
"@kici-dev/sdk": "0.
|
|
74
|
+
"@kici-dev/sdk": "0.8.0"
|
|
75
75
|
},
|
|
76
76
|
"scripts": {
|
|
77
77
|
"build": "node ../../scripts/build-ts.mjs && tsgo --emitDeclarationOnly",
|