@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.
Files changed (221) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +1 -6
  3. package/dist/assets/api-TJJVHrjC.json +118 -0
  4. package/dist/assets/descriptor-BTtjzN9L.json +1382 -0
  5. package/dist/assets/package-BpQF9kR8.json +74 -0
  6. package/dist/assets/package-Ceo2h27X.json +89 -0
  7. package/dist/assets/source_context-D0atuL28.json +20 -0
  8. package/dist/assets/type-BFqO8SCZ.json +202 -0
  9. package/dist/auth/headless-detect.d.ts +14 -0
  10. package/dist/auth/headless-detect.js +25 -0
  11. package/dist/chunk-gOLHoazu.js +4 -0
  12. package/dist/cli.d.ts +3 -0
  13. package/dist/cli.js +193 -0
  14. package/dist/commands/cancel.d.ts +22 -0
  15. package/dist/commands/cancel.js +124 -0
  16. package/dist/commands/compile.d.ts +17 -0
  17. package/dist/commands/compile.js +99 -0
  18. package/dist/commands/docs.d.ts +26 -0
  19. package/dist/commands/docs.js +60 -0
  20. package/dist/commands/drain-worker.d.ts +19 -0
  21. package/dist/commands/drain-worker.js +45 -0
  22. package/dist/commands/endpoints.d.ts +53 -0
  23. package/dist/commands/endpoints.js +185 -0
  24. package/dist/commands/fixture.d.ts +14 -0
  25. package/dist/commands/fixture.js +104 -0
  26. package/dist/commands/hook.d.ts +20 -0
  27. package/dist/commands/hook.js +97 -0
  28. package/dist/commands/index.d.ts +33 -0
  29. package/dist/commands/index.js +20 -0
  30. package/dist/commands/init.d.ts +35 -0
  31. package/dist/commands/init.js +393 -0
  32. package/dist/commands/login.d.ts +23 -0
  33. package/dist/commands/login.js +144 -0
  34. package/dist/commands/logout.d.ts +18 -0
  35. package/dist/commands/logout.js +55 -0
  36. package/dist/commands/org.d.ts +27 -0
  37. package/dist/commands/org.js +126 -0
  38. package/dist/commands/run.d.ts +21 -0
  39. package/dist/commands/run.js +562 -0
  40. package/dist/commands/secrets-list.d.ts +16 -0
  41. package/dist/commands/secrets-list.js +85 -0
  42. package/dist/commands/status.d.ts +30 -0
  43. package/dist/commands/status.js +210 -0
  44. package/dist/commands/test.d.ts +61 -0
  45. package/dist/commands/test.js +220 -0
  46. package/dist/commands/types.d.ts +18 -0
  47. package/dist/commands/types.js +74 -0
  48. package/dist/commands/watch.d.ts +14 -0
  49. package/dist/commands/watch.js +97 -0
  50. package/dist/commands/workflows.d.ts +28 -0
  51. package/dist/commands/workflows.js +154 -0
  52. package/dist/comment-created.json +30 -0
  53. package/dist/create-branch.json +17 -0
  54. package/dist/delete-branch.json +15 -0
  55. package/dist/dispatch.json +15 -0
  56. package/dist/errors/capability-gap.d.ts +50 -0
  57. package/dist/errors/capability-gap.js +54 -0
  58. package/dist/errors/codes.d.ts +25 -0
  59. package/dist/errors/formatter.d.ts +32 -0
  60. package/dist/errors/formatter.js +35 -0
  61. package/dist/errors/index.d.ts +5 -0
  62. package/dist/errors/index.js +4 -0
  63. package/dist/execution/executor.d.ts +61 -0
  64. package/dist/execution/executor.js +230 -0
  65. package/dist/execution/index.d.ts +4 -0
  66. package/dist/execution/index.js +3 -0
  67. package/dist/execution/sdk-alias.d.ts +33 -0
  68. package/dist/execution/sdk-alias.js +102 -0
  69. package/dist/fixtures/compiler.d.ts +47 -0
  70. package/dist/fixtures/compiler.js +177 -0
  71. package/dist/fixtures/defaults/comment-created.json +30 -0
  72. package/dist/fixtures/defaults/create-branch.json +17 -0
  73. package/dist/fixtures/defaults/delete-branch.json +15 -0
  74. package/dist/fixtures/defaults/dispatch.json +15 -0
  75. package/dist/fixtures/defaults/fork.json +19 -0
  76. package/dist/fixtures/defaults/index.d.ts +16 -0
  77. package/dist/fixtures/defaults/index.js +105 -0
  78. package/dist/fixtures/defaults/index.ts +145 -0
  79. package/dist/fixtures/defaults/pr-closed.json +28 -0
  80. package/dist/fixtures/defaults/pr-opened.json +27 -0
  81. package/dist/fixtures/defaults/pr-reopened.json +27 -0
  82. package/dist/fixtures/defaults/pr-synchronize.json +27 -0
  83. package/dist/fixtures/defaults/push.json +16 -0
  84. package/dist/fixtures/defaults/release-published.json +23 -0
  85. package/dist/fixtures/defaults/review-comment-created.json +36 -0
  86. package/dist/fixtures/defaults/review-submitted.json +35 -0
  87. package/dist/fixtures/defaults/star-created.json +15 -0
  88. package/dist/fixtures/defaults/status.json +26 -0
  89. package/dist/fixtures/defaults/tag-push.json +20 -0
  90. package/dist/fixtures/defaults/watch-started.json +15 -0
  91. package/dist/fixtures/defaults/workflow-run-completed.json +23 -0
  92. package/dist/fork.json +19 -0
  93. package/dist/format.d.ts +5 -0
  94. package/dist/format.js +20 -0
  95. package/dist/generators/secrets-dts.d.ts +29 -0
  96. package/dist/generators/secrets-dts.js +67 -0
  97. package/dist/hooks/detector.d.ts +39 -0
  98. package/dist/hooks/detector.js +133 -0
  99. package/dist/hooks/index.d.ts +6 -0
  100. package/dist/hooks/index.js +5 -0
  101. package/dist/hooks/installer.d.ts +24 -0
  102. package/dist/hooks/installer.js +328 -0
  103. package/dist/hooks/templates.d.ts +26 -0
  104. package/dist/hooks/templates.js +63 -0
  105. package/dist/index.d.ts +12 -0
  106. package/dist/index.js +12 -0
  107. package/dist/llm-context/llms-full.txt +9974 -0
  108. package/dist/llm-context/llms.txt +61 -0
  109. package/dist/local-executor/dag-scheduler.d.ts +44 -0
  110. package/dist/local-executor/dag-scheduler.js +183 -0
  111. package/dist/local-executor/index.d.ts +23 -0
  112. package/dist/local-executor/index.js +309 -0
  113. package/dist/local-executor/job-runner.d.ts +40 -0
  114. package/dist/local-executor/job-runner.js +307 -0
  115. package/dist/local-executor/output-streamer.d.ts +31 -0
  116. package/dist/local-executor/output-streamer.js +166 -0
  117. package/dist/local-executor/payload-generator.d.ts +16 -0
  118. package/dist/local-executor/payload-generator.js +138 -0
  119. package/dist/local-executor/picker.d.ts +33 -0
  120. package/dist/local-executor/picker.js +109 -0
  121. package/dist/local-executor/secret-loader.d.ts +18 -0
  122. package/dist/local-executor/secret-loader.js +105 -0
  123. package/dist/local-executor/types.d.ts +80 -0
  124. package/dist/local-executor/types.js +2 -0
  125. package/dist/local-executor/workflow-lock.d.ts +81 -0
  126. package/dist/local-executor/workflow-lock.js +0 -0
  127. package/dist/lockfile/generator.d.ts +39 -0
  128. package/dist/lockfile/generator.js +688 -0
  129. package/dist/lockfile/hash-files.d.ts +14 -0
  130. package/dist/lockfile/hash-files.js +50 -0
  131. package/dist/lockfile/hasher.d.ts +36 -0
  132. package/dist/lockfile/hasher.js +46 -0
  133. package/dist/lockfile/index.d.ts +3 -0
  134. package/dist/lockfile/index.js +4 -0
  135. package/dist/lockfile/purity-analyzer.d.ts +25 -0
  136. package/dist/lockfile/purity-analyzer.js +204 -0
  137. package/dist/package-F7UXSDHW.json +74 -0
  138. package/dist/postinstall.d.ts +9 -0
  139. package/dist/postinstall.js +60 -0
  140. package/dist/pr-closed.json +28 -0
  141. package/dist/pr-opened.json +27 -0
  142. package/dist/pr-reopened.json +27 -0
  143. package/dist/pr-synchronize.json +27 -0
  144. package/dist/push.json +16 -0
  145. package/dist/release-published.json +23 -0
  146. package/dist/remote/client.d.ts +204 -0
  147. package/dist/remote/client.js +203 -0
  148. package/dist/remote/config.d.ts +54 -0
  149. package/dist/remote/config.js +92 -0
  150. package/dist/remote/encryption.d.ts +35 -0
  151. package/dist/remote/encryption.js +87 -0
  152. package/dist/remote/history.d.ts +91 -0
  153. package/dist/remote/history.js +146 -0
  154. package/dist/remote/oauth.d.ts +65 -0
  155. package/dist/remote/oauth.js +302 -0
  156. package/dist/remote/observer.d.ts +81 -0
  157. package/dist/remote/observer.js +174 -0
  158. package/dist/remote/output/json.d.ts +13 -0
  159. package/dist/remote/output/json.js +36 -0
  160. package/dist/remote/output/junit.d.ts +18 -0
  161. package/dist/remote/output/junit.js +50 -0
  162. package/dist/remote/output/streaming.d.ts +57 -0
  163. package/dist/remote/output/streaming.js +124 -0
  164. package/dist/remote/output/summary.d.ts +39 -0
  165. package/dist/remote/output/summary.js +99 -0
  166. package/dist/remote/uploader.d.ts +87 -0
  167. package/dist/remote/uploader.js +197 -0
  168. package/dist/review-comment-created.json +36 -0
  169. package/dist/review-submitted.json +35 -0
  170. package/dist/star-created.json +15 -0
  171. package/dist/status.json +26 -0
  172. package/dist/tag-push.json +20 -0
  173. package/dist/templates/agents-md.d.ts +8 -0
  174. package/dist/templates/agents-md.js +130 -0
  175. package/dist/templates/index.d.ts +43 -0
  176. package/dist/templates/index.js +48 -0
  177. package/dist/templates/package-json.d.ts +18 -0
  178. package/dist/templates/package-json.js +34 -0
  179. package/dist/templates/tsconfig-json.d.ts +9 -0
  180. package/dist/templates/tsconfig-json.js +26 -0
  181. package/dist/templates/workflows/hello-world.d.ts +2 -0
  182. package/dist/templates/workflows/hello-world.js +16 -0
  183. package/dist/templates/workflows/hello-world.ts +21 -0
  184. package/dist/templates/workflows/pr-checks.d.ts +2 -0
  185. package/dist/templates/workflows/pr-checks.js +40 -0
  186. package/dist/templates/workflows/pr-checks.ts +57 -0
  187. package/dist/test-runner/dry-run.d.ts +12 -0
  188. package/dist/test-runner/dry-run.js +66 -0
  189. package/dist/test-runner/event-types.d.ts +86 -0
  190. package/dist/test-runner/event-types.js +330 -0
  191. package/dist/test-runner/git-detector.d.ts +15 -0
  192. package/dist/test-runner/git-detector.js +30 -0
  193. package/dist/test-runner/index.d.ts +13 -0
  194. package/dist/test-runner/index.js +11 -0
  195. package/dist/test-runner/job-executor.d.ts +48 -0
  196. package/dist/test-runner/job-executor.js +245 -0
  197. package/dist/test-runner/output-formatter.d.ts +47 -0
  198. package/dist/test-runner/output-formatter.js +92 -0
  199. package/dist/test-runner/payload-builder.d.ts +20 -0
  200. package/dist/test-runner/payload-builder.js +216 -0
  201. package/dist/test-runner/rule-evaluator.d.ts +14 -0
  202. package/dist/test-runner/rule-evaluator.js +31 -0
  203. package/dist/test-runner/secrets-file.d.ts +24 -0
  204. package/dist/test-runner/secrets-file.js +62 -0
  205. package/dist/test-runner/step-context.d.ts +15 -0
  206. package/dist/test-runner/step-context.js +140 -0
  207. package/dist/test-runner/summary.d.ts +7 -0
  208. package/dist/types.d.ts +525 -0
  209. package/dist/types.js +33 -0
  210. package/dist/validation/index.d.ts +3 -0
  211. package/dist/validation/index.js +3 -0
  212. package/dist/validation/validator.d.ts +26 -0
  213. package/dist/validation/validator.js +164 -0
  214. package/dist/watch-started.json +15 -0
  215. package/dist/workflow-run-completed.json +23 -0
  216. package/dist/workflows/hello-world.ts +21 -0
  217. package/dist/workflows/pr-checks.ts +57 -0
  218. package/hack/postinstall.mjs +105 -0
  219. package/package.json +60 -6
  220. package/sbom.spdx.json +10997 -0
  221. package/index.js +0 -3
