@kici-dev/compiler 0.0.0 → 0.1.2
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/LICENSE +202 -0
- package/README.md +1 -6
- package/dist/assets/api-TJJVHrjC.json +118 -0
- package/dist/assets/descriptor-BTtjzN9L.json +1382 -0
- package/dist/assets/package-BpQF9kR8.json +74 -0
- package/dist/assets/package-Ceo2h27X.json +89 -0
- package/dist/assets/source_context-D0atuL28.json +20 -0
- package/dist/assets/type-BFqO8SCZ.json +202 -0
- package/dist/auth/headless-detect.d.ts +14 -0
- package/dist/auth/headless-detect.js +25 -0
- package/dist/chunk-gOLHoazu.js +4 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +193 -0
- package/dist/commands/cancel.d.ts +22 -0
- package/dist/commands/cancel.js +124 -0
- package/dist/commands/compile.d.ts +17 -0
- package/dist/commands/compile.js +99 -0
- package/dist/commands/docs.d.ts +26 -0
- package/dist/commands/docs.js +60 -0
- package/dist/commands/drain-worker.d.ts +19 -0
- package/dist/commands/drain-worker.js +45 -0
- package/dist/commands/endpoints.d.ts +53 -0
- package/dist/commands/endpoints.js +185 -0
- package/dist/commands/fixture.d.ts +14 -0
- package/dist/commands/fixture.js +104 -0
- package/dist/commands/hook.d.ts +20 -0
- package/dist/commands/hook.js +97 -0
- package/dist/commands/index.d.ts +33 -0
- package/dist/commands/index.js +20 -0
- package/dist/commands/init.d.ts +35 -0
- package/dist/commands/init.js +393 -0
- package/dist/commands/login.d.ts +23 -0
- package/dist/commands/login.js +144 -0
- package/dist/commands/logout.d.ts +18 -0
- package/dist/commands/logout.js +55 -0
- package/dist/commands/org.d.ts +27 -0
- package/dist/commands/org.js +126 -0
- package/dist/commands/run.d.ts +21 -0
- package/dist/commands/run.js +562 -0
- package/dist/commands/secrets-list.d.ts +16 -0
- package/dist/commands/secrets-list.js +85 -0
- package/dist/commands/status.d.ts +30 -0
- package/dist/commands/status.js +210 -0
- package/dist/commands/test.d.ts +61 -0
- package/dist/commands/test.js +220 -0
- package/dist/commands/types.d.ts +18 -0
- package/dist/commands/types.js +74 -0
- package/dist/commands/watch.d.ts +14 -0
- package/dist/commands/watch.js +97 -0
- package/dist/commands/workflows.d.ts +28 -0
- package/dist/commands/workflows.js +154 -0
- package/dist/comment-created.json +30 -0
- package/dist/create-branch.json +17 -0
- package/dist/delete-branch.json +15 -0
- package/dist/dispatch.json +15 -0
- package/dist/errors/capability-gap.d.ts +50 -0
- package/dist/errors/capability-gap.js +54 -0
- package/dist/errors/codes.d.ts +25 -0
- package/dist/errors/formatter.d.ts +32 -0
- package/dist/errors/formatter.js +35 -0
- package/dist/errors/index.d.ts +5 -0
- package/dist/errors/index.js +4 -0
- package/dist/execution/executor.d.ts +61 -0
- package/dist/execution/executor.js +230 -0
- package/dist/execution/index.d.ts +4 -0
- package/dist/execution/index.js +3 -0
- package/dist/execution/sdk-alias.d.ts +33 -0
- package/dist/execution/sdk-alias.js +102 -0
- package/dist/fixtures/compiler.d.ts +47 -0
- package/dist/fixtures/compiler.js +177 -0
- package/dist/fixtures/defaults/comment-created.json +30 -0
- package/dist/fixtures/defaults/create-branch.json +17 -0
- package/dist/fixtures/defaults/delete-branch.json +15 -0
- package/dist/fixtures/defaults/dispatch.json +15 -0
- package/dist/fixtures/defaults/fork.json +19 -0
- package/dist/fixtures/defaults/index.d.ts +16 -0
- package/dist/fixtures/defaults/index.js +105 -0
- package/dist/fixtures/defaults/index.ts +145 -0
- package/dist/fixtures/defaults/pr-closed.json +28 -0
- package/dist/fixtures/defaults/pr-opened.json +27 -0
- package/dist/fixtures/defaults/pr-reopened.json +27 -0
- package/dist/fixtures/defaults/pr-synchronize.json +27 -0
- package/dist/fixtures/defaults/push.json +16 -0
- package/dist/fixtures/defaults/release-published.json +23 -0
- package/dist/fixtures/defaults/review-comment-created.json +36 -0
- package/dist/fixtures/defaults/review-submitted.json +35 -0
- package/dist/fixtures/defaults/star-created.json +15 -0
- package/dist/fixtures/defaults/status.json +26 -0
- package/dist/fixtures/defaults/tag-push.json +20 -0
- package/dist/fixtures/defaults/watch-started.json +15 -0
- package/dist/fixtures/defaults/workflow-run-completed.json +23 -0
- package/dist/fork.json +19 -0
- package/dist/format.d.ts +5 -0
- package/dist/format.js +20 -0
- package/dist/generators/secrets-dts.d.ts +29 -0
- package/dist/generators/secrets-dts.js +67 -0
- package/dist/hooks/detector.d.ts +39 -0
- package/dist/hooks/detector.js +133 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.js +5 -0
- package/dist/hooks/installer.d.ts +24 -0
- package/dist/hooks/installer.js +328 -0
- package/dist/hooks/templates.d.ts +26 -0
- package/dist/hooks/templates.js +63 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +12 -0
- package/dist/llm-context/llms-full.txt +9974 -0
- package/dist/llm-context/llms.txt +61 -0
- package/dist/local-executor/dag-scheduler.d.ts +44 -0
- package/dist/local-executor/dag-scheduler.js +183 -0
- package/dist/local-executor/index.d.ts +23 -0
- package/dist/local-executor/index.js +309 -0
- package/dist/local-executor/job-runner.d.ts +40 -0
- package/dist/local-executor/job-runner.js +307 -0
- package/dist/local-executor/output-streamer.d.ts +31 -0
- package/dist/local-executor/output-streamer.js +166 -0
- package/dist/local-executor/payload-generator.d.ts +16 -0
- package/dist/local-executor/payload-generator.js +138 -0
- package/dist/local-executor/picker.d.ts +33 -0
- package/dist/local-executor/picker.js +109 -0
- package/dist/local-executor/secret-loader.d.ts +18 -0
- package/dist/local-executor/secret-loader.js +105 -0
- package/dist/local-executor/types.d.ts +80 -0
- package/dist/local-executor/types.js +2 -0
- package/dist/local-executor/workflow-lock.d.ts +81 -0
- package/dist/local-executor/workflow-lock.js +0 -0
- package/dist/lockfile/generator.d.ts +39 -0
- package/dist/lockfile/generator.js +688 -0
- package/dist/lockfile/hash-files.d.ts +14 -0
- package/dist/lockfile/hash-files.js +50 -0
- package/dist/lockfile/hasher.d.ts +36 -0
- package/dist/lockfile/hasher.js +46 -0
- package/dist/lockfile/index.d.ts +3 -0
- package/dist/lockfile/index.js +4 -0
- package/dist/lockfile/purity-analyzer.d.ts +25 -0
- package/dist/lockfile/purity-analyzer.js +204 -0
- package/dist/package-F7UXSDHW.json +74 -0
- package/dist/postinstall.d.ts +9 -0
- package/dist/postinstall.js +60 -0
- package/dist/pr-closed.json +28 -0
- package/dist/pr-opened.json +27 -0
- package/dist/pr-reopened.json +27 -0
- package/dist/pr-synchronize.json +27 -0
- package/dist/push.json +16 -0
- package/dist/release-published.json +23 -0
- package/dist/remote/client.d.ts +204 -0
- package/dist/remote/client.js +203 -0
- package/dist/remote/config.d.ts +54 -0
- package/dist/remote/config.js +92 -0
- package/dist/remote/encryption.d.ts +35 -0
- package/dist/remote/encryption.js +87 -0
- package/dist/remote/history.d.ts +91 -0
- package/dist/remote/history.js +146 -0
- package/dist/remote/oauth.d.ts +65 -0
- package/dist/remote/oauth.js +302 -0
- package/dist/remote/observer.d.ts +81 -0
- package/dist/remote/observer.js +174 -0
- package/dist/remote/output/json.d.ts +13 -0
- package/dist/remote/output/json.js +36 -0
- package/dist/remote/output/junit.d.ts +18 -0
- package/dist/remote/output/junit.js +50 -0
- package/dist/remote/output/streaming.d.ts +57 -0
- package/dist/remote/output/streaming.js +124 -0
- package/dist/remote/output/summary.d.ts +39 -0
- package/dist/remote/output/summary.js +99 -0
- package/dist/remote/uploader.d.ts +87 -0
- package/dist/remote/uploader.js +197 -0
- package/dist/review-comment-created.json +36 -0
- package/dist/review-submitted.json +35 -0
- package/dist/star-created.json +15 -0
- package/dist/status.json +26 -0
- package/dist/tag-push.json +20 -0
- package/dist/templates/agents-md.d.ts +8 -0
- package/dist/templates/agents-md.js +130 -0
- package/dist/templates/index.d.ts +43 -0
- package/dist/templates/index.js +48 -0
- package/dist/templates/package-json.d.ts +18 -0
- package/dist/templates/package-json.js +34 -0
- package/dist/templates/tsconfig-json.d.ts +9 -0
- package/dist/templates/tsconfig-json.js +26 -0
- package/dist/templates/workflows/hello-world.d.ts +2 -0
- package/dist/templates/workflows/hello-world.js +16 -0
- package/dist/templates/workflows/hello-world.ts +21 -0
- package/dist/templates/workflows/pr-checks.d.ts +2 -0
- package/dist/templates/workflows/pr-checks.js +40 -0
- package/dist/templates/workflows/pr-checks.ts +57 -0
- package/dist/test-runner/dry-run.d.ts +12 -0
- package/dist/test-runner/dry-run.js +66 -0
- package/dist/test-runner/event-types.d.ts +86 -0
- package/dist/test-runner/event-types.js +330 -0
- package/dist/test-runner/git-detector.d.ts +15 -0
- package/dist/test-runner/git-detector.js +30 -0
- package/dist/test-runner/index.d.ts +13 -0
- package/dist/test-runner/index.js +11 -0
- package/dist/test-runner/job-executor.d.ts +48 -0
- package/dist/test-runner/job-executor.js +245 -0
- package/dist/test-runner/output-formatter.d.ts +47 -0
- package/dist/test-runner/output-formatter.js +92 -0
- package/dist/test-runner/payload-builder.d.ts +20 -0
- package/dist/test-runner/payload-builder.js +216 -0
- package/dist/test-runner/rule-evaluator.d.ts +14 -0
- package/dist/test-runner/rule-evaluator.js +31 -0
- package/dist/test-runner/secrets-file.d.ts +24 -0
- package/dist/test-runner/secrets-file.js +62 -0
- package/dist/test-runner/step-context.d.ts +15 -0
- package/dist/test-runner/step-context.js +140 -0
- package/dist/test-runner/summary.d.ts +7 -0
- package/dist/types.d.ts +525 -0
- package/dist/types.js +33 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.js +3 -0
- package/dist/validation/validator.d.ts +26 -0
- package/dist/validation/validator.js +164 -0
- package/dist/watch-started.json +15 -0
- package/dist/workflow-run-completed.json +23 -0
- package/dist/workflows/hello-world.ts +21 -0
- package/dist/workflows/pr-checks.ts +57 -0
- package/hack/postinstall.mjs +105 -0
- package/package.json +60 -6
- package/sbom.spdx.json +10997 -0
- package/index.js +0 -3
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import "../chunk-gOLHoazu.js";
|
|
2
|
+
import { transformTriggers } from "../lockfile/generator.js";
|
|
3
|
+
import { parseEventArg, triggerSummary, triggerToEventArg } from "../test-runner/event-types.js";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
import { logger } from "@kici-dev/shared";
|
|
6
|
+
import { select } from "@inquirer/prompts";
|
|
7
|
+
//#region src/local-executor/picker.ts
|
|
8
|
+
/**
|
|
9
|
+
* Interactive workflow picker for `kici run local --pick`.
|
|
10
|
+
*
|
|
11
|
+
* Lists every workflow with a summary of its triggers, lets the user pick one
|
|
12
|
+
* (and a specific trigger when there are multiple), and returns the derived
|
|
13
|
+
* event arg plus workflow name. The caller feeds these back into the standard
|
|
14
|
+
* executeLocal pipeline so the run remains consistent with normal trigger
|
|
15
|
+
* matching.
|
|
16
|
+
*/
|
|
17
|
+
var PickerCancelledError = class extends Error {
|
|
18
|
+
constructor(message) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = "PickerCancelledError";
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
function workflowEntries(workflows) {
|
|
24
|
+
return workflows.map((w) => ({
|
|
25
|
+
name: w.name,
|
|
26
|
+
triggers: transformTriggers(w.on)
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
function eventFamily(arg) {
|
|
30
|
+
return arg.toLowerCase().split(":")[0] ?? "";
|
|
31
|
+
}
|
|
32
|
+
function filterFamily(arg) {
|
|
33
|
+
try {
|
|
34
|
+
const parsed = parseEventArg(arg);
|
|
35
|
+
if (parsed.type === "pull_request") return "pr";
|
|
36
|
+
return parsed.type;
|
|
37
|
+
} catch {
|
|
38
|
+
return eventFamily(arg);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function triggerFamilies(trigger) {
|
|
42
|
+
const head = eventFamily(triggerToEventArg(trigger));
|
|
43
|
+
if (trigger._type === "generic_webhook") return ["webhook", "generic_webhook"];
|
|
44
|
+
if (trigger._type === "workflow_complete") return [head, "lifecycle"];
|
|
45
|
+
if (trigger._type === "job_complete") return [head, "lifecycle"];
|
|
46
|
+
return [head];
|
|
47
|
+
}
|
|
48
|
+
function isStdinTty() {
|
|
49
|
+
return Boolean(process.stdin.isTTY);
|
|
50
|
+
}
|
|
51
|
+
function printWorkflowList(entries) {
|
|
52
|
+
logger.info(pc.bold("Available workflows:"));
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
const summaries = entry.triggers.map(triggerSummary).join(", ") || "(no triggers)";
|
|
55
|
+
logger.info(` ${pc.cyan(entry.name)} — ${summaries}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Run the interactive picker.
|
|
60
|
+
*
|
|
61
|
+
* @throws PickerCancelledError when stdin is not a TTY, when no eligible
|
|
62
|
+
* workflows exist, or when the user aborts one of the prompts.
|
|
63
|
+
*/
|
|
64
|
+
async function runPicker(workflows, opts = {}) {
|
|
65
|
+
let entries = workflowEntries(workflows).filter((e) => e.triggers.length > 0);
|
|
66
|
+
if (opts.filterEvent) {
|
|
67
|
+
const family = filterFamily(opts.filterEvent);
|
|
68
|
+
entries = entries.filter((e) => e.triggers.some((t) => triggerFamilies(t).includes(family)));
|
|
69
|
+
}
|
|
70
|
+
if (entries.length === 0) throw new PickerCancelledError(opts.filterEvent ? `No workflows with triggers matching "${opts.filterEvent}". Remove the event arg or pass a different one.` : "No workflows with triggers available to pick.");
|
|
71
|
+
if (!isStdinTty()) {
|
|
72
|
+
printWorkflowList(entries);
|
|
73
|
+
throw new PickerCancelledError("Non-interactive environment: --pick requires a TTY. Pass --workflow <name> plus an event arg instead.");
|
|
74
|
+
}
|
|
75
|
+
let chosenWorkflow;
|
|
76
|
+
try {
|
|
77
|
+
const name = await select({
|
|
78
|
+
message: "Select a workflow to run",
|
|
79
|
+
choices: entries.map((e) => ({
|
|
80
|
+
name: `${e.name} — ${e.triggers.map(triggerSummary).join(", ")}`,
|
|
81
|
+
value: e.name
|
|
82
|
+
}))
|
|
83
|
+
});
|
|
84
|
+
chosenWorkflow = entries.find((e) => e.name === name);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
throw new PickerCancelledError(`Picker cancelled: ${err instanceof Error ? err.message : String(err)}`);
|
|
87
|
+
}
|
|
88
|
+
let trigger;
|
|
89
|
+
if (chosenWorkflow.triggers.length === 1) trigger = chosenWorkflow.triggers[0];
|
|
90
|
+
else try {
|
|
91
|
+
trigger = await select({
|
|
92
|
+
message: `Select a trigger for "${chosenWorkflow.name}"`,
|
|
93
|
+
choices: chosenWorkflow.triggers.map((t) => ({
|
|
94
|
+
name: triggerSummary(t),
|
|
95
|
+
value: t
|
|
96
|
+
}))
|
|
97
|
+
});
|
|
98
|
+
} catch (err) {
|
|
99
|
+
throw new PickerCancelledError(`Picker cancelled: ${err instanceof Error ? err.message : String(err)}`);
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
event: triggerToEventArg(trigger),
|
|
103
|
+
workflow: chosenWorkflow.name
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
export { PickerCancelledError, runPicker };
|
|
108
|
+
|
|
109
|
+
//# sourceMappingURL=picker.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ParsedSecrets } from '../test-runner/secrets-file.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load secrets from multiple sources with merge precedence.
|
|
4
|
+
*
|
|
5
|
+
* Merge order (lowest to highest priority):
|
|
6
|
+
* 1. .kici/.secrets (INI-style, backward compat)
|
|
7
|
+
* 2. .kici/.env.local (dotenv format)
|
|
8
|
+
* 3. .kici/secrets.yaml (YAML with environment scopes, merged flat)
|
|
9
|
+
* 4. --env KEY=VALUE CLI flags
|
|
10
|
+
*
|
|
11
|
+
* Note: process.env is NOT merged here -- it's handled at step-context level.
|
|
12
|
+
*
|
|
13
|
+
* @param kiciDir - Path to the .kici directory
|
|
14
|
+
* @param envFlags - Optional --env KEY=VALUE flag values
|
|
15
|
+
* @returns Merged secrets with correct precedence
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadLocalSecrets(kiciDir: string, envFlags?: string[]): Promise<ParsedSecrets>;
|
|
18
|
+
//# sourceMappingURL=secret-loader.d.ts.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import "../chunk-gOLHoazu.js";
|
|
2
|
+
import { loadSecretsFile } from "../test-runner/secrets-file.js";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { parse } from "yaml";
|
|
6
|
+
//#region src/local-executor/secret-loader.ts
|
|
7
|
+
/**
|
|
8
|
+
* Parse a dotenv-style file (.env.local) into flat key-value pairs.
|
|
9
|
+
* Lines starting with # are comments. Blank lines are ignored.
|
|
10
|
+
*/
|
|
11
|
+
function parseDotenv(content) {
|
|
12
|
+
const result = {};
|
|
13
|
+
for (const rawLine of content.split("\n")) {
|
|
14
|
+
const line = rawLine.trim();
|
|
15
|
+
if (line === "" || line.startsWith("#")) continue;
|
|
16
|
+
const eqIndex = line.indexOf("=");
|
|
17
|
+
if (eqIndex === -1) continue;
|
|
18
|
+
const key = line.slice(0, eqIndex).trim();
|
|
19
|
+
let value = line.slice(eqIndex + 1).trim();
|
|
20
|
+
if (value.length >= 2 && (value[0] === "\"" && value[value.length - 1] === "\"" || value[0] === "'" && value[value.length - 1] === "'")) value = value.slice(1, -1);
|
|
21
|
+
result[key] = value;
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse a secrets.yaml file.
|
|
27
|
+
* Expected format: top-level keys are environment names, values are key-value maps.
|
|
28
|
+
* For local execution, all environments are merged flat (no environment resolution).
|
|
29
|
+
*/
|
|
30
|
+
function parseSecretsYaml(content) {
|
|
31
|
+
const parsed = parse(content);
|
|
32
|
+
if (!parsed || typeof parsed !== "object") return {};
|
|
33
|
+
const result = {};
|
|
34
|
+
for (const [, envSecrets] of Object.entries(parsed)) if (envSecrets && typeof envSecrets === "object" && !Array.isArray(envSecrets)) {
|
|
35
|
+
for (const [key, value] of Object.entries(envSecrets)) if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") result[key] = String(value);
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Parse --env KEY=VALUE flags into a flat map.
|
|
41
|
+
*/
|
|
42
|
+
function parseEnvFlags(flags) {
|
|
43
|
+
const result = {};
|
|
44
|
+
for (const flag of flags) {
|
|
45
|
+
const eqIndex = flag.indexOf("=");
|
|
46
|
+
if (eqIndex === -1) continue;
|
|
47
|
+
const key = flag.slice(0, eqIndex).trim();
|
|
48
|
+
result[key] = flag.slice(eqIndex + 1);
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Read a file, returning null if it doesn't exist.
|
|
54
|
+
*/
|
|
55
|
+
async function readFileOrNull(filePath) {
|
|
56
|
+
try {
|
|
57
|
+
return await readFile(filePath, "utf-8");
|
|
58
|
+
} catch (err) {
|
|
59
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") return null;
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Load secrets from multiple sources with merge precedence.
|
|
65
|
+
*
|
|
66
|
+
* Merge order (lowest to highest priority):
|
|
67
|
+
* 1. .kici/.secrets (INI-style, backward compat)
|
|
68
|
+
* 2. .kici/.env.local (dotenv format)
|
|
69
|
+
* 3. .kici/secrets.yaml (YAML with environment scopes, merged flat)
|
|
70
|
+
* 4. --env KEY=VALUE CLI flags
|
|
71
|
+
*
|
|
72
|
+
* Note: process.env is NOT merged here -- it's handled at step-context level.
|
|
73
|
+
*
|
|
74
|
+
* @param kiciDir - Path to the .kici directory
|
|
75
|
+
* @param envFlags - Optional --env KEY=VALUE flag values
|
|
76
|
+
* @returns Merged secrets with correct precedence
|
|
77
|
+
*/
|
|
78
|
+
async function loadLocalSecrets(kiciDir, envFlags) {
|
|
79
|
+
const iniSecrets = await loadSecretsFile(kiciDir);
|
|
80
|
+
const flat = { ...iniSecrets.flat };
|
|
81
|
+
const contexts = {};
|
|
82
|
+
for (const [ctx, vals] of Object.entries(iniSecrets.contexts)) contexts[ctx] = { ...vals };
|
|
83
|
+
const envLocalContent = await readFileOrNull(path.join(kiciDir, ".env.local"));
|
|
84
|
+
if (envLocalContent !== null) {
|
|
85
|
+
const envLocalSecrets = parseDotenv(envLocalContent);
|
|
86
|
+
Object.assign(flat, envLocalSecrets);
|
|
87
|
+
}
|
|
88
|
+
const yamlContent = await readFileOrNull(path.join(kiciDir, "secrets.yaml"));
|
|
89
|
+
if (yamlContent !== null) {
|
|
90
|
+
const yamlSecrets = parseSecretsYaml(yamlContent);
|
|
91
|
+
Object.assign(flat, yamlSecrets);
|
|
92
|
+
}
|
|
93
|
+
if (envFlags && envFlags.length > 0) {
|
|
94
|
+
const flagSecrets = parseEnvFlags(envFlags);
|
|
95
|
+
Object.assign(flat, flagSecrets);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
flat,
|
|
99
|
+
contexts
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
export { loadLocalSecrets };
|
|
104
|
+
|
|
105
|
+
//# sourceMappingURL=secret-loader.js.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { MatrixValues, Job } from '@kici-dev/sdk';
|
|
2
|
+
import type { JobResult } from '../test-runner/job-executor.js';
|
|
3
|
+
/**
|
|
4
|
+
* All CLI flags for `kici run local`.
|
|
5
|
+
*/
|
|
6
|
+
export interface RunLocalOptions {
|
|
7
|
+
/** Positional arg: event type (e.g. 'push', 'pr:open'). Optional when `pick` is true. */
|
|
8
|
+
event?: string;
|
|
9
|
+
/** --pick / -p: interactive workflow picker (derives event arg from the selected trigger) */
|
|
10
|
+
pick?: boolean;
|
|
11
|
+
/** --workflow filter: run only matching workflow */
|
|
12
|
+
workflow?: string;
|
|
13
|
+
/** --job filter: run only matching job (includes transitive deps) */
|
|
14
|
+
job?: string;
|
|
15
|
+
/** --branch override: override detected git branch */
|
|
16
|
+
branch?: string;
|
|
17
|
+
/** --sha override: override detected git SHA */
|
|
18
|
+
sha?: string;
|
|
19
|
+
/** --payload path: explicit event payload JSON file */
|
|
20
|
+
payload?: string;
|
|
21
|
+
/** --concurrency: max parallel jobs (default: os.availableParallelism()) */
|
|
22
|
+
concurrency?: number;
|
|
23
|
+
/** --keep-going: continue after job failure (default: false) */
|
|
24
|
+
keepGoing?: boolean;
|
|
25
|
+
/** --container: use Podman isolation (default: false) */
|
|
26
|
+
container?: boolean;
|
|
27
|
+
/** --env KEY=VALUE overrides (repeatable) */
|
|
28
|
+
env?: string[];
|
|
29
|
+
/** --quiet: minimal output */
|
|
30
|
+
quiet?: boolean;
|
|
31
|
+
/** --json: JSON output format */
|
|
32
|
+
json?: boolean;
|
|
33
|
+
/** --junit: path for JUnit XML report */
|
|
34
|
+
junit?: string;
|
|
35
|
+
/** --files: override changed file paths (repeatable) */
|
|
36
|
+
files?: string[];
|
|
37
|
+
/** --debug: verbose debug output */
|
|
38
|
+
debug?: boolean;
|
|
39
|
+
/** --kici-dir: path to .kici directory */
|
|
40
|
+
kiciDir?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A job after matrix expansion with resolved values.
|
|
44
|
+
*/
|
|
45
|
+
export interface ResolvedJob {
|
|
46
|
+
/** Original job definition */
|
|
47
|
+
job: Job;
|
|
48
|
+
/** Expanded name (e.g. 'test (node-18, linux)') */
|
|
49
|
+
expandedName: string;
|
|
50
|
+
/** Matrix values for this expansion (empty object if no matrix) */
|
|
51
|
+
matrixValues: MatrixValues;
|
|
52
|
+
/** Resolved dependency names (expanded names of upstream jobs) */
|
|
53
|
+
resolvedNeeds: string[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Result for a single job execution in local mode.
|
|
57
|
+
* Extends JobResult with matrix context and cancellation.
|
|
58
|
+
*/
|
|
59
|
+
export interface LocalJobResult extends Omit<JobResult, 'status'> {
|
|
60
|
+
/** Job completion status (adds 'cancelled' to base JobResult statuses) */
|
|
61
|
+
status: 'success' | 'failure' | 'skipped' | 'cancelled';
|
|
62
|
+
/** Matrix values if this job was part of a matrix expansion */
|
|
63
|
+
matrixValues?: MatrixValues;
|
|
64
|
+
/** Whether this job was cancelled (e.g. by AbortSignal) */
|
|
65
|
+
cancelled?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Result of executing a workflow locally.
|
|
69
|
+
*/
|
|
70
|
+
export interface WorkflowExecutionResult {
|
|
71
|
+
/** Workflow name */
|
|
72
|
+
name: string;
|
|
73
|
+
/** Overall status */
|
|
74
|
+
status: 'success' | 'failure' | 'skipped';
|
|
75
|
+
/** Individual job results */
|
|
76
|
+
jobs: LocalJobResult[];
|
|
77
|
+
/** Total execution duration in milliseconds */
|
|
78
|
+
durationMs: number;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow-level concurrency lock for `kici run local`.
|
|
3
|
+
*
|
|
4
|
+
* Enforces the SDK-declared `workflow.concurrency` block across concurrent
|
|
5
|
+
* `kici run local` invocations on the same machine and user. Mirrors the
|
|
6
|
+
* orchestrator semantics:
|
|
7
|
+
*
|
|
8
|
+
* - `group` callback evaluated against the simulated event, fails closed
|
|
9
|
+
* on throw via {@link ConcurrencyKeyEvaluationError} (the caller aborts the
|
|
10
|
+
* run rather than fall back to the workflow name).
|
|
11
|
+
* - `cancelInProgress: true` interrupts the holder via SIGTERM, escalates
|
|
12
|
+
* to SIGKILL after `KICI_LOCAL_LOCK_KILL_GRACE_MS` (default 30000ms).
|
|
13
|
+
* - Otherwise contention waits in FIFO order on the underlying file lock.
|
|
14
|
+
* - Stale locks (holder PID gone per `process.kill(pid, 0)`) are reclaimed.
|
|
15
|
+
*
|
|
16
|
+
* The lock primitive is `proper-lockfile` (atomic `mkdir` of a `.lock`
|
|
17
|
+
* directory next to the metadata sidecar). The lock identity is
|
|
18
|
+
* `sha256(workflowName + '\0' + groupKey)`, scoped to a per-user lock dir
|
|
19
|
+
* (`$XDG_RUNTIME_DIR/kici-local-locks/` on Linux, else
|
|
20
|
+
* `os.tmpdir()/kici-local-locks-<uid>/`).
|
|
21
|
+
*/
|
|
22
|
+
import type { Workflow } from '@kici-dev/sdk';
|
|
23
|
+
/** Sidecar metadata persisted next to the lock dir for diagnostics + reclamation. */
|
|
24
|
+
export interface LockHolderMetadata {
|
|
25
|
+
pid: number;
|
|
26
|
+
startedAt: string;
|
|
27
|
+
workflowName: string;
|
|
28
|
+
groupKey: string;
|
|
29
|
+
hostname: string;
|
|
30
|
+
}
|
|
31
|
+
/** Handle returned by {@link acquireWorkflowLock}. Caller MUST invoke `release()` in a `finally`. */
|
|
32
|
+
export interface WorkflowLockHandle {
|
|
33
|
+
release(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export interface AcquireWorkflowLockOptions {
|
|
36
|
+
workflowName: string;
|
|
37
|
+
workflow: Workflow;
|
|
38
|
+
/** The simulated-event payload object passed as `groupCtx.event` to the user's group fn. */
|
|
39
|
+
event: Record<string, unknown>;
|
|
40
|
+
/** Branch derived from the simulated event for `groupCtx.branch`. */
|
|
41
|
+
branch: string;
|
|
42
|
+
debug?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Thrown when the workflow's `concurrency.group()` function throws or rejects.
|
|
46
|
+
* The caller surfaces this as a workflow failure (it does NOT fall back to the
|
|
47
|
+
* workflow name as a key — fail-closed is the documented contract).
|
|
48
|
+
*/
|
|
49
|
+
export declare class ConcurrencyKeyEvaluationError extends Error {
|
|
50
|
+
readonly cause?: Error;
|
|
51
|
+
readonly workflowName: string;
|
|
52
|
+
constructor(workflowName: string, cause: unknown);
|
|
53
|
+
}
|
|
54
|
+
/** Module-level stub for `process.kill`, swappable by tests via {@link __setKillFnForTesting}. */
|
|
55
|
+
type KillFn = (pid: number, signal?: string | number) => boolean;
|
|
56
|
+
/** Test-only: swap the kill function so unit tests don't actually signal real PIDs. */
|
|
57
|
+
export declare function __setKillFnForTesting(fn?: KillFn): void;
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the per-user lock directory. Prefers `$XDG_RUNTIME_DIR/kici-local-locks/`
|
|
60
|
+
* (Linux per-user runtime dir, mode 0700), else `os.tmpdir()/kici-local-locks-<uid>/`.
|
|
61
|
+
*
|
|
62
|
+
* Created with `mode: 0o700`. Falls through silently to the tmpdir form on EACCES/EROFS.
|
|
63
|
+
*/
|
|
64
|
+
export declare function resolveLockDir(): Promise<string>;
|
|
65
|
+
/**
|
|
66
|
+
* Evaluate the workflow's concurrency `group` function against the simulated event.
|
|
67
|
+
*
|
|
68
|
+
* Returns `null` when the workflow has no `concurrency` block. Throws
|
|
69
|
+
* {@link ConcurrencyKeyEvaluationError} when the group function throws or rejects.
|
|
70
|
+
*/
|
|
71
|
+
export declare function resolveConcurrencyKey(workflow: Workflow, event: Record<string, unknown>, branch: string): Promise<string | null>;
|
|
72
|
+
/**
|
|
73
|
+
* Acquire the workflow-level concurrency lock for a `kici run local` invocation.
|
|
74
|
+
*
|
|
75
|
+
* Returns `null` immediately when the workflow has no `concurrency` block (no
|
|
76
|
+
* locking is performed). Otherwise blocks until the lock is held, then returns
|
|
77
|
+
* a handle whose `release()` MUST be invoked in a `finally`.
|
|
78
|
+
*/
|
|
79
|
+
export declare function acquireWorkflowLock(opts: AcquireWorkflowLockOptions): Promise<WorkflowLockHandle | null>;
|
|
80
|
+
export {};
|
|
81
|
+
//# sourceMappingURL=workflow-lock.d.ts.map
|
|
Binary file
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { TriggerConfig } from '@kici-dev/sdk';
|
|
2
|
+
import { type LockFile, type LockTrigger, type WorkflowWithSource } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Detect git repository root by running `git rev-parse --show-toplevel`.
|
|
5
|
+
* Falls back to cwd if not in a git repo.
|
|
6
|
+
*
|
|
7
|
+
* @returns Absolute path to git root, or cwd if not in git repo
|
|
8
|
+
*/
|
|
9
|
+
export declare function detectGitRoot(): string;
|
|
10
|
+
/**
|
|
11
|
+
* Compute SHA-256 hash of the .kici/package-lock.json lockfile.
|
|
12
|
+
* Used as part of the dependency cache key.
|
|
13
|
+
*
|
|
14
|
+
* @param gitRoot - Absolute path to git repository root
|
|
15
|
+
* @returns Hex SHA-256 hash string, or null if no lockfile found in .kici/
|
|
16
|
+
*/
|
|
17
|
+
export declare function computeLockfileHash(gitRoot: string): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Generate a lock file from validated workflows with source tracking.
|
|
20
|
+
*
|
|
21
|
+
* @param workflowsWithSource - Validated workflows with source info
|
|
22
|
+
* @returns Lock file ready for JSON serialization
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateLockFile(workflowsWithSource: WorkflowWithSource[]): LockFile;
|
|
25
|
+
/**
|
|
26
|
+
* Transform trigger configs to lock file format.
|
|
27
|
+
* Uses flatMap because push triggers with tags generate two lock triggers.
|
|
28
|
+
* Exported for reuse in the test runner's in-memory lock format conversion.
|
|
29
|
+
*/
|
|
30
|
+
export declare function transformTriggers(triggers?: TriggerConfig[]): readonly LockTrigger[];
|
|
31
|
+
/**
|
|
32
|
+
* Serialize lock file to JSON string.
|
|
33
|
+
*
|
|
34
|
+
* @param lockFile - Lock file object
|
|
35
|
+
* @param pretty - Whether to pretty-print (default: true)
|
|
36
|
+
* @returns JSON string
|
|
37
|
+
*/
|
|
38
|
+
export declare function serializeLockFile(lockFile: LockFile, pretty?: boolean): string;
|
|
39
|
+
//# sourceMappingURL=generator.d.ts.map
|