@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,210 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { formatCapabilityGapError } from "../errors/capability-gap.js";
3
+ import { loadGlobalConfig } from "../remote/config.js";
4
+ import { AuthenticationError, ConnectionError, NotFoundError, OrchestratorClient } from "../remote/client.js";
5
+ import { StreamingFormatter } from "../remote/output/streaming.js";
6
+ import { RunHistory } from "../remote/history.js";
7
+ import { observeCompletion } from "./run.js";
8
+ import pc from "picocolors";
9
+ import { formatDuration, logger, toErrorMessage } from "@kici-dev/shared";
10
+ //#region src/commands/status.ts
11
+ /**
12
+ * kici status command
13
+ *
14
+ * Shows the status and details of a test run, with optional log streaming.
15
+ * Looks up local history first, then fetches from the orchestrator for
16
+ * up-to-date status and logs.
17
+ */
18
+ const CLI_VERSION = typeof KICI_VERSION !== "undefined" ? KICI_VERSION : "0.0.1";
19
+ /**
20
+ * Show status and details of a test run.
21
+ *
22
+ * Default mode: show run summary table from local history + orchestrator.
23
+ * --logs: stream full logs from the orchestrator.
24
+ * --job <name>: filter logs to a specific job.
25
+ * --json: output raw JSON.
26
+ *
27
+ * @param runId - The run ID to inspect
28
+ * @param options - Status display options
29
+ * @returns true on success, false on error
30
+ */
31
+ async function statusCommand(runId, options = {}) {
32
+ try {
33
+ const history = new RunHistory();
34
+ await history.load();
35
+ const localEntry = history.getEntry(runId);
36
+ if (!options.json) displayAuthInfo(await loadGlobalConfig());
37
+ const config = await loadGlobalConfig();
38
+ const endpoint = config.endpoint ?? config.platformEndpoint;
39
+ if (!config.token || !endpoint) {
40
+ if (localEntry) {
41
+ if (options.json) console.log(JSON.stringify(localEntry, null, 2));
42
+ else displayLocalEntry(localEntry);
43
+ return true;
44
+ }
45
+ logger.error(pc.red("Not authenticated and no local history for this run. Run `kici login` to authenticate."));
46
+ return false;
47
+ }
48
+ const client = new OrchestratorClient({
49
+ endpoint,
50
+ token: config.token
51
+ });
52
+ try {
53
+ const remoteStatus = await client.getRunStatus(runId);
54
+ if (options.json) {
55
+ console.log(JSON.stringify(remoteStatus, null, 2));
56
+ return true;
57
+ }
58
+ if (options.logs) return await displayLogs(client, config.token, runId, options.job);
59
+ displayRunSummary(remoteStatus, localEntry);
60
+ return true;
61
+ } catch (error) {
62
+ if (error instanceof NotFoundError) {
63
+ if (localEntry) {
64
+ if (options.json) console.log(JSON.stringify(localEntry, null, 2));
65
+ else {
66
+ logger.info(pc.yellow("Run not found on orchestrator. Showing local history:\n"));
67
+ displayLocalEntry(localEntry);
68
+ }
69
+ return true;
70
+ }
71
+ logger.error(pc.red(`Run not found: ${runId}`));
72
+ return false;
73
+ }
74
+ if (error instanceof AuthenticationError) {
75
+ logger.error(pc.red("Authentication failed. Run `kici login` to re-authenticate."));
76
+ return false;
77
+ }
78
+ if (error instanceof ConnectionError) {
79
+ if (localEntry) {
80
+ logger.info(pc.yellow("Cannot reach orchestrator. Showing local history (may be stale):\n"));
81
+ if (options.json) console.log(JSON.stringify(localEntry, null, 2));
82
+ else displayLocalEntry(localEntry);
83
+ return true;
84
+ }
85
+ logger.error(pc.red(`Connection failed: ${error.message}`));
86
+ return false;
87
+ }
88
+ throw error;
89
+ }
90
+ } catch (error) {
91
+ const message = toErrorMessage(error);
92
+ logger.error(pc.red(`Error: ${message}`));
93
+ return false;
94
+ }
95
+ }
96
+ /**
97
+ * Display a run summary from remote status (+ local context).
98
+ */
99
+ function displayRunSummary(remote, local) {
100
+ const statusColor = remote.status === "success" ? pc.green : remote.status === "failed" ? pc.red : remote.status === "cancelled" ? pc.yellow : pc.blue;
101
+ logger.info(pc.bold(`\nRun: ${remote.runId}`));
102
+ logger.info(`Status: ${statusColor(remote.status)}`);
103
+ if (local?.fixtureId) logger.info(`Fixture: ${pc.cyan(local.fixtureId)}`);
104
+ if (local?.endpoint) logger.info(`Endpoint: ${pc.gray(local.endpoint)}`);
105
+ if (local?.startedAt) logger.info(`Started: ${pc.gray(local.startedAt)}`);
106
+ if (local?.completedAt) logger.info(`Completed: ${pc.gray(local.completedAt)}`);
107
+ if (remote.summary) {
108
+ const totalDuration = remote.summary.totalDurationMs;
109
+ logger.info(`Duration: ${pc.gray(formatDuration(totalDuration))}`);
110
+ if (remote.summary.jobs.length > 0) {
111
+ logger.info(pc.bold("\nJobs:"));
112
+ const nameWidth = Math.max(10, ...remote.summary.jobs.map((j) => j.name.length)) + 2;
113
+ for (const job of remote.summary.jobs) {
114
+ const jobColor = job.status === "success" ? pc.green : job.status === "failed" ? pc.red : job.status === "cancelled" ? pc.yellow : pc.blue;
115
+ const duration = job.durationMs ? formatDuration(job.durationMs) : "-";
116
+ logger.info(` ${jobColor(job.status.padEnd(12))} ${job.name.padEnd(nameWidth)} ${pc.gray(duration)}`);
117
+ }
118
+ }
119
+ }
120
+ logger.info("");
121
+ }
122
+ /**
123
+ * Display a local-only history entry.
124
+ */
125
+ function displayLocalEntry(entry) {
126
+ const statusColor = entry.status === "success" ? pc.green : entry.status === "failed" ? pc.red : entry.status === "cancelled" ? pc.yellow : pc.blue;
127
+ logger.info(pc.bold(`\nRun: ${entry.runId}`));
128
+ logger.info(`Status: ${statusColor(entry.status)}`);
129
+ logger.info(`Fixture: ${pc.cyan(entry.fixtureId)}`);
130
+ logger.info(`Endpoint: ${pc.gray(entry.endpoint)}`);
131
+ logger.info(`Started: ${pc.gray(entry.startedAt)}`);
132
+ if (entry.completedAt) logger.info(`Completed: ${pc.gray(entry.completedAt)}`);
133
+ if (entry.durationMs) logger.info(`Duration: ${pc.gray(formatDuration(entry.durationMs))}`);
134
+ if (entry.jobs && entry.jobs.length > 0) {
135
+ logger.info(pc.bold("\nJobs:"));
136
+ for (const job of entry.jobs) {
137
+ const jobColor = job.status === "success" ? pc.green : job.status === "failed" ? pc.red : job.status === "cancelled" ? pc.yellow : pc.blue;
138
+ const duration = job.durationMs ? formatDuration(job.durationMs) : "-";
139
+ logger.info(` ${jobColor(job.status.padEnd(12))} ${job.name} ${pc.gray(duration)}`);
140
+ }
141
+ }
142
+ logger.info(pc.gray("\n(Local history only -- run may have updated on orchestrator)"));
143
+ logger.info("");
144
+ }
145
+ /**
146
+ * Stream logs for a run from the orchestrator.
147
+ *
148
+ * For active runs, connects via WebSocket for live streaming.
149
+ * For completed runs, fetches historical logs from storage.
150
+ */
151
+ async function displayLogs(client, token, runId, jobFilter) {
152
+ let logsResponse;
153
+ try {
154
+ logsResponse = await client.getRunLogs(runId, jobFilter);
155
+ } catch (error) {
156
+ if (error instanceof NotFoundError) {
157
+ const caps = await client.getCapabilities();
158
+ logger.error(formatCapabilityGapError({
159
+ feature: "log-streaming",
160
+ cliVersion: CLI_VERSION,
161
+ orchestratorVersion: caps.orchestratorVersion
162
+ }));
163
+ return false;
164
+ }
165
+ throw error;
166
+ }
167
+ if (logsResponse.observeUrl) {
168
+ logger.info(pc.bold(`\nStreaming live logs for run: ${runId}\n`));
169
+ return (await observeCompletion("status", runId, logsResponse.observeUrl, token, client, {})).status === "success";
170
+ }
171
+ logger.info(pc.bold(`\nLogs for run: ${runId}\n`));
172
+ if (!logsResponse.logs || logsResponse.logs.length === 0) {
173
+ logger.info(pc.gray("No logs available for this run."));
174
+ return true;
175
+ }
176
+ const formatter = new StreamingFormatter();
177
+ for (const entry of logsResponse.logs) for (const line of entry.lines) {
178
+ const output = formatter.formatLogLine(entry.jobName, entry.stepName, line);
179
+ if (output) process.stdout.write(output);
180
+ }
181
+ logger.info("");
182
+ return true;
183
+ }
184
+ /**
185
+ * Display authentication information section.
186
+ *
187
+ * Shows logged-in user, active org, and PAT expiry with warnings.
188
+ */
189
+ function displayAuthInfo(config) {
190
+ logger.info(pc.bold("\nAuth:"));
191
+ if (config.pat) {
192
+ const email = config.userEmail || "unknown";
193
+ logger.info(` Logged in as: ${pc.cyan(email)}`);
194
+ logger.info(` Active org: ${config.activeOrgId || pc.gray("none")}`);
195
+ if (config.patExpiresAt) {
196
+ const expiryDate = new Date(config.patExpiresAt);
197
+ const now = /* @__PURE__ */ new Date();
198
+ const daysRemaining = Math.ceil((expiryDate.getTime() - now.getTime()) / (1e3 * 60 * 60 * 24));
199
+ if (daysRemaining <= 0) logger.info(pc.red(` PAT expired. Run 'kici login' to re-authenticate.`));
200
+ else if (daysRemaining <= 7) logger.info(pc.yellow(` PAT expires in ${daysRemaining} day(s). Run 'kici login' to refresh.`));
201
+ else logger.info(` PAT expires: ${expiryDate.toLocaleDateString()} (${daysRemaining} days remaining)`);
202
+ }
203
+ } else if (config.token) logger.info(` Using API key authentication.`);
204
+ else logger.info(pc.gray(` Not authenticated. Run 'kici login' to get started.`));
205
+ logger.info("");
206
+ }
207
+ //#endregion
208
+ export { statusCommand };
209
+
210
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1,61 @@
1
+ import { type PayloadOptions } from '../test-runner/payload-builder.js';
2
+ /** Options for the kici test command (dry-run trigger preview) */
3
+ export interface TestOptions extends PayloadOptions {
4
+ /** Filter to specific workflow */
5
+ workflow?: string;
6
+ /** Filter to specific job */
7
+ job?: string;
8
+ /** Enable debug output */
9
+ debug?: boolean;
10
+ /** Path to .kici directory (defaults to .kici) */
11
+ kiciDir?: string;
12
+ /** Flat secret overrides: KEY=VALUE */
13
+ secret?: string[];
14
+ /** Context secret overrides: contextName.KEY=VALUE */
15
+ context?: string[];
16
+ }
17
+ /** Options for the kici run remote command */
18
+ export interface RemoteRunOptions extends TestOptions {
19
+ /** Run all available fixtures */
20
+ all?: boolean;
21
+ /** Run matching fixtures concurrently */
22
+ parallel?: boolean;
23
+ /** Fire and forget (print runIds, don't stream) */
24
+ wait?: boolean;
25
+ /** Suppress output except final result */
26
+ quiet?: boolean;
27
+ /** Output structured JSON result */
28
+ json?: boolean;
29
+ /** Output JUnit XML result */
30
+ junit?: string;
31
+ /** Override routing key for this run */
32
+ routingKey?: string;
33
+ /** Show recent run history */
34
+ history?: boolean;
35
+ }
36
+ /** Result of a single remote fixture run */
37
+ export interface RemoteRunResult {
38
+ fixtureId: string;
39
+ runId: string;
40
+ status: 'accepted' | 'rejected' | 'success' | 'failed' | 'cancelled' | 'error';
41
+ reason?: string;
42
+ observeUrl?: string;
43
+ durationMs?: number;
44
+ jobs?: Array<{
45
+ name: string;
46
+ status: string;
47
+ durationMs?: number;
48
+ }>;
49
+ }
50
+ /**
51
+ * Main test command entry point.
52
+ *
53
+ * `kici test <event>` is now dry-run trigger preview only.
54
+ * If the argument looks like a fixture name (not a known event type), prints a migration message.
55
+ */
56
+ export declare function testCommand(event: string | undefined, options: TestOptions): Promise<boolean>;
57
+ /**
58
+ * Local-only dry-run mode: compile workflows, match triggers, display what would execute.
59
+ */
60
+ export declare function testDryRun(event: string, options: TestOptions): Promise<boolean>;
61
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1,220 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { discoverWorkflows, resolveKiciDir } from "../execution/executor.js";
3
+ import "../execution/index.js";
4
+ import { transformTriggers } from "../lockfile/generator.js";
5
+ import { parseEventArg } from "../test-runner/event-types.js";
6
+ import { buildEventPayload } from "../test-runner/payload-builder.js";
7
+ import { displayDryRun } from "../test-runner/dry-run.js";
8
+ import { loadSecretsFile } from "../test-runner/secrets-file.js";
9
+ import pc from "picocolors";
10
+ import { readFile } from "node:fs/promises";
11
+ import path from "node:path";
12
+ import { logger, toErrorMessage } from "@kici-dev/shared";
13
+ import { matchAllWorkflows, normalizeRunsOn } from "@kici-dev/engine";
14
+ //#region src/commands/test.ts
15
+ /**
16
+ * Main test command entry point.
17
+ *
18
+ * `kici test <event>` is now dry-run trigger preview only.
19
+ * If the argument looks like a fixture name (not a known event type), prints a migration message.
20
+ */
21
+ async function testCommand(event, options) {
22
+ if (options.debug) {
23
+ process.env.KICI_DEBUG = "true";
24
+ logger.info(pc.gray("Debug mode enabled"));
25
+ }
26
+ try {
27
+ if (!event) {
28
+ logger.info(pc.bold("\nUsage: kici test <event>\n"));
29
+ logger.info(pc.gray("Preview which workflows and jobs would run for a given event.\n"));
30
+ logger.info(pc.gray("Examples:"));
31
+ logger.info(pc.gray(" kici test push"));
32
+ logger.info(pc.gray(" kici test pr:open"));
33
+ logger.info(pc.gray(" kici test schedule"));
34
+ logger.info(pc.gray(" kici test lifecycle:workflow_complete\n"));
35
+ logger.info(pc.gray("For remote fixture execution, use: kici run remote [fixture] [options]"));
36
+ logger.info(pc.gray("For local workflow execution, use: kici run local <event> [options]\n"));
37
+ return true;
38
+ }
39
+ if (!isKnownEventArg(event)) {
40
+ logger.info(pc.yellow(`\nFixture-based testing has moved to \`kici run remote\`.\nRun \`kici run remote ${event}\` instead.\n`));
41
+ return false;
42
+ }
43
+ return await testDryRun(event, options);
44
+ } catch (error) {
45
+ const message = toErrorMessage(error);
46
+ logger.error(pc.red(`\nError: ${message}\n`));
47
+ if (options.debug && error instanceof Error && error.stack) logger.error(pc.gray(error.stack));
48
+ return false;
49
+ }
50
+ }
51
+ /**
52
+ * Check if the argument is a known event type.
53
+ * Returns true if parseEventArg succeeds, false if it looks like a fixture name.
54
+ */
55
+ function isKnownEventArg(arg) {
56
+ try {
57
+ parseEventArg(arg);
58
+ return true;
59
+ } catch {
60
+ return arg.includes(":");
61
+ }
62
+ }
63
+ /**
64
+ * Local-only dry-run mode: compile workflows, match triggers, display what would execute.
65
+ */
66
+ async function testDryRun(event, options) {
67
+ try {
68
+ const kiciDir = resolveKiciDir(options.kiciDir);
69
+ logger.info(pc.gray(`KiCI directory: ${kiciDir}`));
70
+ await loadTestSecrets(kiciDir, options.secret, options.context);
71
+ logger.info(pc.gray(`Event: ${event}`));
72
+ const simulatedEvent = await buildEventPayload(event, options);
73
+ logger.info(pc.gray(`Target branch: ${simulatedEvent.targetBranch}`));
74
+ if (simulatedEvent.sourceBranch) logger.info(pc.gray(`Source branch: ${simulatedEvent.sourceBranch}`));
75
+ if (simulatedEvent.changedFiles && simulatedEvent.changedFiles.length > 0) logger.info(pc.gray(`Changed files: ${simulatedEvent.changedFiles.join(", ")}`));
76
+ const { workflows } = await loadWorkflows(kiciDir);
77
+ const lockWorkflows = workflowsToLockFormat(workflows);
78
+ const decisions = matchAllWorkflows(lockWorkflows, simulatedEvent);
79
+ const matchedWorkflows = workflows.filter((_, i) => decisions[i].matched);
80
+ logger.info(pc.gray(`Workflows: ${workflows.length} total, ${matchedWorkflows.length} matched\n`));
81
+ let filteredWorkflows = matchedWorkflows;
82
+ if (options.workflow) {
83
+ filteredWorkflows = matchedWorkflows.filter((w) => w.name === options.workflow);
84
+ if (filteredWorkflows.length === 0) {
85
+ logger.info(pc.yellow(`No workflow found matching: ${options.workflow}`));
86
+ return false;
87
+ }
88
+ }
89
+ displayDryRun(lockWorkflows, decisions, {
90
+ workflow: options.workflow,
91
+ job: options.job
92
+ });
93
+ return true;
94
+ } catch (error) {
95
+ const message = toErrorMessage(error);
96
+ logger.error(pc.red(`\nError: ${message}\n`));
97
+ if (options.debug && error instanceof Error && error.stack) logger.error(pc.gray(error.stack));
98
+ return false;
99
+ }
100
+ }
101
+ /**
102
+ * Load lock file if exists, otherwise discover workflows.
103
+ */
104
+ async function loadWorkflows(kiciDir) {
105
+ const lockFilePath = path.join(kiciDir, "kici.lock.json");
106
+ try {
107
+ const lockContent = await readFile(lockFilePath, "utf-8");
108
+ const lockFile = JSON.parse(lockContent);
109
+ logger.info(pc.gray(`Using lock file: ${lockFilePath}`));
110
+ return {
111
+ lockFile,
112
+ workflows: (await discoverWorkflows(kiciDir)).workflows.map((w) => w.workflow)
113
+ };
114
+ } catch {
115
+ logger.info(pc.gray(`Discovering workflows from ${kiciDir}/workflows/`));
116
+ return { workflows: (await discoverWorkflows(kiciDir)).workflows.map((w) => w.workflow) };
117
+ }
118
+ }
119
+ /**
120
+ * Convert SDK Workflow to lock-file-like structure for trigger matching.
121
+ */
122
+ function workflowsToLockFormat(workflows) {
123
+ return workflows.map((w) => ({
124
+ name: w.name,
125
+ contentHash: "",
126
+ compileSchemaVersion: 0,
127
+ triggers: transformTriggers(w.on),
128
+ jobs: w.jobs.map((j, i) => {
129
+ if (typeof j === "function") return {
130
+ _type: "dynamic",
131
+ source: {
132
+ file: "",
133
+ index: i
134
+ }
135
+ };
136
+ return {
137
+ _type: "static",
138
+ name: j.name,
139
+ runsOn: typeof j.runsOn === "string" || Array.isArray(j.runsOn) ? j.runsOn : (() => {
140
+ const n = normalizeRunsOn(j.runsOn);
141
+ return n.labels.length === 1 ? n.labels[0] : n.labels;
142
+ })(),
143
+ needs: j.needs?.map((n) => {
144
+ if (typeof n === "string") return n;
145
+ if ("name" in n) return n.name;
146
+ if ("group" in n) return `__group:${n.group}`;
147
+ return n.name;
148
+ }) ?? [],
149
+ steps: j.steps.map((s) => {
150
+ if (typeof s === "function") return {
151
+ name: "",
152
+ hasOutputs: false
153
+ };
154
+ return {
155
+ name: s.name,
156
+ hasOutputs: !!s.outputs
157
+ };
158
+ }),
159
+ rules: j.rules?.map((r, ri) => ({
160
+ _type: "dynamic",
161
+ label: r.label,
162
+ source: {
163
+ file: "",
164
+ index: ri
165
+ }
166
+ })),
167
+ matrix: j.matrix ? typeof j.matrix === "function" ? {
168
+ _type: "dynamic",
169
+ source: {
170
+ file: "",
171
+ jobName: j.name
172
+ }
173
+ } : {
174
+ _type: "static",
175
+ values: j.matrix
176
+ } : void 0,
177
+ description: j.description
178
+ };
179
+ }),
180
+ rules: w.rules?.map((r, i) => ({
181
+ _type: "dynamic",
182
+ label: r.label,
183
+ source: {
184
+ file: "",
185
+ index: i
186
+ }
187
+ })),
188
+ description: w.description
189
+ }));
190
+ }
191
+ /**
192
+ * Load test secrets from .kici/.secrets file and merge CLI overrides.
193
+ */
194
+ async function loadTestSecrets(kiciDir, secretFlags, contextFlags) {
195
+ const secrets = await loadSecretsFile(kiciDir);
196
+ if (secretFlags) for (const flag of secretFlags) {
197
+ const eqIndex = flag.indexOf("=");
198
+ if (eqIndex === -1) continue;
199
+ const key = flag.slice(0, eqIndex).trim();
200
+ const value = flag.slice(eqIndex + 1).trim();
201
+ secrets.flat[key] = value;
202
+ }
203
+ if (contextFlags) for (const flag of contextFlags) {
204
+ const dotIndex = flag.indexOf(".");
205
+ if (dotIndex === -1) continue;
206
+ const contextName = flag.slice(0, dotIndex).trim();
207
+ const rest = flag.slice(dotIndex + 1);
208
+ const eqIndex = rest.indexOf("=");
209
+ if (eqIndex === -1) continue;
210
+ const key = rest.slice(0, eqIndex).trim();
211
+ const value = rest.slice(eqIndex + 1).trim();
212
+ if (!secrets.contexts[contextName]) secrets.contexts[contextName] = {};
213
+ secrets.contexts[contextName][key] = value;
214
+ }
215
+ return secrets;
216
+ }
217
+ //#endregion
218
+ export { testCommand, testDryRun };
219
+
220
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1,18 @@
1
+ export interface TypesOptions {
2
+ /** Path to .kici directory (defaults to .kici) */
3
+ kiciDir?: string;
4
+ /** Orchestrator endpoint override (defaults to global config) */
5
+ endpoint?: string;
6
+ }
7
+ /**
8
+ * Generate TypeScript declarations for environment secrets.
9
+ *
10
+ * Fetches environment metadata from the orchestrator and generates
11
+ * .kici/types/secrets.d.ts with module augmentation for
12
+ * KnownSecretKeys and EnvironmentSecrets.
13
+ *
14
+ * @param options - Command options
15
+ * @returns true on success, false on error
16
+ */
17
+ export declare function typesCommand(options: TypesOptions): Promise<boolean>;
18
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,74 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { loadGlobalConfig } from "../remote/config.js";
3
+ import { generateSecretsDts } from "../generators/secrets-dts.js";
4
+ import pc from "picocolors";
5
+ import fs from "node:fs/promises";
6
+ import path from "node:path";
7
+ import { toErrorMessage } from "@kici-dev/shared";
8
+ //#region src/commands/types.ts
9
+ /**
10
+ * Generate TypeScript declarations for environment secrets.
11
+ *
12
+ * Fetches environment metadata from the orchestrator and generates
13
+ * .kici/types/secrets.d.ts with module augmentation for
14
+ * KnownSecretKeys and EnvironmentSecrets.
15
+ *
16
+ * @param options - Command options
17
+ * @returns true on success, false on error
18
+ */
19
+ async function typesCommand(options) {
20
+ try {
21
+ const config = await loadGlobalConfig();
22
+ if (!config.token) {
23
+ console.error(pc.red("Not authenticated. Run `kici login` first to connect to your orchestrator."));
24
+ return false;
25
+ }
26
+ const endpoint = options.endpoint ?? config.endpoint;
27
+ if (!endpoint) {
28
+ console.error(pc.red("No orchestrator endpoint configured. Run `kici login --endpoint <url>` first."));
29
+ return false;
30
+ }
31
+ if (!config.activeOrgId) {
32
+ console.error(pc.red("No active organization. Run `kici org list` then `kici org use <name>` first."));
33
+ return false;
34
+ }
35
+ const url = `${endpoint.replace(/\/+$/, "")}/api/v1/admin/environments?orgId=${encodeURIComponent(config.activeOrgId)}&includeSecrets=true`;
36
+ const res = await fetch(url, { headers: { Authorization: `Bearer ${config.token}` } });
37
+ if (res.status === 401) {
38
+ console.error(pc.red("Authentication failed. Check your API key with `kici login`."));
39
+ return false;
40
+ }
41
+ if (res.status === 403) {
42
+ console.error(pc.red("Permission denied. Your API key does not have environments.read access."));
43
+ return false;
44
+ }
45
+ if (!res.ok) {
46
+ const text = await res.text();
47
+ console.error(pc.red(`Failed to fetch environments: ${res.status} ${text}`));
48
+ return false;
49
+ }
50
+ const dtsContent = generateSecretsDts({
51
+ environments: ((await res.json()).environments ?? []).map((e) => ({
52
+ name: e.name,
53
+ keys: e.secret_keys ?? []
54
+ })),
55
+ endpoint: endpoint.replace(/\/+$/, ""),
56
+ generatedAt: /* @__PURE__ */ new Date()
57
+ });
58
+ const kiciDir = options.kiciDir ?? ".kici";
59
+ const typesDir = path.join(kiciDir, "types");
60
+ await fs.mkdir(typesDir, { recursive: true });
61
+ const outputPath = path.join(typesDir, "secrets.d.ts");
62
+ await fs.writeFile(outputPath, dtsContent, "utf-8");
63
+ console.log(pc.green("Types generated") + pc.dim(` ${outputPath}`));
64
+ return true;
65
+ } catch (err) {
66
+ const message = toErrorMessage(err);
67
+ console.error(pc.red(`Failed to generate types: ${message}`));
68
+ return false;
69
+ }
70
+ }
71
+ //#endregion
72
+ export { typesCommand };
73
+
74
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,14 @@
1
+ import { type CompileOptions } from './compile.js';
2
+ /**
3
+ * Run compiler in watch mode.
4
+ *
5
+ * Features:
6
+ * - Clears terminal on each recompile (like tsc --watch)
7
+ * - Debounces rapid file changes (200ms)
8
+ * - Graceful shutdown on SIGINT/SIGTERM
9
+ * - Prevents concurrent compilation
10
+ *
11
+ * @param options - Compile options (kiciDir, verbose flag)
12
+ */
13
+ export declare function watchCommand(options: Omit<CompileOptions, 'check'>): Promise<void>;
14
+ //# sourceMappingURL=watch.d.ts.map
@@ -0,0 +1,97 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { resolveKiciDir } from "../execution/executor.js";
3
+ import "../execution/index.js";
4
+ import { compileCommand } from "./compile.js";
5
+ import pc from "picocolors";
6
+ import path from "node:path";
7
+ import { logger, toErrorMessage } from "@kici-dev/shared";
8
+ import chokidar from "chokidar";
9
+ //#region src/commands/watch.ts
10
+ /** Debounce delay in milliseconds */
11
+ const DEBOUNCE_MS = 200;
12
+ /**
13
+ * Run compiler in watch mode.
14
+ *
15
+ * Features:
16
+ * - Clears terminal on each recompile (like tsc --watch)
17
+ * - Debounces rapid file changes (200ms)
18
+ * - Graceful shutdown on SIGINT/SIGTERM
19
+ * - Prevents concurrent compilation
20
+ *
21
+ * @param options - Compile options (kiciDir, verbose flag)
22
+ */
23
+ async function watchCommand(options) {
24
+ const kiciDir = resolveKiciDir(options.kiciDir);
25
+ const workflowDir = path.join(kiciDir, "workflows");
26
+ let debounceTimeout = null;
27
+ let isCompiling = false;
28
+ let pendingRecompile = false;
29
+ /**
30
+ * Run a compilation cycle.
31
+ * If called while already compiling, sets a flag to recompile after the
32
+ * current compilation finishes (prevents dropped file changes).
33
+ */
34
+ const compile = async (initial = false) => {
35
+ if (isCompiling) {
36
+ pendingRecompile = true;
37
+ return;
38
+ }
39
+ isCompiling = true;
40
+ pendingRecompile = false;
41
+ if (!initial) console.clear();
42
+ const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
43
+ logger.debug(pc.dim(`[${timestamp}] Compiling...`));
44
+ try {
45
+ if (await compileCommand({
46
+ kiciDir: options.kiciDir,
47
+ check: false,
48
+ verbose: options.verbose
49
+ })) logger.debug(pc.dim(`\n[${timestamp}] Watching for file changes...`));
50
+ else logger.debug(pc.dim(`\n[${timestamp}] Fix errors and save to recompile...`));
51
+ } catch (error) {
52
+ logger.error(pc.red("Unexpected error:"), toErrorMessage(error));
53
+ logger.debug(pc.dim(`\n[${timestamp}] Watching for file changes...`));
54
+ } finally {
55
+ isCompiling = false;
56
+ if (pendingRecompile) {
57
+ pendingRecompile = false;
58
+ compile();
59
+ }
60
+ }
61
+ };
62
+ await compile(true);
63
+ const watcher = chokidar.watch(path.join(workflowDir, "*.ts"), {
64
+ persistent: true,
65
+ awaitWriteFinish: {
66
+ stabilityThreshold: 100,
67
+ pollInterval: 50
68
+ },
69
+ ignoreInitial: true
70
+ });
71
+ const handleChange = () => {
72
+ if (debounceTimeout) clearTimeout(debounceTimeout);
73
+ debounceTimeout = setTimeout(() => {
74
+ compile();
75
+ }, DEBOUNCE_MS);
76
+ };
77
+ watcher.on("change", handleChange);
78
+ watcher.on("add", handleChange);
79
+ watcher.on("unlink", handleChange);
80
+ watcher.on("error", (error) => {
81
+ logger.error(pc.red("Watch error:"), toErrorMessage(error));
82
+ });
83
+ logger.debug(pc.dim(`\nWatching for file changes...`));
84
+ logger.debug(pc.dim(`Press Ctrl+C to stop.\n`));
85
+ const shutdown = async () => {
86
+ logger.debug(pc.dim("\nShutting down..."));
87
+ if (debounceTimeout) clearTimeout(debounceTimeout);
88
+ await watcher.close();
89
+ process.exit(0);
90
+ };
91
+ process.on("SIGINT", shutdown);
92
+ process.on("SIGTERM", shutdown);
93
+ }
94
+ //#endregion
95
+ export { watchCommand };
96
+
97
+ //# sourceMappingURL=watch.js.map