@@ -0,0 +1,307 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { formatter } from "../test-runner/output-formatter.js";
3
+ import { createStepContext } from "../test-runner/step-context.js";
4
+ import { createRuleContext, evaluateRules as evaluateRulesWithFormatting } from "../test-runner/rule-evaluator.js";
5
+ import path from "node:path";
6
+ import { pathToFileURL } from "node:url";
7
+ import { applyIncludeExclude, expandMatrix, isDynamicJobFn, setJobOutputsMap, setStepOutputsMap, setStepRefMap } from "@kici-dev/sdk";
8
+ //#region src/local-executor/job-runner.ts
9
+ /**
10
+ * Job resolution (matrix/dynamic) and single-job execution with step context.
11
+ *
12
+ * Handles:
13
+ * - Static job resolution
14
+ * - Matrix expansion into multiple ResolvedJob instances
15
+ * - Dynamic job function evaluation
16
+ * - Single-job step-by-step execution with rules, abort, and output chaining
17
+ */
18
+ /**
19
+ * Resolve SDK output setter functions from the workflow's module instance.
20
+ * Ensures output maps are set on the same SDK module the workflow code uses.
21
+ */
22
+ async function resolveSdkSetters(kiciDir) {
23
+ if (kiciDir) try {
24
+ const sdk = await import(pathToFileURL(path.join(kiciDir, "node_modules", "@kici-dev", "sdk", "dist", "index.js")).href);
25
+ return {
26
+ setStepOutputsMap: sdk.setStepOutputsMap,
27
+ setStepRefMap: sdk.setStepRefMap,
28
+ setJobOutputsMap: sdk.setJobOutputsMap
29
+ };
30
+ } catch {}
31
+ return {
32
+ setStepOutputsMap,
33
+ setStepRefMap,
34
+ setJobOutputsMap
35
+ };
36
+ }
37
+ /**
38
+ * Format matrix values into a display string for the job name.
39
+ * Single-dimension: "node-18"
40
+ * Multi-dimensional: "linux, 18"
41
+ */
42
+ function formatMatrixSuffix(matrixValues) {
43
+ if ("value" in matrixValues && matrixValues.value !== void 0) return matrixValues.value;
44
+ return Object.values(matrixValues).filter((v) => v !== void 0).join(", ");
45
+ }
46
+ /**
47
+ * Resolve a needs entry to a string name.
48
+ * Handles Job objects, strings, DynamicGroupRef, and object forms.
49
+ */
50
+ function resolveNeedName(need) {
51
+ if (typeof need === "string") return need;
52
+ if ("name" in need) return need.name;
53
+ if ("group" in need) return `__group:${need.group}`;
54
+ return need.name;
55
+ }
56
+ /**
57
+ * Resolve all jobs in a workflow, expanding matrix jobs and evaluating dynamic jobs.
58
+ *
59
+ * - Static jobs: create ResolvedJob with name, needs, job reference
60
+ * - Matrix jobs: use expandMatrix() from SDK, create one ResolvedJob per combination
61
+ * - Dynamic job functions: evaluate the function, recursively resolve results
62
+ * - Fan-in: if a job needs a matrix-expanded job, it needs ALL instances
63
+ */
64
+ async function resolveJobs(workflow, event) {
65
+ const resolved = [];
66
+ const expansionMap = /* @__PURE__ */ new Map();
67
+ for (const jobOrFn of workflow.jobs) if (isDynamicJobFn(jobOrFn)) {
68
+ const generatedJobs = await jobOrFn({
69
+ $: (await import("zx")).$,
70
+ ctx: {
71
+ workflow: { name: workflow.name },
72
+ event: {
73
+ type: event.type,
74
+ ...event.payload
75
+ }
76
+ },
77
+ log: {
78
+ info: () => {},
79
+ warn: () => {},
80
+ error: () => {},
81
+ debug: () => {}
82
+ },
83
+ env: { ...process.env },
84
+ kici: { infrastructure: { list: () => Promise.resolve({
85
+ scalers: [],
86
+ agents: []
87
+ }) } }
88
+ });
89
+ for (const genJob of generatedJobs) {
90
+ const genResolved = await resolveStaticJob(genJob, expansionMap);
91
+ resolved.push(...genResolved);
92
+ }
93
+ } else {
94
+ const jobResolved = await resolveStaticJob(jobOrFn, expansionMap);
95
+ resolved.push(...jobResolved);
96
+ }
97
+ for (const r of resolved) r.resolvedNeeds = resolveNeedsWithExpansion(r.job, expansionMap);
98
+ return resolved;
99
+ }
100
+ /**
101
+ * Resolve a single static job, potentially expanding its matrix.
102
+ */
103
+ async function resolveStaticJob(job, expansionMap) {
104
+ if (!job.matrix) {
105
+ expansionMap.set(job.name, [job.name]);
106
+ return [{
107
+ job,
108
+ expandedName: job.name,
109
+ matrixValues: {},
110
+ resolvedNeeds: []
111
+ }];
112
+ }
113
+ let staticMatrix;
114
+ if (typeof job.matrix === "function") {
115
+ const matrixContext = {
116
+ $: (await import("zx")).$,
117
+ ctx: {
118
+ workflow: { name: "" },
119
+ job: {
120
+ name: job.name,
121
+ runsOn: job.runsOn
122
+ }
123
+ },
124
+ log: {
125
+ info: () => {},
126
+ warn: () => {},
127
+ error: () => {},
128
+ debug: () => {}
129
+ },
130
+ env: { ...process.env }
131
+ };
132
+ staticMatrix = await job.matrix(matrixContext);
133
+ } else staticMatrix = job.matrix;
134
+ let expanded = expandMatrix(staticMatrix);
135
+ if (job.include || job.exclude) expanded = applyIncludeExclude(expanded, job.include, job.exclude);
136
+ const expandedNames = [];
137
+ const results = [];
138
+ for (const matrixValues of expanded) {
139
+ const suffix = formatMatrixSuffix(matrixValues);
140
+ const expandedName = `${job.name} (${suffix})`;
141
+ expandedNames.push(expandedName);
142
+ results.push({
143
+ job,
144
+ expandedName,
145
+ matrixValues,
146
+ resolvedNeeds: []
147
+ });
148
+ }
149
+ expansionMap.set(job.name, expandedNames);
150
+ return results;
151
+ }
152
+ /**
153
+ * Resolve needs with matrix expansion awareness.
154
+ * If a job needs a matrix-expanded job, it needs ALL expanded instances (fan-in).
155
+ */
156
+ function resolveNeedsWithExpansion(job, expansionMap) {
157
+ if (!job.needs || job.needs.length === 0) return [];
158
+ const resolvedNeeds = [];
159
+ for (const need of job.needs) {
160
+ const needName = resolveNeedName(need);
161
+ const expandedNames = expansionMap.get(needName);
162
+ if (expandedNames) resolvedNeeds.push(...expandedNames);
163
+ else resolvedNeeds.push(needName);
164
+ }
165
+ return resolvedNeeds;
166
+ }
167
+ /**
168
+ * Execute a single resolved job: evaluate rules, run steps sequentially,
169
+ * check abort signal between steps, collect outputs.
170
+ */
171
+ async function executeResolvedJob(resolvedJob, context) {
172
+ const { expandedName, matrixValues } = resolvedJob;
173
+ const startTime = Date.now();
174
+ const hasMatrix = Object.keys(matrixValues).length > 0;
175
+ try {
176
+ return await executeResolvedJobInner(resolvedJob, context, startTime);
177
+ } catch (e) {
178
+ const durationMs = Date.now() - startTime;
179
+ const error = e instanceof Error ? e : new Error(String(e));
180
+ formatter.logJobFailure(expandedName, durationMs, error);
181
+ return {
182
+ name: expandedName,
183
+ status: "failure",
184
+ durationMs,
185
+ steps: [],
186
+ error,
187
+ matrixValues: hasMatrix ? matrixValues : void 0
188
+ };
189
+ }
190
+ }
191
+ async function executeResolvedJobInner(resolvedJob, context, startTime) {
192
+ const { job, expandedName, matrixValues } = resolvedJob;
193
+ formatter.logJobStart(expandedName);
194
+ const sdkSetters = await resolveSdkSetters(context.kiciDir);
195
+ let ruleResults;
196
+ if (job.rules && job.rules.length > 0) {
197
+ const ruleContext = createRuleContext(context.event, context.event.changedFiles);
198
+ const ruleEval = await evaluateRulesWithFormatting(job.rules, ruleContext, expandedName);
199
+ ruleResults = ruleEval.results;
200
+ if (!ruleEval.allPassed) return {
201
+ name: expandedName,
202
+ status: "skipped",
203
+ durationMs: Date.now() - startTime,
204
+ steps: [],
205
+ ruleResults,
206
+ matrixValues: Object.keys(matrixValues).length > 0 ? matrixValues : void 0
207
+ };
208
+ }
209
+ const outputsMap = /* @__PURE__ */ new Map();
210
+ const refMap = /* @__PURE__ */ new WeakMap();
211
+ sdkSetters.setStepOutputsMap(outputsMap);
212
+ sdkSetters.setStepRefMap(refMap);
213
+ setStepOutputsMap(outputsMap);
214
+ setStepRefMap(refMap);
215
+ sdkSetters.setJobOutputsMap(context.jobOutputsMap);
216
+ setJobOutputsMap(context.jobOutputsMap);
217
+ const hasMatrix = Object.keys(matrixValues).length > 0;
218
+ const repoRoot = path.dirname(context.kiciDir);
219
+ const stepCtx = createStepContext({ name: context.workflowName }, {
220
+ name: expandedName,
221
+ runsOn: typeof job.runsOn === "string" ? job.runsOn : Array.isArray(job.runsOn) ? job.runsOn.join(",") : (Array.isArray(job.runsOn.labels) ? job.runsOn.labels : [job.runsOn.labels]).join(",")
222
+ }, repoRoot, void 0, hasMatrix ? matrixValues : void 0, context.secrets, void 0, context.event.payload, context.event.provider);
223
+ const stepResults = [];
224
+ let stepCounter = 0;
225
+ for (const stepOrFn of job.steps) {
226
+ if (context.signal.aborted) return {
227
+ name: expandedName,
228
+ status: "cancelled",
229
+ durationMs: Date.now() - startTime,
230
+ steps: stepResults,
231
+ ruleResults,
232
+ matrixValues: hasMatrix ? matrixValues : void 0,
233
+ cancelled: true
234
+ };
235
+ let normalizedStep;
236
+ if (typeof stepOrFn === "function") {
237
+ stepCounter++;
238
+ const name = `step-${stepCounter}`;
239
+ refMap.set(stepOrFn, name);
240
+ normalizedStep = {
241
+ _tag: "Step",
242
+ name,
243
+ run: stepOrFn
244
+ };
245
+ } else {
246
+ normalizedStep = stepOrFn;
247
+ if (!normalizedStep.name) stepCounter++;
248
+ }
249
+ formatter.logStepStart(expandedName, normalizedStep.name);
250
+ const stepStart = Date.now();
251
+ try {
252
+ const outputs = await normalizedStep.run(stepCtx);
253
+ const stepDuration = Date.now() - stepStart;
254
+ formatter.logStepComplete(expandedName, normalizedStep.name, stepDuration);
255
+ const stepResult = {
256
+ name: normalizedStep.name,
257
+ status: "success",
258
+ durationMs: stepDuration,
259
+ outputs
260
+ };
261
+ if (outputs != null) outputsMap.set(normalizedStep.name, outputs);
262
+ stepResults.push(stepResult);
263
+ } catch (e) {
264
+ const stepDuration = Date.now() - stepStart;
265
+ const error = e instanceof Error ? e : new Error(String(e));
266
+ formatter.logStepError(expandedName, normalizedStep.name, error);
267
+ stepResults.push({
268
+ name: normalizedStep.name,
269
+ status: "failure",
270
+ durationMs: stepDuration,
271
+ error
272
+ });
273
+ const durationMs = Date.now() - startTime;
274
+ formatter.logJobFailure(expandedName, durationMs, error);
275
+ return {
276
+ name: expandedName,
277
+ status: "failure",
278
+ durationMs,
279
+ steps: stepResults,
280
+ ruleResults,
281
+ matrixValues: hasMatrix ? matrixValues : void 0,
282
+ error
283
+ };
284
+ }
285
+ }
286
+ const stepsWithOutputs = stepResults.filter((s) => s.outputs != null);
287
+ if (stepsWithOutputs.length === 1 && stepResults.length === 1) context.jobOutputsMap.set(expandedName, stepsWithOutputs[0].outputs);
288
+ else if (stepsWithOutputs.length > 0) {
289
+ const aggregated = {};
290
+ for (const stepResult of stepsWithOutputs) aggregated[stepResult.name] = stepResult.outputs;
291
+ context.jobOutputsMap.set(expandedName, aggregated);
292
+ }
293
+ const durationMs = Date.now() - startTime;
294
+ formatter.logJobComplete(expandedName, durationMs);
295
+ return {
296
+ name: expandedName,
297
+ status: "success",
298
+ durationMs,
299
+ steps: stepResults,
300
+ ruleResults,
301
+ matrixValues: hasMatrix ? matrixValues : void 0
302
+ };
303
+ }
304
+ //#endregion
305
+ export { executeResolvedJob, resolveJobs };
306
+
307
+ //# sourceMappingURL=job-runner.js.map
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Output formatting for local execution: tree summary, JSON, JUnit XML.
3
+ *
4
+ * - displayLocalSummary: tree-format summary with per-step timing
5
+ * - formatLocalJsonResult: structured JSON output
6
+ * - formatLocalJunitResult: JUnit XML for CI integration
7
+ */
8
+ import type { WorkflowExecutionResult } from './types.js';
9
+ /**
10
+ * Display tree-format execution summary to the console.
11
+ *
12
+ * Shows per-workflow, per-job, per-step timing and status.
13
+ * Matrix values appear in the job name.
14
+ */
15
+ export declare function displayLocalSummary(results: WorkflowExecutionResult[]): void;
16
+ /**
17
+ * Format workflow execution results as structured JSON.
18
+ *
19
+ * @returns JSON string with 2-space indentation.
20
+ */
21
+ export declare function formatLocalJsonResult(results: WorkflowExecutionResult[]): string;
22
+ /**
23
+ * Format workflow execution results as JUnit XML.
24
+ *
25
+ * Each workflow maps to a <testsuite>, each job maps to a <testcase>.
26
+ * Failed jobs include failure message. Skipped/cancelled jobs use <skipped />.
27
+ *
28
+ * @returns Valid JUnit XML string.
29
+ */
30
+ export declare function formatLocalJunitResult(results: WorkflowExecutionResult[]): string;
31
+ //# sourceMappingURL=output-streamer.d.ts.map
@@ -0,0 +1,166 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import pc from "picocolors";
3
+ import { logger } from "@kici-dev/shared";
4
+ //#region src/local-executor/output-streamer.ts
5
+ /**
6
+ * Output formatting for local execution: tree summary, JSON, JUnit XML.
7
+ *
8
+ * - displayLocalSummary: tree-format summary with per-step timing
9
+ * - formatLocalJsonResult: structured JSON output
10
+ * - formatLocalJunitResult: JUnit XML for CI integration
11
+ */
12
+ /**
13
+ * Display tree-format execution summary to the console.
14
+ *
15
+ * Shows per-workflow, per-job, per-step timing and status.
16
+ * Matrix values appear in the job name.
17
+ */
18
+ function displayLocalSummary(results) {
19
+ const hasFailure = results.some((r) => r.status === "failure");
20
+ const allSkipped = results.every((r) => r.status === "skipped");
21
+ logger.info("");
22
+ logger.info(pc.bold("=== EXECUTION SUMMARY ==="));
23
+ logger.info("");
24
+ const overallStatus = hasFailure ? pc.red("FAILED") : allSkipped ? pc.yellow("SKIPPED") : pc.green("SUCCESS");
25
+ logger.info(`Status: ${overallStatus}`);
26
+ logger.info("");
27
+ for (const workflow of results) {
28
+ logger.info(`Workflow: ${pc.bold(workflow.name)} (${workflow.durationMs}ms)`);
29
+ for (const job of workflow.jobs) {
30
+ const jobLabel = formatJobLabel(job);
31
+ const jobIcon = statusIcon(job.status);
32
+ logger.info(` ${jobIcon} ${jobLabel} (${job.durationMs}ms)`);
33
+ if (job.ruleResults && job.ruleResults.length > 0) for (const rule of job.ruleResults) {
34
+ const rIcon = rule.passed ? pc.green("[ok]") : pc.red("[fail]");
35
+ logger.info(pc.gray(` ${rIcon} rule: ${rule.label}`));
36
+ }
37
+ for (const step of job.steps) {
38
+ const sIcon = step.status === "success" ? pc.green("[ok]") : pc.red("[fail]");
39
+ logger.info(` ${sIcon} ${step.name} (${step.durationMs}ms)`);
40
+ if (step.error) logger.info(pc.red(` Error: ${step.error.message}`));
41
+ }
42
+ if (job.status === "cancelled") logger.info(pc.yellow(" (cancelled)"));
43
+ else if (job.status === "skipped") logger.info(pc.yellow(" (skipped: dependency failed)"));
44
+ }
45
+ logger.info("");
46
+ }
47
+ const totalDuration = results.reduce((sum, r) => sum + r.durationMs, 0);
48
+ logger.info(pc.gray(`Total duration: ${totalDuration}ms`));
49
+ }
50
+ /**
51
+ * Format job label including matrix values if present.
52
+ * e.g., "test (node18, ubuntu)" or just "lint"
53
+ */
54
+ function formatJobLabel(job) {
55
+ if (job.matrixValues && Object.keys(job.matrixValues).length > 0) {
56
+ const vals = Object.values(job.matrixValues).join(", ");
57
+ if (job.name.includes("(")) return job.name;
58
+ return `${job.name} (${vals})`;
59
+ }
60
+ return job.name;
61
+ }
62
+ /**
63
+ * Get colored status icon for a job status.
64
+ */
65
+ function statusIcon(status) {
66
+ switch (status) {
67
+ case "success": return pc.green("[ok]");
68
+ case "failure": return pc.red("[fail]");
69
+ case "skipped": return pc.yellow("[skip]");
70
+ case "cancelled": return pc.yellow("[cancel]");
71
+ default: return pc.gray("[?]");
72
+ }
73
+ }
74
+ /**
75
+ * Format workflow execution results as structured JSON.
76
+ *
77
+ * @returns JSON string with 2-space indentation.
78
+ */
79
+ function formatLocalJsonResult(results) {
80
+ const passed = results.filter((r) => r.status === "success").length;
81
+ const failed = results.filter((r) => r.status === "failure").length;
82
+ const skipped = results.filter((r) => r.status === "skipped").length;
83
+ const totalDurationMs = results.reduce((sum, r) => sum + r.durationMs, 0);
84
+ const output = {
85
+ workflows: results.map((wf) => ({
86
+ name: wf.name,
87
+ status: wf.status,
88
+ durationMs: wf.durationMs,
89
+ jobs: wf.jobs.map((job) => ({
90
+ name: job.name,
91
+ status: job.status,
92
+ durationMs: job.durationMs,
93
+ ...job.matrixValues && Object.keys(job.matrixValues).length > 0 && { matrixValues: job.matrixValues },
94
+ steps: job.steps.map((step) => ({
95
+ name: step.name,
96
+ status: step.status,
97
+ durationMs: step.durationMs,
98
+ ...step.error && { error: step.error.message }
99
+ })),
100
+ ...job.ruleResults && job.ruleResults.length > 0 && { ruleResults: job.ruleResults.map((r) => ({
101
+ label: r.label,
102
+ passed: r.passed,
103
+ durationMs: r.durationMs
104
+ })) },
105
+ ...job.error && { error: job.error.message }
106
+ }))
107
+ })),
108
+ summary: {
109
+ totalWorkflows: results.length,
110
+ passed,
111
+ failed,
112
+ skipped,
113
+ totalDurationMs
114
+ }
115
+ };
116
+ return JSON.stringify(output, null, 2);
117
+ }
118
+ /**
119
+ * Format workflow execution results as JUnit XML.
120
+ *
121
+ * Each workflow maps to a <testsuite>, each job maps to a <testcase>.
122
+ * Failed jobs include failure message. Skipped/cancelled jobs use <skipped />.
123
+ *
124
+ * @returns Valid JUnit XML string.
125
+ */
126
+ function formatLocalJunitResult(results) {
127
+ const totalTests = results.reduce((sum, r) => sum + r.jobs.length, 0);
128
+ const totalFailures = results.reduce((sum, r) => sum + r.jobs.filter((j) => j.status === "failure").length, 0);
129
+ const totalTimeSeconds = results.reduce((sum, r) => sum + r.durationMs / 1e3, 0);
130
+ const lines = [];
131
+ lines.push("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
132
+ lines.push(`<testsuites name="kici-local" tests="${totalTests}" failures="${totalFailures}" time="${totalTimeSeconds.toFixed(3)}">`);
133
+ for (const workflow of results) {
134
+ const suiteTests = workflow.jobs.length;
135
+ const suiteFailures = workflow.jobs.filter((j) => j.status === "failure").length;
136
+ const suiteTimeSeconds = workflow.durationMs / 1e3;
137
+ lines.push(` <testsuite name="${escapeXml(workflow.name)}" tests="${suiteTests}" failures="${suiteFailures}" time="${suiteTimeSeconds.toFixed(3)}">`);
138
+ for (const job of workflow.jobs) {
139
+ const jobTimeSeconds = job.durationMs / 1e3;
140
+ const jobName = formatJobLabel(job);
141
+ if (job.status === "failure") {
142
+ const errorMsg = job.error?.message ?? "Job failed";
143
+ lines.push(` <testcase name="${escapeXml(jobName)}" classname="${escapeXml(workflow.name)}" time="${jobTimeSeconds.toFixed(3)}">`);
144
+ lines.push(` <failure message="${escapeXml(errorMsg)}">${escapeXml(errorMsg)}</failure>`);
145
+ lines.push(" </testcase>");
146
+ } else if (job.status === "skipped" || job.status === "cancelled") {
147
+ lines.push(` <testcase name="${escapeXml(jobName)}" classname="${escapeXml(workflow.name)}" time="${jobTimeSeconds.toFixed(3)}">`);
148
+ lines.push(" <skipped />");
149
+ lines.push(" </testcase>");
150
+ } else lines.push(` <testcase name="${escapeXml(jobName)}" classname="${escapeXml(workflow.name)}" time="${jobTimeSeconds.toFixed(3)}" />`);
151
+ }
152
+ lines.push(" </testsuite>");
153
+ }
154
+ lines.push("</testsuites>");
155
+ return lines.join("\n");
156
+ }
157
+ /**
158
+ * Escape special XML characters in a string.
159
+ */
160
+ function escapeXml(text) {
161
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
162
+ }
163
+ //#endregion
164
+ export { displayLocalSummary, formatLocalJsonResult, formatLocalJunitResult };
165
+
166
+ //# sourceMappingURL=output-streamer.js.map
@@ -0,0 +1,16 @@
1
+ import type { SimulatedEvent } from '@kici-dev/engine';
2
+ import type { RunLocalOptions } from './types.js';
3
+ /**
4
+ * Generate a SimulatedEvent from git state and CLI overrides.
5
+ *
6
+ * For push events: detects branch, SHA, and changed files from git.
7
+ * For PR events: uses current branch as source, 'main' (or --branch) as target.
8
+ * If --payload flag is provided, delegates to existing buildEventPayload.
9
+ * Falls back gracefully when not in a git repository.
10
+ *
11
+ * @param event - Event argument string (e.g. 'push', 'pr:open')
12
+ * @param options - CLI options with override fields
13
+ * @returns Generated SimulatedEvent
14
+ */
15
+ export declare function generateEventPayload(event: string, options: RunLocalOptions): Promise<SimulatedEvent>;
16
+ //# sourceMappingURL=payload-generator.d.ts.map
@@ -0,0 +1,138 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { parseEventArg } from "../test-runner/event-types.js";
3
+ import { buildEventPayload } from "../test-runner/payload-builder.js";
4
+ import { execSync } from "node:child_process";
5
+ //#region src/local-executor/payload-generator.ts
6
+ const ZERO_SHA = "0000000000000000000000000000000000000000";
7
+ /**
8
+ * Run a git command and return trimmed output, or null on failure.
9
+ */
10
+ function git(cmd) {
11
+ try {
12
+ return execSync(cmd, {
13
+ encoding: "utf-8",
14
+ stdio: [
15
+ "pipe",
16
+ "pipe",
17
+ "pipe"
18
+ ]
19
+ }).trim();
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+ /**
25
+ * Detect current git branch name.
26
+ */
27
+ function detectBranch() {
28
+ return git("git rev-parse --abbrev-ref HEAD");
29
+ }
30
+ /**
31
+ * Detect current git HEAD SHA.
32
+ */
33
+ function detectSha() {
34
+ return git("git rev-parse HEAD");
35
+ }
36
+ /**
37
+ * Detect changed files from git diff (unstaged + staged, deduplicated).
38
+ */
39
+ function detectChangedFiles() {
40
+ const unstaged = git("git diff --name-only HEAD");
41
+ const staged = git("git diff --name-only --cached");
42
+ const files = /* @__PURE__ */ new Set();
43
+ if (unstaged) for (const f of unstaged.split("\n").filter(Boolean)) files.add(f);
44
+ if (staged) for (const f of staged.split("\n").filter(Boolean)) files.add(f);
45
+ return [...files];
46
+ }
47
+ /**
48
+ * Generate a SimulatedEvent from git state and CLI overrides.
49
+ *
50
+ * For push events: detects branch, SHA, and changed files from git.
51
+ * For PR events: uses current branch as source, 'main' (or --branch) as target.
52
+ * If --payload flag is provided, delegates to existing buildEventPayload.
53
+ * Falls back gracefully when not in a git repository.
54
+ *
55
+ * @param event - Event argument string (e.g. 'push', 'pr:open')
56
+ * @param options - CLI options with override fields
57
+ * @returns Generated SimulatedEvent
58
+ */
59
+ async function generateEventPayload(event, options) {
60
+ if (options.payload) return buildEventPayload(event, {
61
+ payload: options.payload,
62
+ branch: options.branch,
63
+ sha: options.sha,
64
+ files: options.files
65
+ });
66
+ const eventType = parseEventArg(event);
67
+ const detectedBranch = detectBranch() ?? "main";
68
+ const detectedSha = detectSha() ?? ZERO_SHA;
69
+ const changedFiles = options.files && options.files.length > 0 ? options.files : detectChangedFiles();
70
+ const branch = options.branch ?? detectedBranch;
71
+ const sha = options.sha ?? detectedSha;
72
+ switch (eventType.type) {
73
+ case "push": return {
74
+ type: "push",
75
+ payload: {
76
+ ref: `refs/heads/${branch}`,
77
+ after: sha,
78
+ before: ZERO_SHA,
79
+ head_commit: {
80
+ id: sha,
81
+ message: "local execution"
82
+ },
83
+ repository: { default_branch: "main" }
84
+ },
85
+ targetBranch: branch,
86
+ changedFiles
87
+ };
88
+ case "pull_request": {
89
+ const action = "action" in eventType ? eventType.action : "opened";
90
+ const targetBranch = options.branch ?? "main";
91
+ const sourceBranch = detectedBranch;
92
+ return {
93
+ type: "pull_request",
94
+ action,
95
+ payload: {
96
+ action,
97
+ number: 1,
98
+ pull_request: {
99
+ number: 1,
100
+ head: {
101
+ ref: sourceBranch,
102
+ sha
103
+ },
104
+ base: { ref: targetBranch }
105
+ },
106
+ repository: { default_branch: "main" }
107
+ },
108
+ targetBranch,
109
+ sourceBranch,
110
+ changedFiles
111
+ };
112
+ }
113
+ case "tag": return {
114
+ type: "tag",
115
+ payload: {
116
+ ref: `refs/tags/${branch}`,
117
+ after: sha,
118
+ repository: { default_branch: "main" }
119
+ },
120
+ targetBranch: branch,
121
+ changedFiles
122
+ };
123
+ default: {
124
+ const action = "action" in eventType ? eventType.action : void 0;
125
+ return {
126
+ type: eventType.type,
127
+ action,
128
+ payload: { repository: { default_branch: "main" } },
129
+ targetBranch: branch,
130
+ changedFiles
131
+ };
132
+ }
133
+ }
134
+ }
135
+ //#endregion
136
+ export { generateEventPayload };
137
+
138
+ //# sourceMappingURL=payload-generator.js.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Interactive workflow picker for `kici run local --pick`.
3
+ *
4
+ * Lists every workflow with a summary of its triggers, lets the user pick one
5
+ * (and a specific trigger when there are multiple), and returns the derived
6
+ * event arg plus workflow name. The caller feeds these back into the standard
7
+ * executeLocal pipeline so the run remains consistent with normal trigger
8
+ * matching.
9
+ */
10
+ import type { Workflow } from '@kici-dev/sdk';
11
+ export declare class PickerCancelledError extends Error {
12
+ constructor(message: string);
13
+ }
14
+ export interface PickerOptions {
15
+ /**
16
+ * Optional event-arg filter. When set, restrict the workflow list to those
17
+ * with at least one trigger whose derived event arg shares the same family
18
+ * (e.g. `filterEvent: 'pr'` keeps any workflow with a `pr:*` trigger).
19
+ */
20
+ filterEvent?: string;
21
+ }
22
+ export interface PickerResult {
23
+ event: string;
24
+ workflow: string;
25
+ }
26
+ /**
27
+ * Run the interactive picker.
28
+ *
29
+ * @throws PickerCancelledError when stdin is not a TTY, when no eligible
30
+ * workflows exist, or when the user aborts one of the prompts.
31
+ */
32
+ export declare function runPicker(workflows: Workflow[], opts?: PickerOptions): Promise<PickerResult>;
33
+ //# sourceMappingURL=picker.d.ts.map