@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
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { selectOverlayFiles } from "../remote/uploader.js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import { execFileSync, execSync } from "node:child_process";
|
|
6
|
+
import { makeTempDir } from "@kici-dev/core/tmp";
|
|
7
|
+
//#region src/local-plane/source-provider.ts
|
|
8
|
+
/**
|
|
9
|
+
* LocalSourceProvider — resolve the workdir a `kici run --local` dispatch
|
|
10
|
+
* registers as a `file://` source for the plane.
|
|
11
|
+
*
|
|
12
|
+
* The plane orchestrator's local provider fetches the lock from
|
|
13
|
+
* `<repoBasePath>/.kici/kici.lock.json` and the ephemeral agent clones
|
|
14
|
+
* `file://<repoBasePath>` at a committed sha. So the resolved workdir must be a
|
|
15
|
+
* git repo whose HEAD carries the workflow + lock the run should execute.
|
|
16
|
+
*
|
|
17
|
+
* Two profiles:
|
|
18
|
+
* - **default (isolated):** an isolated tmp clone at HEAD with the local overlay
|
|
19
|
+
* (dirty + untracked files) applied and committed onto a `kici-local` branch,
|
|
20
|
+
* so the clone-by-sha the agent performs sees uncommitted work without
|
|
21
|
+
* touching the developer's tree.
|
|
22
|
+
* - **`--in-place`:** the repo root directly (ambient state, the profile the CI
|
|
23
|
+
* deploy jobs use). Cleanup is a no-op.
|
|
24
|
+
*/
|
|
25
|
+
/** The `kici-local` branch the isolated profile commits its overlay onto. */
|
|
26
|
+
const LOCAL_RUN_BRANCH = "kici-local";
|
|
27
|
+
/** Max number of overlay files copied concurrently. */
|
|
28
|
+
const COPY_BATCH_SIZE = 32;
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the workdir for an offline routed run.
|
|
31
|
+
*
|
|
32
|
+
* @param opts.inPlace - Use the repo root directly instead of an isolated clone.
|
|
33
|
+
* @param opts.repoRoot - The developer's repo root.
|
|
34
|
+
*/
|
|
35
|
+
async function resolveWorkdir(opts) {
|
|
36
|
+
requireGitRepo(opts.repoRoot);
|
|
37
|
+
return opts.inPlace ? resolveInPlace(opts.repoRoot) : resolveIsolated(opts.repoRoot);
|
|
38
|
+
}
|
|
39
|
+
/** In-place: the repo root, triggered at its current branch + HEAD. */
|
|
40
|
+
function resolveInPlace(repoRoot) {
|
|
41
|
+
const branch = gitOut(repoRoot, [
|
|
42
|
+
"rev-parse",
|
|
43
|
+
"--abbrev-ref",
|
|
44
|
+
"HEAD"
|
|
45
|
+
]);
|
|
46
|
+
const sha = gitOut(repoRoot, ["rev-parse", "HEAD"]);
|
|
47
|
+
return {
|
|
48
|
+
dir: repoRoot,
|
|
49
|
+
ref: `refs/heads/${branch}`,
|
|
50
|
+
sha,
|
|
51
|
+
branch,
|
|
52
|
+
cleanup: async () => {}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Isolated: a tmp clone at HEAD with the local overlay applied and committed
|
|
57
|
+
* onto the `kici-local` branch, then commits so the agent's clone-by-sha
|
|
58
|
+
* carries the work.
|
|
59
|
+
*/
|
|
60
|
+
async function resolveIsolated(repoRoot) {
|
|
61
|
+
const workdir = await makeTempDir("local-run", { persist: true });
|
|
62
|
+
const tmpDir = workdir.path;
|
|
63
|
+
const { sha, existingFiles, deletedFiles } = await selectOverlayFiles(repoRoot);
|
|
64
|
+
execSync(`git clone --no-hardlinks --quiet ${shellQuote(repoRoot)} ${shellQuote(tmpDir)}`, { stdio: "ignore" });
|
|
65
|
+
execSync(`git checkout --quiet ${sha}`, {
|
|
66
|
+
cwd: tmpDir,
|
|
67
|
+
stdio: "ignore"
|
|
68
|
+
});
|
|
69
|
+
await applyOverlay(repoRoot, tmpDir, existingFiles, deletedFiles);
|
|
70
|
+
execFileSync("git", [
|
|
71
|
+
"checkout",
|
|
72
|
+
"-B",
|
|
73
|
+
LOCAL_RUN_BRANCH
|
|
74
|
+
], {
|
|
75
|
+
cwd: tmpDir,
|
|
76
|
+
stdio: "ignore"
|
|
77
|
+
});
|
|
78
|
+
execFileSync("git", ["add", "-A"], {
|
|
79
|
+
cwd: tmpDir,
|
|
80
|
+
stdio: "ignore"
|
|
81
|
+
});
|
|
82
|
+
if (gitOut(tmpDir, ["status", "--porcelain"])) execFileSync("git", [
|
|
83
|
+
"-c",
|
|
84
|
+
"user.email=local@kici.dev",
|
|
85
|
+
"-c",
|
|
86
|
+
"user.name=kici local",
|
|
87
|
+
"commit",
|
|
88
|
+
"--no-verify",
|
|
89
|
+
"--no-gpg-sign",
|
|
90
|
+
"-m",
|
|
91
|
+
"kici run --local overlay"
|
|
92
|
+
], {
|
|
93
|
+
cwd: tmpDir,
|
|
94
|
+
stdio: "ignore"
|
|
95
|
+
});
|
|
96
|
+
const committed = gitOut(tmpDir, ["rev-parse", "HEAD"]);
|
|
97
|
+
return {
|
|
98
|
+
dir: tmpDir,
|
|
99
|
+
ref: `refs/heads/${LOCAL_RUN_BRANCH}`,
|
|
100
|
+
sha: committed,
|
|
101
|
+
branch: LOCAL_RUN_BRANCH,
|
|
102
|
+
cleanup: () => workdir.cleanup()
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** Copy overlay files onto the clone and remove local deletions. */
|
|
106
|
+
async function applyOverlay(repoRoot, tmpDir, existingFiles, deletedFiles) {
|
|
107
|
+
for (let i = 0; i < existingFiles.length; i += COPY_BATCH_SIZE) {
|
|
108
|
+
const batch = existingFiles.slice(i, i + COPY_BATCH_SIZE);
|
|
109
|
+
await Promise.all(batch.map((file) => copyOverlayFile(repoRoot, tmpDir, file)));
|
|
110
|
+
}
|
|
111
|
+
for (let i = 0; i < deletedFiles.length; i += COPY_BATCH_SIZE) {
|
|
112
|
+
const batch = deletedFiles.slice(i, i + COPY_BATCH_SIZE);
|
|
113
|
+
await Promise.all(batch.map((file) => fs.rm(path.join(tmpDir, file), { force: true })));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Copy a single overlay file, preserving its mode. Symlinks are recreated as
|
|
118
|
+
* links (not dereferenced) — the same shape the remote tarball preserves.
|
|
119
|
+
*/
|
|
120
|
+
async function copyOverlayFile(repoRoot, tmpDir, file) {
|
|
121
|
+
const src = path.join(repoRoot, file);
|
|
122
|
+
const dest = path.join(tmpDir, file);
|
|
123
|
+
await fs.mkdir(path.dirname(dest), { recursive: true });
|
|
124
|
+
const srcStat = await fs.lstat(src);
|
|
125
|
+
if (srcStat.isSymbolicLink()) {
|
|
126
|
+
const target = await fs.readlink(src);
|
|
127
|
+
await fs.rm(dest, { force: true });
|
|
128
|
+
await fs.symlink(target, dest);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
await fs.copyFile(src, dest);
|
|
132
|
+
await fs.chmod(dest, srcStat.mode);
|
|
133
|
+
}
|
|
134
|
+
/** Throw an actionable error if `repoRoot` is not a git work tree. */
|
|
135
|
+
function requireGitRepo(repoRoot) {
|
|
136
|
+
try {
|
|
137
|
+
execSync("git rev-parse --is-inside-work-tree", {
|
|
138
|
+
cwd: repoRoot,
|
|
139
|
+
stdio: "ignore"
|
|
140
|
+
});
|
|
141
|
+
} catch {
|
|
142
|
+
throw new Error(`kici run --local needs a git repository, but "${repoRoot}" is not inside a git work tree. Initialize a repo (git init) before running.`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** Run a git command in `cwd` and return trimmed stdout. */
|
|
146
|
+
function gitOut(cwd, args) {
|
|
147
|
+
return execFileSync("git", args, {
|
|
148
|
+
cwd,
|
|
149
|
+
encoding: "utf8"
|
|
150
|
+
}).trim();
|
|
151
|
+
}
|
|
152
|
+
/** Minimal single-quote shell escaping for paths passed to git via execSync. */
|
|
153
|
+
function shellQuote(value) {
|
|
154
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
export { LOCAL_RUN_BRANCH, resolveWorkdir };
|
|
158
|
+
|
|
159
|
+
//# sourceMappingURL=source-provider.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route a `kici run --local --trusted` run onto the plane's trusted label set
|
|
3
|
+
* by appending a routing label to every job's `runsOn` in the workdir lock the
|
|
4
|
+
* plane orchestrator reads.
|
|
5
|
+
*
|
|
6
|
+
* The orchestrator resolves each job's target agent from the lock's `runsOn`
|
|
7
|
+
* selectors (subset match + smallest-set-wins in the scaler label matcher).
|
|
8
|
+
* A default run leaves `runsOn` untouched, so a `runsOn: ['default']` job lands
|
|
9
|
+
* on the sandboxed `['default']` label set — byte-identical to a non-trusted
|
|
10
|
+
* run. `--trusted` appends the non-reserved `self-hosted` label, which only the
|
|
11
|
+
* trusted `['default','self-hosted']` label set carries, forcing every job onto
|
|
12
|
+
* the trusted profile.
|
|
13
|
+
*
|
|
14
|
+
* This is routing-by-label to a PRE-CONFIGURED trusted scaler label set — the
|
|
15
|
+
* `KICI_TRUSTED_ENV` value lives only in that label set's env (the plane's own
|
|
16
|
+
* config), never on a dispatch payload. The lock patch adds a label
|
|
17
|
+
* requirement, not the trusted flag itself.
|
|
18
|
+
*/
|
|
19
|
+
/** Handle to restore the lock to its pre-patch bytes. */
|
|
20
|
+
export interface RunsOnLabelInjection {
|
|
21
|
+
/** Rewrite the original bytes captured before the patch. */
|
|
22
|
+
restore: () => void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Append an exact-match `runsOn` selector for `label` to every job in the lock
|
|
26
|
+
* at `lockPath`, unless the job already requires it. Returns a `restore()` that
|
|
27
|
+
* rewrites the original file bytes (call it in a `finally` — for an in-place run
|
|
28
|
+
* it un-dirties the developer's tree; for an isolated run the throwaway clone is
|
|
29
|
+
* removed anyway).
|
|
30
|
+
*/
|
|
31
|
+
export declare function injectRunsOnLabel(lockPath: string, label: string): RunsOnLabelInjection;
|
|
32
|
+
//# sourceMappingURL=trusted-routing.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
//#region src/local-plane/trusted-routing.ts
|
|
4
|
+
/**
|
|
5
|
+
* Route a `kici run --local --trusted` run onto the plane's trusted label set
|
|
6
|
+
* by appending a routing label to every job's `runsOn` in the workdir lock the
|
|
7
|
+
* plane orchestrator reads.
|
|
8
|
+
*
|
|
9
|
+
* The orchestrator resolves each job's target agent from the lock's `runsOn`
|
|
10
|
+
* selectors (subset match + smallest-set-wins in the scaler label matcher).
|
|
11
|
+
* A default run leaves `runsOn` untouched, so a `runsOn: ['default']` job lands
|
|
12
|
+
* on the sandboxed `['default']` label set — byte-identical to a non-trusted
|
|
13
|
+
* run. `--trusted` appends the non-reserved `self-hosted` label, which only the
|
|
14
|
+
* trusted `['default','self-hosted']` label set carries, forcing every job onto
|
|
15
|
+
* the trusted profile.
|
|
16
|
+
*
|
|
17
|
+
* This is routing-by-label to a PRE-CONFIGURED trusted scaler label set — the
|
|
18
|
+
* `KICI_TRUSTED_ENV` value lives only in that label set's env (the plane's own
|
|
19
|
+
* config), never on a dispatch payload. The lock patch adds a label
|
|
20
|
+
* requirement, not the trusted flag itself.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Append an exact-match `runsOn` selector for `label` to every job in the lock
|
|
24
|
+
* at `lockPath`, unless the job already requires it. Returns a `restore()` that
|
|
25
|
+
* rewrites the original file bytes (call it in a `finally` — for an in-place run
|
|
26
|
+
* it un-dirties the developer's tree; for an isolated run the throwaway clone is
|
|
27
|
+
* removed anyway).
|
|
28
|
+
*/
|
|
29
|
+
function injectRunsOnLabel(lockPath, label) {
|
|
30
|
+
const original = fs.readFileSync(lockPath, "utf-8");
|
|
31
|
+
const lock = JSON.parse(original);
|
|
32
|
+
for (const workflow of lock.workflows ?? []) for (const job of workflow.jobs ?? []) {
|
|
33
|
+
const runsOn = job.runsOn ??= [];
|
|
34
|
+
if (!runsOn.some((m) => m.kind === "exact" && m.value === label)) runsOn.push({
|
|
35
|
+
kind: "exact",
|
|
36
|
+
value: label
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
fs.writeFileSync(lockPath, JSON.stringify(lock, null, 2) + "\n");
|
|
40
|
+
return { restore: () => {
|
|
41
|
+
fs.writeFileSync(lockPath, original);
|
|
42
|
+
} };
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { injectRunsOnLabel };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=trusted-routing.js.map
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import type { StepInput, TriggerConfig } from '@kici-dev/sdk';
|
|
2
2
|
import { type LockFile, type LockTrigger, type LockStepEntry, type WorkflowWithSource } from '../types.js';
|
|
3
|
+
import { type SourceLocation } from '../errors/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Courtesy compatibility warning for `kici compile`.
|
|
6
|
+
*
|
|
7
|
+
* When the current schema version is itself a breaking version
|
|
8
|
+
* (`floor === version`), locks emitted now stamp `minReaderVersion = version`
|
|
9
|
+
* and cannot be read by orchestrators older than that version — return a
|
|
10
|
+
* one-line heads-up naming the required orchestrator schema. When the floor sits
|
|
11
|
+
* below the current version (`floor < version`) the emitted lock is additive
|
|
12
|
+
* over older readers down to the floor, so no warning is warranted (return
|
|
13
|
+
* null). The orchestrator remains the authoritative reject; this is informational.
|
|
14
|
+
*/
|
|
15
|
+
export declare function schemaWindowWarning(floor: number, version: number): string | null;
|
|
3
16
|
/**
|
|
4
17
|
* Detect git repository root by running `git rev-parse --show-toplevel`.
|
|
5
18
|
* Falls back to cwd if not in a git repo.
|
|
@@ -47,7 +60,7 @@ export declare function transformTriggers(triggers?: TriggerConfig[]): readonly
|
|
|
47
60
|
* compiler's naming matches the agent's `extractAndNormalizeSteps` enumeration —
|
|
48
61
|
* the flat-stepIndex invariant.
|
|
49
62
|
*/
|
|
50
|
-
export declare function transformSteps(steps: readonly StepInput[], gitRoot: string): readonly LockStepEntry[];
|
|
63
|
+
export declare function transformSteps(steps: readonly StepInput[], gitRoot: string, jobLocation?: SourceLocation): readonly LockStepEntry[];
|
|
51
64
|
/**
|
|
52
65
|
* Serialize lock file to JSON string.
|
|
53
66
|
*
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
-
import {
|
|
2
|
+
import { compilerError } from "../errors/formatter.js";
|
|
3
|
+
import { locationForJob, locationForWorkflow } from "../errors/source-location.js";
|
|
4
|
+
import "../errors/index.js";
|
|
5
|
+
import { BREAKING_FLOOR as BREAKING_FLOOR$1, SCHEMA_VERSION as SCHEMA_VERSION$1 } from "../types.js";
|
|
3
6
|
import { computeContentHash } from "./hasher.js";
|
|
4
7
|
import { resolveHashFiles } from "./hash-files.js";
|
|
5
8
|
import { analyzePurity } from "./purity-analyzer.js";
|
|
@@ -13,6 +16,21 @@ import { normalizeRunsOnAllToMatchers, normalizeRunsOnToMatchers, runsOnPickFrom
|
|
|
13
16
|
import { execSync } from "node:child_process";
|
|
14
17
|
//#region src/lockfile/generator.ts
|
|
15
18
|
/**
|
|
19
|
+
* Courtesy compatibility warning for `kici compile`.
|
|
20
|
+
*
|
|
21
|
+
* When the current schema version is itself a breaking version
|
|
22
|
+
* (`floor === version`), locks emitted now stamp `minReaderVersion = version`
|
|
23
|
+
* and cannot be read by orchestrators older than that version — return a
|
|
24
|
+
* one-line heads-up naming the required orchestrator schema. When the floor sits
|
|
25
|
+
* below the current version (`floor < version`) the emitted lock is additive
|
|
26
|
+
* over older readers down to the floor, so no warning is warranted (return
|
|
27
|
+
* null). The orchestrator remains the authoritative reject; this is informational.
|
|
28
|
+
*/
|
|
29
|
+
function schemaWindowWarning(floor, version) {
|
|
30
|
+
if (floor < version) return null;
|
|
31
|
+
return `This lock uses schema v${version}, a breaking schema version — orchestrators older than v${version} cannot read it. Upgrade the orchestrator to schema v${version} or newer before it can dispatch from this lock.`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
16
34
|
* Detect git repository root by running `git rev-parse --show-toplevel`.
|
|
17
35
|
* Falls back to cwd if not in a git repo.
|
|
18
36
|
*
|
|
@@ -96,9 +114,11 @@ function generateLockFile(workflowsWithSource) {
|
|
|
96
114
|
});
|
|
97
115
|
return {
|
|
98
116
|
schemaVersion: SCHEMA_VERSION$1,
|
|
117
|
+
minReaderVersion: BREAKING_FLOOR$1,
|
|
99
118
|
source: topLevelSource,
|
|
100
119
|
contentHash: sha256(JSON.stringify({
|
|
101
120
|
schemaVersion: SCHEMA_VERSION$1,
|
|
121
|
+
minReaderVersion: BREAKING_FLOOR$1,
|
|
102
122
|
source: topLevelSource,
|
|
103
123
|
workflows
|
|
104
124
|
})),
|
|
@@ -158,7 +178,7 @@ function transformWorkflow(workflow, sourceFile, exportRef, bundleSource, gitRoo
|
|
|
158
178
|
...workflow.concurrency.max !== void 0 && { max: workflow.concurrency.max }
|
|
159
179
|
} },
|
|
160
180
|
...workflow.timeout !== void 0 && { timeout: workflow.timeout },
|
|
161
|
-
...workflow.approval !== void 0 && { approval: (assertNonStepApprovalScope(workflow.approval, "workflow"), toLockApproval(workflow.approval)) }
|
|
181
|
+
...workflow.approval !== void 0 && { approval: (assertNonStepApprovalScope(workflow.approval, "workflow", locationForWorkflow(sourceFile)), toLockApproval(workflow.approval)) }
|
|
162
182
|
};
|
|
163
183
|
}
|
|
164
184
|
/**
|
|
@@ -316,6 +336,14 @@ function toLockWorkflowComplete(t) {
|
|
|
316
336
|
...t.source !== void 0 && { source: t.source }
|
|
317
337
|
};
|
|
318
338
|
}
|
|
339
|
+
function toLockWorkflowsFailedBatch(t) {
|
|
340
|
+
return {
|
|
341
|
+
_type: "workflows_failed_batch",
|
|
342
|
+
accumulateFor: t.accumulateFor,
|
|
343
|
+
...t.name !== void 0 && { name: t.name },
|
|
344
|
+
...t.source !== void 0 && { source: t.source }
|
|
345
|
+
};
|
|
346
|
+
}
|
|
319
347
|
function toLockJobComplete(t) {
|
|
320
348
|
return {
|
|
321
349
|
_type: "job_complete",
|
|
@@ -383,6 +411,7 @@ function transformOneTrigger(trigger) {
|
|
|
383
411
|
case "WebhookTrigger": return [toLockWebhook(trigger)];
|
|
384
412
|
case "KiciEventTrigger": return [toLockKiciEvent(trigger)];
|
|
385
413
|
case "WorkflowCompleteTrigger": return [toLockWorkflowComplete(trigger)];
|
|
414
|
+
case "WorkflowsFailedBatchTrigger": return [toLockWorkflowsFailedBatch(trigger)];
|
|
386
415
|
case "JobCompleteTrigger": return [toLockJobComplete(trigger)];
|
|
387
416
|
case "GenericWebhookTrigger": return [toLockGenericWebhook(trigger)];
|
|
388
417
|
case "ScheduleTrigger": return [toLockSchedule(trigger)];
|
|
@@ -478,30 +507,31 @@ function normalizeRunsOnForLock(runsOn, jobName) {
|
|
|
478
507
|
* The overlap check compares exact matchers only — a glob/regex include and an
|
|
479
508
|
* exact exclude (or vice versa) cannot be statically known to overlap.
|
|
480
509
|
*/
|
|
481
|
-
function validateRunsOn(runsOn, jobName) {
|
|
510
|
+
function validateRunsOn(runsOn, jobName, location) {
|
|
482
511
|
const { include, exclude } = normalizeRunsOnToMatchers(runsOn, `job '${jobName}' runsOn`);
|
|
483
512
|
const includeExact = new Set(include.filter((m) => m.kind === "exact").map((m) => m.value));
|
|
484
513
|
const overlap = exclude.filter((m) => m.kind === "exact").map((m) => m.value).filter((v) => includeExact.has(v));
|
|
485
|
-
if (overlap.length > 0) throw
|
|
514
|
+
if (overlap.length > 0) throw compilerError("E112", `Job "${jobName}": labels and exclude overlap on [${overlap.join(", ")}]. A label cannot be both required and excluded.`, {
|
|
515
|
+
location,
|
|
516
|
+
suggestion: "Remove the overlapping label(s) from either runsOn or the exclude set."
|
|
517
|
+
});
|
|
486
518
|
}
|
|
487
519
|
/**
|
|
488
|
-
* Transform one
|
|
520
|
+
* Transform one context reference (static name or function) into a lock
|
|
489
521
|
* `{ value, dynamic }` entry. A function element is analyzed for purity: a pure
|
|
490
522
|
* function becomes an inline expression resolvable at two-phase eval; an impure
|
|
491
523
|
* one carries only the `dynamic` flag (the agent runs an init job to resolve it).
|
|
492
524
|
*/
|
|
493
|
-
function
|
|
525
|
+
function transformContextRef(ref) {
|
|
494
526
|
if (typeof ref === "function") {
|
|
495
527
|
const fnSource = ref.toString();
|
|
496
|
-
|
|
497
|
-
if (purity.pure) return {
|
|
528
|
+
if (analyzePurity(fnSource).pure) return {
|
|
498
529
|
value: {
|
|
499
530
|
_type: "inline",
|
|
500
531
|
expression: fnSource
|
|
501
532
|
},
|
|
502
533
|
dynamic: true
|
|
503
534
|
};
|
|
504
|
-
console.warn(`[kici] Job "${jobName}": environment function is not pure (${purity.reason}). An init job will be required, adding ~5-10s delay.`);
|
|
505
535
|
return {
|
|
506
536
|
value: "",
|
|
507
537
|
dynamic: true
|
|
@@ -516,15 +546,25 @@ function transformEnvironmentRef(ref, jobName) {
|
|
|
516
546
|
* Transform a static job to lock file format.
|
|
517
547
|
*/
|
|
518
548
|
function transformJob(job, configPath, index, gitRoot, uuidToName) {
|
|
519
|
-
|
|
520
|
-
if (job.runsOn
|
|
549
|
+
const jobLocation = locationForJob(job, configPath);
|
|
550
|
+
if (job.runsOn !== void 0 && job.runsOnAll !== void 0) throw compilerError("E108", `job '${job.name}': runsOn and runsOnAll are mutually exclusive`, {
|
|
551
|
+
location: jobLocation,
|
|
552
|
+
suggestion: "Set exactly one of runsOn (single agent) or runsOnAll (fan-out to every matching agent)."
|
|
553
|
+
});
|
|
554
|
+
if (job.runsOn === void 0 && job.runsOnAll === void 0) throw compilerError("E109", `job '${job.name}': one of runsOn or runsOnAll is required`, {
|
|
555
|
+
location: jobLocation,
|
|
556
|
+
suggestion: "Add runsOn: \"kici:os:linux\" (or another agent label) to the job."
|
|
557
|
+
});
|
|
521
558
|
if (job.onUnreachable !== void 0 && job.runsOnAll === void 0) console.warn(`[kici] job '${job.name}': onUnreachable is ignored without runsOnAll`);
|
|
522
|
-
if (job.maxParallel !== void 0 && job.maxParallel < 1) throw
|
|
559
|
+
if (job.maxParallel !== void 0 && job.maxParallel < 1) throw compilerError("E110", `job '${job.name}': maxParallel must be >= 1`, {
|
|
560
|
+
location: jobLocation,
|
|
561
|
+
suggestion: "Set maxParallel to a positive integer, or remove it to run unbounded."
|
|
562
|
+
});
|
|
523
563
|
if (!(job.matrix !== void 0 || job.runsOnAll !== void 0) && (job.maxParallel !== void 0 || job.failFast !== void 0)) console.warn(`[kici] job '${job.name}': maxParallel/failFast are ignored without matrix or runsOnAll (no fan-out to bound)`);
|
|
524
|
-
if (job.runsOn !== void 0) validateRunsOn(job.runsOn, job.name);
|
|
525
|
-
const
|
|
526
|
-
const
|
|
527
|
-
if (
|
|
564
|
+
if (job.runsOn !== void 0) validateRunsOn(job.runsOn, job.name, jobLocation);
|
|
565
|
+
const contextFields = {};
|
|
566
|
+
const contextRefs = job.contexts ?? (job.context !== void 0 ? [job.context] : void 0);
|
|
567
|
+
if (contextRefs !== void 0 && contextRefs.length > 0) contextFields.contexts = contextRefs.map((ref) => transformContextRef(ref));
|
|
528
568
|
const envFields = {};
|
|
529
569
|
if (job.env !== void 0) {
|
|
530
570
|
if (typeof job.env === "function") {
|
|
@@ -535,14 +575,16 @@ function transformJob(job, configPath, index, gitRoot, uuidToName) {
|
|
|
535
575
|
_type: "inline",
|
|
536
576
|
expression: fnSource
|
|
537
577
|
};
|
|
538
|
-
else console.warn(`[kici] Job "${job.name}": env function is not pure (${purity.reason}). An init job will be required, adding ~5-10s delay.`);
|
|
539
578
|
} else if (typeof job.env === "object") envFields.env = { ...job.env };
|
|
540
579
|
}
|
|
541
580
|
if (job.resources !== void 0) try {
|
|
542
581
|
validateResourceRequest(job.resources);
|
|
543
582
|
} catch (err) {
|
|
544
583
|
const reason = err instanceof Error ? err.message : String(err);
|
|
545
|
-
throw
|
|
584
|
+
throw compilerError("E111", `Job "${job.name}": invalid resources -- ${reason}`, {
|
|
585
|
+
location: jobLocation,
|
|
586
|
+
suggestion: "Fix the resources request (valid CPU/memory strings, request <= limit)."
|
|
587
|
+
});
|
|
546
588
|
}
|
|
547
589
|
const concurrencyFields = {};
|
|
548
590
|
if (job.concurrencyGroup !== void 0) {
|
|
@@ -554,7 +596,6 @@ function transformJob(job, configPath, index, gitRoot, uuidToName) {
|
|
|
554
596
|
_type: "inline",
|
|
555
597
|
expression: fnSource
|
|
556
598
|
};
|
|
557
|
-
else console.warn(`[kici] Job "${job.name}": concurrencyGroup function is not pure (${purity.reason}). An init job will be required, adding ~5-10s delay.`);
|
|
558
599
|
} else if (typeof job.concurrencyGroup === "string") concurrencyFields.concurrencyGroup = job.concurrencyGroup;
|
|
559
600
|
}
|
|
560
601
|
return {
|
|
@@ -567,7 +608,7 @@ function transformJob(job, configPath, index, gitRoot, uuidToName) {
|
|
|
567
608
|
...job.maxParallel !== void 0 && { maxParallel: job.maxParallel },
|
|
568
609
|
...job.failFast !== void 0 && { failFast: job.failFast },
|
|
569
610
|
...resolveNeedsForLock(job.needs, uuidToName),
|
|
570
|
-
steps: transformSteps(job.steps, gitRoot),
|
|
611
|
+
steps: transformSteps(job.steps, gitRoot, jobLocation),
|
|
571
612
|
matrix: job.matrix ? transformMatrix(job.matrix, job.name, configPath) : void 0,
|
|
572
613
|
include: job.include?.map((inc) => ({ ...inc })),
|
|
573
614
|
exclude: job.exclude?.map((exc) => ({ ...exc })),
|
|
@@ -576,7 +617,8 @@ function transformJob(job, configPath, index, gitRoot, uuidToName) {
|
|
|
576
617
|
...job.checkout !== void 0 && { checkout: job.checkout },
|
|
577
618
|
...job.cache !== void 0 && { cache: normalizeCacheSpecs(job.cache) },
|
|
578
619
|
...job.container !== void 0 && { container: job.container },
|
|
579
|
-
...
|
|
620
|
+
...job.sandbox !== void 0 && { sandbox: job.sandbox },
|
|
621
|
+
...contextFields,
|
|
580
622
|
...envFields,
|
|
581
623
|
...concurrencyFields,
|
|
582
624
|
...job.onCancel !== void 0 && { hasOnCancel: true },
|
|
@@ -589,7 +631,7 @@ function transformJob(job, configPath, index, gitRoot, uuidToName) {
|
|
|
589
631
|
...job.timeout !== void 0 && { timeout: job.timeout },
|
|
590
632
|
...job.resources !== void 0 && { resources: job.resources },
|
|
591
633
|
...job.init !== void 0 && { init: job.init },
|
|
592
|
-
...job.approval !== void 0 && { approval: (assertNonStepApprovalScope(job.approval, "job"), toLockApproval(job.approval)) }
|
|
634
|
+
...job.approval !== void 0 && { approval: (assertNonStepApprovalScope(job.approval, "job", jobLocation), toLockApproval(job.approval)) }
|
|
593
635
|
};
|
|
594
636
|
}
|
|
595
637
|
/**
|
|
@@ -653,15 +695,21 @@ function toLockApproval(c) {
|
|
|
653
695
|
* step-scope-only gate (it fires between a step's check and run), so it is a
|
|
654
696
|
* compile error anywhere else.
|
|
655
697
|
*/
|
|
656
|
-
function assertNonStepApprovalScope(c, scope) {
|
|
657
|
-
if (normalizeApproval(c).when === "drift") throw
|
|
698
|
+
function assertNonStepApprovalScope(c, scope, location) {
|
|
699
|
+
if (normalizeApproval(c).when === "drift") throw compilerError("E113", `approval.when "drift" is only valid on steps (found at ${scope} scope)`, {
|
|
700
|
+
location,
|
|
701
|
+
suggestion: "Move the drift-gated approval onto a step, or use when: \"always\" at job/workflow scope."
|
|
702
|
+
});
|
|
658
703
|
}
|
|
659
704
|
/**
|
|
660
705
|
* Validate a step's approval config: `when: 'drift'` fires between the step's
|
|
661
706
|
* check and run, so it requires a `check` facet. A compile error otherwise.
|
|
662
707
|
*/
|
|
663
|
-
function assertStepApprovalCheckFacet(step) {
|
|
664
|
-
if (step.approval !== void 0 && normalizeApproval(step.approval).when === "drift" && step.check === void 0) throw
|
|
708
|
+
function assertStepApprovalCheckFacet(step, jobLocation) {
|
|
709
|
+
if (step.approval !== void 0 && normalizeApproval(step.approval).when === "drift" && step.check === void 0) throw compilerError("E114", `step '${step.name || "(unnamed)"}': approval.when "drift" requires a check facet`, {
|
|
710
|
+
location: step._sourceLocation ?? jobLocation,
|
|
711
|
+
suggestion: "Add a check facet to the step, or use approval when: \"always\"."
|
|
712
|
+
});
|
|
665
713
|
}
|
|
666
714
|
/**
|
|
667
715
|
* Transform a job's `steps` array into lock-file entries. Sequential steps and
|
|
@@ -670,22 +718,40 @@ function assertStepApprovalCheckFacet(step) {
|
|
|
670
718
|
* compiler's naming matches the agent's `extractAndNormalizeSteps` enumeration —
|
|
671
719
|
* the flat-stepIndex invariant.
|
|
672
720
|
*/
|
|
673
|
-
function transformSteps(steps, gitRoot) {
|
|
721
|
+
function transformSteps(steps, gitRoot, jobLocation) {
|
|
722
|
+
const anchor = jobLocation ?? {
|
|
723
|
+
file: "",
|
|
724
|
+
line: 1,
|
|
725
|
+
column: 1
|
|
726
|
+
};
|
|
674
727
|
const counter = { n: 0 };
|
|
675
728
|
let groupOrdinal = 0;
|
|
676
729
|
return steps.map((entry) => {
|
|
677
|
-
if (isParallelGroup(entry)) return transformParallelGroup(entry, gitRoot, counter, groupOrdinal
|
|
678
|
-
return transformSequentialStep(entry, gitRoot, counter);
|
|
730
|
+
if (isParallelGroup(entry)) return transformParallelGroup(entry, gitRoot, counter, groupOrdinal++, anchor);
|
|
731
|
+
return transformSequentialStep(entry, gitRoot, counter, anchor);
|
|
679
732
|
});
|
|
680
733
|
}
|
|
734
|
+
/** Best step-scoped location: the step's captured call-site, else the job anchor. */
|
|
735
|
+
function stepEntryLocation(entry, jobLocation) {
|
|
736
|
+
return entry._sourceLocation ?? jobLocation;
|
|
737
|
+
}
|
|
681
738
|
/** Validate and transform a `ParallelGroup` into a `LockParallelStep`. */
|
|
682
|
-
function transformParallelGroup(group, gitRoot, counter, groupOrdinal) {
|
|
683
|
-
if (group.steps.length === 0) throw
|
|
739
|
+
function transformParallelGroup(group, gitRoot, counter, groupOrdinal, jobLocation) {
|
|
740
|
+
if (group.steps.length === 0) throw compilerError("E115", "job step: empty parallel group not allowed", {
|
|
741
|
+
location: jobLocation,
|
|
742
|
+
suggestion: "Add at least one step to the parallel group, or remove the group."
|
|
743
|
+
});
|
|
684
744
|
const seen = /* @__PURE__ */ new Set();
|
|
685
745
|
const children = group.steps.map((child) => {
|
|
686
|
-
if (isParallelGroup(child)) throw
|
|
687
|
-
|
|
688
|
-
|
|
746
|
+
if (isParallelGroup(child)) throw compilerError("E116", "job step: nested parallel groups are not supported", {
|
|
747
|
+
location: stepEntryLocation(child, jobLocation),
|
|
748
|
+
suggestion: "Flatten the nested group — a parallel group may only contain steps."
|
|
749
|
+
});
|
|
750
|
+
const lockChild = transformSequentialStep(child, gitRoot, counter, jobLocation);
|
|
751
|
+
if (seen.has(lockChild.name)) throw compilerError("E117", `job step: duplicate step name '${lockChild.name}' in parallel group`, {
|
|
752
|
+
location: stepEntryLocation(child, jobLocation),
|
|
753
|
+
suggestion: "Give each step in a parallel group a unique name."
|
|
754
|
+
});
|
|
689
755
|
seen.add(lockChild.name);
|
|
690
756
|
return lockChild;
|
|
691
757
|
});
|
|
@@ -699,7 +765,7 @@ function transformParallelGroup(group, gitRoot, counter, groupOrdinal) {
|
|
|
699
765
|
};
|
|
700
766
|
}
|
|
701
767
|
/** Transform a single sequential step (or bare function) into a `LockStep`. */
|
|
702
|
-
function transformSequentialStep(stepOrFn, gitRoot, counter) {
|
|
768
|
+
function transformSequentialStep(stepOrFn, gitRoot, counter, jobLocation) {
|
|
703
769
|
if (typeof stepOrFn === "function") {
|
|
704
770
|
counter.n++;
|
|
705
771
|
return {
|
|
@@ -733,7 +799,7 @@ function transformSequentialStep(stepOrFn, gitRoot, counter) {
|
|
|
733
799
|
...step.cleanup !== void 0 && { hasCleanup: true },
|
|
734
800
|
...step.check !== void 0 && { hasCheck: true },
|
|
735
801
|
...step.whenInSync !== void 0 && { hasWhenInSync: true },
|
|
736
|
-
...step.approval !== void 0 && { approval: (assertStepApprovalCheckFacet(step), toLockApproval(step.approval)) }
|
|
802
|
+
...step.approval !== void 0 && { approval: (assertStepApprovalCheckFacet(step, jobLocation), toLockApproval(step.approval)) }
|
|
737
803
|
};
|
|
738
804
|
}
|
|
739
805
|
/**
|
|
@@ -812,6 +878,6 @@ function serializeLockFile(lockFile, pretty = true) {
|
|
|
812
878
|
return JSON.stringify(lockFile, null, pretty ? 2 : void 0);
|
|
813
879
|
}
|
|
814
880
|
//#endregion
|
|
815
|
-
export { computeLockfileHash, detectGitRoot, generateLockFile, serializeLockFile, transformSteps, transformTriggers };
|
|
881
|
+
export { computeLockfileHash, detectGitRoot, generateLockFile, schemaWindowWarning, serializeLockFile, transformSteps, transformTriggers };
|
|
816
882
|
|
|
817
883
|
//# sourceMappingURL=generator.js.map
|
package/dist/lockfile/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export { generateLockFile, serializeLockFile, detectGitRoot, computeLockfileHash, } from './generator.js';
|
|
1
|
+
export { generateLockFile, serializeLockFile, detectGitRoot, computeLockfileHash, schemaWindowWarning, } from './generator.js';
|
|
2
2
|
export { computeContentHash, COMPILE_SCHEMA_VERSION } from './hasher.js';
|
|
3
|
+
export { DynamicValueField, analyzeJobPurity, collectWorkflowPurityWarnings, } from './purity-diagnostics.js';
|
|
4
|
+
export type { JobPurityWarning } from './purity-diagnostics.js';
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/lockfile/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
2
|
import { COMPILE_SCHEMA_VERSION, computeContentHash } from "./hasher.js";
|
|
3
|
-
import { computeLockfileHash, detectGitRoot, generateLockFile, serializeLockFile } from "./generator.js";
|
|
4
|
-
|
|
3
|
+
import { computeLockfileHash, detectGitRoot, generateLockFile, schemaWindowWarning, serializeLockFile } from "./generator.js";
|
|
4
|
+
import { DynamicValueField, analyzeJobPurity, collectWorkflowPurityWarnings } from "./purity-diagnostics.js";
|
|
5
|
+
export { COMPILE_SCHEMA_VERSION, DynamicValueField, analyzeJobPurity, collectWorkflowPurityWarnings, computeContentHash, computeLockfileHash, detectGitRoot, generateLockFile, schemaWindowWarning, serializeLockFile };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Job } from '@kici-dev/sdk';
|
|
2
|
+
import type { WorkflowWithSource } from '../types.js';
|
|
3
|
+
/** Which dynamic-value slot on a job carried the impure function. */
|
|
4
|
+
export declare enum DynamicValueField {
|
|
5
|
+
Context = "context",
|
|
6
|
+
Env = "env",
|
|
7
|
+
ConcurrencyGroup = "concurrencyGroup"
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* One impure dynamic-value function found on a static job. Each impurity forces
|
|
11
|
+
* the orchestrator to dispatch an agent-side `__init__` job (~5-10s) instead of
|
|
12
|
+
* inlining the value, so we surface it to the author at compile / preview time.
|
|
13
|
+
*/
|
|
14
|
+
export interface JobPurityWarning {
|
|
15
|
+
workflowName: string;
|
|
16
|
+
sourceFile?: string;
|
|
17
|
+
jobName: string;
|
|
18
|
+
field: DynamicValueField;
|
|
19
|
+
reason: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Analyze a single static job's dynamic-value functions (context(s), env,
|
|
23
|
+
* concurrencyGroup) for impurity. Returns one warning per impure function.
|
|
24
|
+
*/
|
|
25
|
+
export declare function analyzeJobPurity(job: Job, workflowName: string, sourceFile?: string): JobPurityWarning[];
|
|
26
|
+
/**
|
|
27
|
+
* Walk every workflow's static jobs and collect impurity warnings. Function-typed
|
|
28
|
+
* jobs (dynamic job generators) are skipped — their purity is analyzed at dispatch.
|
|
29
|
+
*/
|
|
30
|
+
export declare function collectWorkflowPurityWarnings(workflows: WorkflowWithSource[]): JobPurityWarning[];
|
|
31
|
+
//# sourceMappingURL=purity-diagnostics.d.ts.map
|