@kici-dev/compiler 0.1.26 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/dist/auth/headless-detect.d.ts +14 -5
  2. package/dist/auth/headless-detect.js +50 -9
  3. package/dist/cli-banner.d.ts +6 -3
  4. package/dist/cli-banner.js +13 -5
  5. package/dist/cli.js +180 -48
  6. package/dist/commands/check-mode.d.ts +1 -1
  7. package/dist/commands/compile.js +31 -7
  8. package/dist/commands/diagnostics.js +14 -2
  9. package/dist/commands/doctor.d.ts +64 -0
  10. package/dist/commands/doctor.js +413 -0
  11. package/dist/commands/endpoints.js +6 -0
  12. package/dist/commands/fixture.js +13 -0
  13. package/dist/commands/hook.js +3 -2
  14. package/dist/commands/index.d.ts +13 -1
  15. package/dist/commands/index.js +10 -3
  16. package/dist/commands/init-host-os.d.ts +34 -0
  17. package/dist/commands/init-host-os.js +44 -0
  18. package/dist/commands/init.d.ts +4 -0
  19. package/dist/commands/init.js +160 -37
  20. package/dist/commands/local-trust-root.d.ts +6 -0
  21. package/dist/commands/local-trust-root.js +52 -0
  22. package/dist/commands/local.d.ts +65 -0
  23. package/dist/commands/local.js +206 -0
  24. package/dist/commands/login.d.ts +2 -0
  25. package/dist/commands/login.js +41 -1
  26. package/dist/commands/logout.js +7 -0
  27. package/dist/commands/notifications.d.ts +61 -0
  28. package/dist/commands/notifications.js +274 -0
  29. package/dist/commands/preview.js +9 -2
  30. package/dist/commands/run-banner.d.ts +31 -0
  31. package/dist/commands/run-banner.js +25 -0
  32. package/dist/commands/run-routed.d.ts +53 -0
  33. package/dist/commands/run-routed.js +185 -0
  34. package/dist/commands/run.d.ts +0 -17
  35. package/dist/commands/run.js +44 -58
  36. package/dist/commands/runs/artifacts/download.d.ts +24 -0
  37. package/dist/commands/runs/artifacts/download.js +154 -0
  38. package/dist/commands/runs/artifacts/list.d.ts +5 -0
  39. package/dist/commands/runs/artifacts/list.js +47 -0
  40. package/dist/commands/runs/cancel.js +2 -2
  41. package/dist/commands/runs/list.js +8 -2
  42. package/dist/commands/secrets-list.d.ts +2 -2
  43. package/dist/commands/secrets-list.js +4 -4
  44. package/dist/commands/types.d.ts +3 -3
  45. package/dist/commands/types.js +4 -4
  46. package/dist/commands/verify-attestation.d.ts +3 -1
  47. package/dist/commands/verify-attestation.js +18 -7
  48. package/dist/errors/formatter.d.ts +14 -1
  49. package/dist/errors/formatter.js +13 -3
  50. package/dist/errors/index.d.ts +2 -1
  51. package/dist/errors/index.js +3 -2
  52. package/dist/errors/source-location.d.ts +20 -0
  53. package/dist/errors/source-location.js +45 -0
  54. package/dist/execution/executor.js +32 -12
  55. package/dist/fixtures/defaults/index.js +2 -1
  56. package/dist/generators/secrets-dts.d.ts +9 -9
  57. package/dist/generators/secrets-dts.js +12 -12
  58. package/dist/llm-context/llms-architecture.txt +50 -21
  59. package/dist/llm-context/llms-cli.txt +2667 -1454
  60. package/dist/llm-context/llms-features.txt +484 -414
  61. package/dist/llm-context/llms-full.txt +6703 -4687
  62. package/dist/llm-context/llms-getting-started.txt +311 -55
  63. package/dist/llm-context/llms-patterns.txt +17 -29
  64. package/dist/llm-context/llms-providers.txt +10 -1
  65. package/dist/llm-context/llms-sdk-runtime.txt +2013 -0
  66. package/dist/llm-context/llms-sdk.txt +596 -2157
  67. package/dist/llm-context/llms.txt +31 -17
  68. package/dist/local-plane/orchestrator-process.d.ts +70 -0
  69. package/dist/local-plane/orchestrator-process.js +129 -0
  70. package/dist/local-plane/os-mismatch-hint.d.ts +16 -0
  71. package/dist/local-plane/os-mismatch-hint.js +34 -0
  72. package/dist/local-plane/paths.d.ts +39 -0
  73. package/dist/local-plane/paths.js +54 -0
  74. package/dist/local-plane/plane-liveness.d.ts +68 -0
  75. package/dist/local-plane/plane-liveness.js +145 -0
  76. package/dist/local-plane/plane-manager.d.ts +193 -0
  77. package/dist/local-plane/plane-manager.js +480 -0
  78. package/dist/local-plane/plane-seed.d.ts +76 -0
  79. package/dist/local-plane/plane-seed.js +59 -0
  80. package/dist/local-plane/plane-trigger.d.ts +71 -0
  81. package/dist/local-plane/plane-trigger.js +110 -0
  82. package/dist/local-plane/platform-attach.d.ts +53 -0
  83. package/dist/local-plane/platform-attach.js +107 -0
  84. package/dist/local-plane/port-holder.d.ts +78 -0
  85. package/dist/local-plane/port-holder.js +227 -0
  86. package/dist/local-plane/postgres.d.ts +56 -0
  87. package/dist/local-plane/postgres.js +187 -0
  88. package/dist/local-plane/resolve-plane.d.ts +37 -0
  89. package/dist/local-plane/resolve-plane.js +76 -0
  90. package/dist/local-plane/run-follow.d.ts +61 -0
  91. package/dist/local-plane/run-follow.js +151 -0
  92. package/dist/local-plane/scaler-config.d.ts +68 -0
  93. package/dist/local-plane/scaler-config.js +132 -0
  94. package/dist/local-plane/secret-seed.d.ts +59 -0
  95. package/dist/local-plane/secret-seed.js +112 -0
  96. package/dist/local-plane/source-provider.d.ts +43 -0
  97. package/dist/local-plane/source-provider.js +159 -0
  98. package/dist/local-plane/trusted-routing.d.ts +32 -0
  99. package/dist/local-plane/trusted-routing.js +47 -0
  100. package/dist/lockfile/generator.d.ts +14 -1
  101. package/dist/lockfile/generator.js +103 -37
  102. package/dist/lockfile/index.d.ts +3 -1
  103. package/dist/lockfile/index.js +3 -2
  104. package/dist/lockfile/purity-diagnostics.d.ts +31 -0
  105. package/dist/lockfile/purity-diagnostics.js +52 -0
  106. package/dist/postinstall.js +2 -1
  107. package/dist/remote/artifact-extract.d.ts +8 -0
  108. package/dist/remote/artifact-extract.js +58 -0
  109. package/dist/remote/config.d.ts +21 -3
  110. package/dist/remote/config.js +24 -5
  111. package/dist/remote/dashboard-client.d.ts +46 -9
  112. package/dist/remote/dashboard-client.js +54 -11
  113. package/dist/remote/fs-case.d.ts +21 -0
  114. package/dist/remote/fs-case.js +45 -0
  115. package/dist/remote/history.d.ts +9 -3
  116. package/dist/remote/history.js +79 -10
  117. package/dist/remote/local-repo-identity.d.ts +1 -1
  118. package/dist/remote/local-repo-identity.js +2 -1
  119. package/dist/remote/notifications-client.d.ts +149 -0
  120. package/dist/remote/notifications-client.js +103 -0
  121. package/dist/remote/oauth.d.ts +13 -0
  122. package/dist/remote/oauth.js +31 -5
  123. package/dist/remote/output/summary.js +76 -14
  124. package/dist/remote/platform-client.d.ts +1 -1
  125. package/dist/remote/render.js +30 -9
  126. package/dist/{local-executor → remote}/secret-loader.d.ts +1 -1
  127. package/dist/{local-executor → remote}/secret-loader.js +4 -4
  128. package/dist/remote/secret-upload.d.ts +1 -1
  129. package/dist/remote/secret-upload.js +2 -2
  130. package/dist/remote/uploader.d.ts +1 -1
  131. package/dist/remote/uploader.js +7 -6
  132. package/dist/templates/agents-md.d.ts +1 -1
  133. package/dist/templates/agents-md.js +8 -8
  134. package/dist/templates/index.d.ts +1 -1
  135. package/dist/templates/index.js +2 -2
  136. package/dist/templates/package-json.d.ts +15 -0
  137. package/dist/templates/package-json.js +26 -5
  138. package/dist/test-runner/dry-run.d.ts +2 -1
  139. package/dist/test-runner/dry-run.js +18 -1
  140. package/dist/test-runner/event-types.d.ts +2 -0
  141. package/dist/test-runner/event-types.js +3 -0
  142. package/dist/test-runner/job-executor.d.ts +1 -0
  143. package/dist/test-runner/job-executor.js +82 -44
  144. package/dist/test-runner/output-formatter.d.ts +5 -2
  145. package/dist/test-runner/output-formatter.js +6 -4
  146. package/dist/test-runner/payload-builder.d.ts +7 -1
  147. package/dist/test-runner/payload-builder.js +11 -2
  148. package/dist/test-runner/rule-evaluator.d.ts +7 -3
  149. package/dist/test-runner/rule-evaluator.js +13 -12
  150. package/dist/{local-executor → test-runner}/runs-on-display.js +1 -1
  151. package/dist/test-runner/step-context.d.ts +23 -5
  152. package/dist/test-runner/step-context.js +29 -119
  153. package/dist/types.d.ts +26 -7
  154. package/dist/types.js +4 -2
  155. package/dist/validation/index.d.ts +2 -0
  156. package/dist/validation/index.js +2 -1
  157. package/dist/validation/typecheck.d.ts +28 -0
  158. package/dist/validation/typecheck.js +110 -0
  159. package/dist/validation/validator.d.ts +9 -4
  160. package/dist/validation/validator.js +38 -44
  161. package/package.json +13 -13
  162. package/sbom.spdx.json +9311 -1528
  163. package/dist/assets/api-TJJVHrjC.json +0 -118
  164. package/dist/assets/descriptor-BTtjzN9L.json +0 -1382
  165. package/dist/assets/package-BpQF9kR8.json +0 -74
  166. package/dist/assets/package-Ceo2h27X.json +0 -89
  167. package/dist/assets/source_context-D0atuL28.json +0 -20
  168. package/dist/assets/type-BFqO8SCZ.json +0 -202
  169. package/dist/commands/cancel.d.ts +0 -22
  170. package/dist/commands/detect-package-manager.d.ts +0 -42
  171. package/dist/commands/held-run-resolve.d.ts +0 -50
  172. package/dist/commands/status.d.ts +0 -34
  173. package/dist/commands/test.d.ts +0 -88
  174. package/dist/errors/codes.d.ts +0 -25
  175. package/dist/local-executor/dag-scheduler.d.ts +0 -44
  176. package/dist/local-executor/dag-scheduler.js +0 -183
  177. package/dist/local-executor/index.d.ts +0 -23
  178. package/dist/local-executor/index.js +0 -378
  179. package/dist/local-executor/job-runner.d.ts +0 -47
  180. package/dist/local-executor/job-runner.js +0 -411
  181. package/dist/local-executor/materializer.d.ts +0 -44
  182. package/dist/local-executor/materializer.js +0 -132
  183. package/dist/local-executor/output-streamer.d.ts +0 -31
  184. package/dist/local-executor/output-streamer.js +0 -168
  185. package/dist/local-executor/payload-generator.d.ts +0 -16
  186. package/dist/local-executor/payload-generator.js +0 -138
  187. package/dist/local-executor/picker.d.ts +0 -33
  188. package/dist/local-executor/picker.js +0 -109
  189. package/dist/local-executor/to-event-payload.d.ts +0 -16
  190. package/dist/local-executor/to-event-payload.js +0 -21
  191. package/dist/local-executor/types.d.ts +0 -93
  192. package/dist/local-executor/types.js +0 -2
  193. package/dist/local-executor/workflow-lock.d.ts +0 -82
  194. package/dist/local-executor/workflow-lock.js +0 -0
  195. package/dist/package-F7UXSDHW.json +0 -74
  196. package/dist/remote/client.d.ts +0 -210
  197. package/dist/remote/observer.d.ts +0 -81
  198. package/dist/test-runner/summary.d.ts +0 -7
  199. /package/dist/{local-executor → test-runner}/runs-on-display.d.ts +0 -0
@@ -0,0 +1,64 @@
1
+ import { type DiagnoseResponse, type DiagnoseResult } from '@kici-dev/core';
2
+ import { type DiagnosticsInfrastructureResponse } from '@kici-dev/engine';
3
+ import { type GlobalConfig } from '../remote/config.js';
4
+ import { type DashboardErrorKind } from '../remote/dashboard-client.js';
5
+ import { type LockFile } from '../types.js';
6
+ /** A doctor check result: a shared DiagnoseResult plus the exact fix command. */
7
+ export interface DoctorCheckResult extends DiagnoseResult {
8
+ nextCommand?: string;
9
+ }
10
+ /** A check body before the runner stamps its measured duration. */
11
+ export type DoctorCheckBody = Omit<DoctorCheckResult, 'durationMs'>;
12
+ /** The outcome of the single authenticated infrastructure probe. */
13
+ export type ProbeOutcome = {
14
+ ok: true;
15
+ infra: DiagnosticsInfrastructureResponse;
16
+ } | {
17
+ ok: false;
18
+ kind: DashboardErrorKind;
19
+ message: string;
20
+ };
21
+ /** Is a stored token + endpoint present (regardless of expiry)? */
22
+ export declare function hasCredentials(config: GlobalConfig): boolean;
23
+ /** Check 1: logged in with an unexpired token. */
24
+ export declare function checkLogin(config: GlobalConfig, now: number): DoctorCheckBody;
25
+ /** Check 2: an active organization is selected. */
26
+ export declare function checkActiveOrg(config: GlobalConfig): DoctorCheckBody;
27
+ /** Check 3: the Platform accepted the stored token (live-token probe). */
28
+ export declare function checkLiveToken(probe: ProbeOutcome | null): DoctorCheckBody;
29
+ /** Local + git state of the compiled lock file. */
30
+ export interface LockState {
31
+ exists: boolean;
32
+ fresh: boolean;
33
+ committed: boolean;
34
+ gitAvailable: boolean;
35
+ lock: LockFile | null;
36
+ }
37
+ /** Check 4: an orchestrator is connected for this org. */
38
+ export declare function checkOrchestrator(probe: ProbeOutcome | null): DoctorCheckBody;
39
+ /** Check 5: the lock file is present, fresh, and committed. */
40
+ export declare function checkLockFile(state: LockState): DoctorCheckBody;
41
+ /** Check 6: every workflow's runsOn labels are satisfiable by a connected agent or scaler. */
42
+ export declare function checkLabels(lock: LockFile | null, probe: ProbeOutcome | null): DoctorCheckBody;
43
+ export interface DoctorOptions {
44
+ json?: boolean;
45
+ kiciDir?: string;
46
+ }
47
+ /** Injectable seams so every path is unit-testable without real IO. */
48
+ export interface DoctorDeps {
49
+ loadConfig: () => Promise<GlobalConfig>;
50
+ probe: (config: GlobalConfig) => Promise<ProbeOutcome | null>;
51
+ gatherLockState: (kiciDir: string) => Promise<LockState>;
52
+ now: () => number;
53
+ }
54
+ /** Render the funnel as a status table with a trailing next-command hint per row. */
55
+ export declare function renderDoctorTable(response: DiagnoseResponse & {
56
+ checks: DoctorCheckResult[];
57
+ }): string;
58
+ /**
59
+ * Run the onboarding-funnel diagnostic and return the process exit code
60
+ * (0 all pass · 1 any warn · 2 any fail). The single infrastructure probe is
61
+ * timed and attributed to the token-live check; the local checks are instant.
62
+ */
63
+ export declare function doctorCommand(options?: DoctorOptions, deps?: DoctorDeps): Promise<number>;
64
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1,413 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import { resolveKiciDir } from "../execution/executor.js";
3
+ import "../execution/index.js";
4
+ import { isLockStaticJob } from "../types.js";
5
+ import { loadGlobalConfig } from "../remote/config.js";
6
+ import { DashboardClient, DashboardClientError } from "../remote/dashboard-client.js";
7
+ import path from "node:path";
8
+ import pc from "picocolors";
9
+ import fs from "node:fs/promises";
10
+ import { deriveDiagnoseOverall, diagnoseExitCode, toErrorMessage } from "@kici-dev/core";
11
+ import { matcherSatisfiedBy } from "@kici-dev/engine";
12
+ import { execFile } from "node:child_process";
13
+ import { promisify } from "node:util";
14
+ //#region src/commands/doctor.ts
15
+ /**
16
+ * kici doctor — walk the onboarding funnel and diagnose where a developer's
17
+ * setup breaks. Each check reports pass/warn/fail with the exact next command
18
+ * to run. Composed entirely from client-side state (the stored config, one
19
+ * authenticated infrastructure read, and local filesystem/git state) — no new
20
+ * Platform API is required.
21
+ */
22
+ const execFileAsync = promisify(execFile);
23
+ const SEVEN_DAYS_MS = 10080 * 60 * 1e3;
24
+ /** Is a stored token + endpoint present (regardless of expiry)? */
25
+ function hasCredentials(config) {
26
+ return Boolean((config.pat ?? config.token) && (config.platformEndpoint ?? config.endpoint));
27
+ }
28
+ /** Check 1: logged in with an unexpired token. */
29
+ function checkLogin(config, now) {
30
+ const name = "login";
31
+ const endpoint = config.platformEndpoint ?? config.endpoint;
32
+ if (!hasCredentials(config)) return {
33
+ name,
34
+ status: "fail",
35
+ message: "Not logged in (no stored credentials).",
36
+ nextCommand: "kici login"
37
+ };
38
+ if (config.patExpiresAt) {
39
+ const expiresAt = Date.parse(config.patExpiresAt);
40
+ if (!Number.isNaN(expiresAt)) {
41
+ if (expiresAt <= now) return {
42
+ name,
43
+ status: "fail",
44
+ message: "Access token has expired.",
45
+ nextCommand: "kici login"
46
+ };
47
+ if (expiresAt - now < SEVEN_DAYS_MS) return {
48
+ name,
49
+ status: "warn",
50
+ message: `Access token expires in ${Math.ceil((expiresAt - now) / (1440 * 60 * 1e3))} day(s).`,
51
+ nextCommand: "kici login"
52
+ };
53
+ }
54
+ }
55
+ return {
56
+ name,
57
+ status: "pass",
58
+ message: `Logged in to ${endpoint}.`
59
+ };
60
+ }
61
+ /** Check 2: an active organization is selected. */
62
+ function checkActiveOrg(config) {
63
+ const name = "active-org";
64
+ if (!config.activeOrgId) return {
65
+ name,
66
+ status: "fail",
67
+ message: "No active organization selected.",
68
+ nextCommand: "kici org use <name>"
69
+ };
70
+ return {
71
+ name,
72
+ status: "pass",
73
+ message: `Active organization: ${config.activeOrgId}.`
74
+ };
75
+ }
76
+ /** Check 3: the Platform accepted the stored token (live-token probe). */
77
+ function checkLiveToken(probe) {
78
+ const name = "token-live";
79
+ if (probe === null) return {
80
+ name,
81
+ status: "warn",
82
+ message: "Skipped: requires login and an active organization."
83
+ };
84
+ if (probe.ok) return {
85
+ name,
86
+ status: "pass",
87
+ message: "Platform accepted the access token."
88
+ };
89
+ if (probe.kind === "unauthorized" || probe.kind === "not_logged_in") return {
90
+ name,
91
+ status: "fail",
92
+ message: `Authentication failed: ${probe.message}`,
93
+ nextCommand: "kici login"
94
+ };
95
+ return {
96
+ name,
97
+ status: "warn",
98
+ message: `Could not verify token: ${probe.message}`
99
+ };
100
+ }
101
+ /** Check 4: an orchestrator is connected for this org. */
102
+ function checkOrchestrator(probe) {
103
+ const name = "orchestrator";
104
+ if (probe === null || !probe.ok) return {
105
+ name,
106
+ status: "warn",
107
+ message: "Skipped: Platform not reachable (see token-live)."
108
+ };
109
+ const orchestrators = probe.infra.orchestrators ?? [];
110
+ const connected = orchestrators.filter((o) => o.connected);
111
+ if (orchestrators.length === 0) return {
112
+ name,
113
+ status: "warn",
114
+ message: "No orchestrator has connected for this organization yet.",
115
+ nextCommand: "kici diagnostics"
116
+ };
117
+ if (connected.length === 0) return {
118
+ name,
119
+ status: "fail",
120
+ message: `${orchestrators.length} orchestrator(s) registered but none are currently connected.`,
121
+ nextCommand: "kici diagnostics"
122
+ };
123
+ return {
124
+ name,
125
+ status: "pass",
126
+ message: `${connected.length} orchestrator(s) connected.`
127
+ };
128
+ }
129
+ /** Check 5: the lock file is present, fresh, and committed. */
130
+ function checkLockFile(state) {
131
+ const name = "lock-file";
132
+ if (!state.exists) return {
133
+ name,
134
+ status: "fail",
135
+ message: "No compiled kici.lock.json found.",
136
+ nextCommand: "kici compile"
137
+ };
138
+ if (!state.fresh) return {
139
+ name,
140
+ status: "warn",
141
+ message: "Lock file is stale — workflow sources changed since the last compile.",
142
+ nextCommand: "kici compile"
143
+ };
144
+ if (state.gitAvailable && !state.committed) return {
145
+ name,
146
+ status: "warn",
147
+ message: "Lock file has uncommitted changes.",
148
+ nextCommand: "git add .kici/kici.lock.json && git commit"
149
+ };
150
+ return {
151
+ name,
152
+ status: "pass",
153
+ message: "Lock file present, fresh, and committed."
154
+ };
155
+ }
156
+ /**
157
+ * A label group satisfies a requirement only when it matches EVERY runsOn
158
+ * matcher AND matches NONE of the excludeLabels — the same authority the
159
+ * orchestrator's job queue applies (`runsOn.every` && `!exclude.some`).
160
+ */
161
+ function requirementSatisfiedBy(req, labels) {
162
+ return req.runsOn.every((m) => matcherSatisfiedBy(m, labels)) && !req.exclude.some((m) => matcherSatisfiedBy(m, labels));
163
+ }
164
+ function describeMatcher(m) {
165
+ return m.kind === "regex" ? `/${m.source}/${m.flags}` : m.value;
166
+ }
167
+ function describeRequirement(req) {
168
+ const base = req.runsOn.map(describeMatcher).join(" + ");
169
+ return req.exclude.length > 0 ? `${base} − ${req.exclude.map(describeMatcher).join(", ")}` : base;
170
+ }
171
+ /**
172
+ * Collect the label groups that can satisfy a runsOn set on their own: each
173
+ * connected agent's label set, and each scaler labelSet.
174
+ */
175
+ function availableLabelGroups(infra) {
176
+ const groups = [];
177
+ for (const o of infra.orchestrators) {
178
+ if (!o.connected) continue;
179
+ for (const a of o.agents ?? []) groups.push(new Set(a.labels ?? []));
180
+ for (const s of o.scalers ?? []) for (const set of s.labelSets ?? []) groups.push(new Set(set));
181
+ }
182
+ return groups;
183
+ }
184
+ /** Check 6: every workflow's runsOn labels are satisfiable by a connected agent or scaler. */
185
+ function checkLabels(lock, probe) {
186
+ const name = "labels";
187
+ if (!lock) return {
188
+ name,
189
+ status: "warn",
190
+ message: "Skipped: no compiled lock file to read labels from."
191
+ };
192
+ if (probe === null || !probe.ok) return {
193
+ name,
194
+ status: "warn",
195
+ message: "Skipped: Platform not reachable (see token-live)."
196
+ };
197
+ const required = [];
198
+ for (const wf of lock.workflows) for (const job of wf.jobs) {
199
+ if (!isLockStaticJob(job)) continue;
200
+ const runsOn = job.runsOn ?? [];
201
+ if (runsOn.length === 0) continue;
202
+ required.push({
203
+ runsOn,
204
+ exclude: job.excludeLabels ?? []
205
+ });
206
+ }
207
+ if (required.length === 0) return {
208
+ name,
209
+ status: "pass",
210
+ message: "No workflow label constraints to satisfy."
211
+ };
212
+ const groups = availableLabelGroups(probe.infra);
213
+ if (groups.length === 0) return {
214
+ name,
215
+ status: "warn",
216
+ message: "No connected agents or scalers to satisfy any workflow labels.",
217
+ nextCommand: "kici diagnostics"
218
+ };
219
+ const unsatisfied = /* @__PURE__ */ new Set();
220
+ for (const req of required) if (!groups.some((labels) => requirementSatisfiedBy(req, labels))) unsatisfied.add(describeRequirement(req));
221
+ if (unsatisfied.size > 0) return {
222
+ name,
223
+ status: "warn",
224
+ message: `No connected agent or scaler can satisfy: ${[...unsatisfied].join("; ")}.`,
225
+ details: { unsatisfied: [...unsatisfied] },
226
+ nextCommand: "kici diagnostics"
227
+ };
228
+ return {
229
+ name,
230
+ status: "pass",
231
+ message: "All workflow labels are satisfiable by connected capacity."
232
+ };
233
+ }
234
+ /** Newest mtime (ms) across every *.ts under the workflows directory, or 0. */
235
+ async function newestWorkflowMtime(workflowsDir) {
236
+ let newest = 0;
237
+ let entries;
238
+ try {
239
+ entries = await fs.readdir(workflowsDir);
240
+ } catch {
241
+ return 0;
242
+ }
243
+ for (const entry of entries) {
244
+ if (!entry.endsWith(".ts")) continue;
245
+ try {
246
+ const st = await fs.stat(path.join(workflowsDir, entry));
247
+ if (st.mtimeMs > newest) newest = st.mtimeMs;
248
+ } catch {}
249
+ }
250
+ return newest;
251
+ }
252
+ /** Is the working tree clean for the given path? gitAvailable=false when not a repo. */
253
+ async function gitCleanForPath(filePath) {
254
+ try {
255
+ const { stdout } = await execFileAsync("git", [
256
+ "status",
257
+ "--porcelain",
258
+ "--",
259
+ filePath
260
+ ], { cwd: path.dirname(filePath) });
261
+ return {
262
+ gitAvailable: true,
263
+ committed: stdout.trim() === ""
264
+ };
265
+ } catch {
266
+ return {
267
+ gitAvailable: false,
268
+ committed: false
269
+ };
270
+ }
271
+ }
272
+ /** Default gatherer: read the lock file, compute freshness by mtime, check git. */
273
+ async function defaultGatherLockState(kiciDir) {
274
+ const abs = resolveKiciDir(kiciDir);
275
+ const lockPath = path.join(abs, "kici.lock.json");
276
+ let lock = null;
277
+ let lockMtime = 0;
278
+ try {
279
+ lockMtime = (await fs.stat(lockPath)).mtimeMs;
280
+ lock = JSON.parse(await fs.readFile(lockPath, "utf-8"));
281
+ } catch {
282
+ return {
283
+ exists: false,
284
+ fresh: false,
285
+ committed: false,
286
+ gitAvailable: false,
287
+ lock: null
288
+ };
289
+ }
290
+ const newestSrc = await newestWorkflowMtime(path.join(abs, "workflows"));
291
+ const { gitAvailable, committed } = await gitCleanForPath(lockPath);
292
+ return {
293
+ exists: true,
294
+ fresh: lockMtime >= newestSrc,
295
+ committed,
296
+ gitAvailable,
297
+ lock
298
+ };
299
+ }
300
+ async function probeInfrastructure(client) {
301
+ try {
302
+ return {
303
+ ok: true,
304
+ infra: await client.getInfrastructure()
305
+ };
306
+ } catch (err) {
307
+ if (err instanceof DashboardClientError) return {
308
+ ok: false,
309
+ kind: err.kind,
310
+ message: err.message
311
+ };
312
+ return {
313
+ ok: false,
314
+ kind: "http",
315
+ message: toErrorMessage(err)
316
+ };
317
+ }
318
+ }
319
+ /** Default probe: attempt one authenticated infrastructure read, or null when not eligible. */
320
+ async function defaultProbe(config) {
321
+ if (!hasCredentials(config) || !config.activeOrgId) return null;
322
+ let client;
323
+ try {
324
+ client = DashboardClient.fromConfig(config);
325
+ } catch (err) {
326
+ if (err instanceof DashboardClientError) return {
327
+ ok: false,
328
+ kind: err.kind,
329
+ message: err.message
330
+ };
331
+ throw err;
332
+ }
333
+ return probeInfrastructure(client);
334
+ }
335
+ const defaultDeps = {
336
+ loadConfig: loadGlobalConfig,
337
+ probe: defaultProbe,
338
+ gatherLockState: defaultGatherLockState,
339
+ now: Date.now
340
+ };
341
+ function colorizeStatus(status) {
342
+ switch (status) {
343
+ case "pass":
344
+ case "healthy": return pc.green(status);
345
+ case "warn":
346
+ case "degraded": return pc.yellow(status);
347
+ case "fail":
348
+ case "unhealthy": return pc.red(status);
349
+ default: return status;
350
+ }
351
+ }
352
+ /** Render the funnel as a status table with a trailing next-command hint per row. */
353
+ function renderDoctorTable(response) {
354
+ const lines = [];
355
+ lines.push(`${pc.bold("kici doctor")} ${colorizeStatus(response.status)}`);
356
+ lines.push("");
357
+ for (const c of response.checks) {
358
+ lines.push(`${colorizeStatus(c.status.padEnd(4))} ${pc.bold(c.name.padEnd(14))} ${c.message}`);
359
+ if (c.nextCommand) lines.push(` ${pc.cyan(`→ ${c.nextCommand}`)}`);
360
+ }
361
+ return lines.join("\n");
362
+ }
363
+ /**
364
+ * Run the onboarding-funnel diagnostic and return the process exit code
365
+ * (0 all pass · 1 any warn · 2 any fail). The single infrastructure probe is
366
+ * timed and attributed to the token-live check; the local checks are instant.
367
+ */
368
+ async function doctorCommand(options = {}, deps = defaultDeps) {
369
+ const config = await deps.loadConfig();
370
+ const now = deps.now();
371
+ const lockState = await deps.gatherLockState(options.kiciDir ?? ".kici");
372
+ const probeStart = deps.now();
373
+ const probe = await deps.probe(config);
374
+ const probeMs = Math.max(0, deps.now() - probeStart);
375
+ const checks = [
376
+ {
377
+ ...checkLogin(config, now),
378
+ durationMs: 0
379
+ },
380
+ {
381
+ ...checkActiveOrg(config),
382
+ durationMs: 0
383
+ },
384
+ {
385
+ ...checkLockFile(lockState),
386
+ durationMs: 0
387
+ },
388
+ {
389
+ ...checkLiveToken(probe),
390
+ durationMs: probeMs
391
+ },
392
+ {
393
+ ...checkOrchestrator(probe),
394
+ durationMs: 0
395
+ },
396
+ {
397
+ ...checkLabels(lockState.lock, probe),
398
+ durationMs: 0
399
+ }
400
+ ];
401
+ const response = {
402
+ status: deriveDiagnoseOverall(checks),
403
+ checks,
404
+ timestamp: new Date(now).toISOString()
405
+ };
406
+ if (options.json) console.log(JSON.stringify(response, null, 2));
407
+ else console.log(renderDoctorTable(response));
408
+ return diagnoseExitCode(checks);
409
+ }
410
+ //#endregion
411
+ export { checkActiveOrg, checkLabels, checkLiveToken, checkLockFile, checkLogin, checkOrchestrator, doctorCommand, hasCredentials, renderDoctorTable };
412
+
413
+ //# sourceMappingURL=doctor.js.map
@@ -113,6 +113,12 @@ function categorizeTrigger(workflowName, trigger, groups) {
113
113
  eventName: `workflow_complete${trigger.name ? `:${trigger.name}` : ""}`
114
114
  });
115
115
  break;
116
+ case "workflows_failed_batch":
117
+ groups.kiciEvent.push({
118
+ workflowName,
119
+ eventName: `workflows_failed_batch${trigger.name ? `:${trigger.name}` : ""}`
120
+ });
121
+ break;
116
122
  case "job_complete":
117
123
  groups.kiciEvent.push({
118
124
  workflowName,
@@ -16,6 +16,7 @@ import { logger } from "@kici-dev/core";
16
16
  const INTERNAL_EVENT_TYPES = /* @__PURE__ */ new Set([
17
17
  "kici_event",
18
18
  "workflow_complete",
19
+ "workflows_failed_batch",
19
20
  "job_complete",
20
21
  "generic_webhook",
21
22
  "schedule",
@@ -45,6 +46,18 @@ function generateInternalFixture(eventType) {
45
46
  status: "status" in eventType ? eventType.status : "success",
46
47
  sourceRepo: "owner/repo"
47
48
  };
49
+ case "workflows_failed_batch": return {
50
+ total: 2,
51
+ runs: [{
52
+ runId: "run-1",
53
+ repo: "owner/repo",
54
+ workflowName: "ci"
55
+ }, {
56
+ runId: "run-2",
57
+ repo: "owner/repo",
58
+ workflowName: "deploy"
59
+ }]
60
+ };
48
61
  case "job_complete": return {
49
62
  workflowName: "workflowName" in eventType ? eventType.workflowName : "ci",
50
63
  jobName: "jobName" in eventType ? eventType.jobName : "build",
@@ -7,6 +7,7 @@ import pc from "picocolors";
7
7
  import { readFile } from "node:fs/promises";
8
8
  import { logger, toErrorMessage } from "@kici-dev/core";
9
9
  import { select } from "@inquirer/prompts";
10
+ import { isCiEnvironment } from "@kici-dev/core/ci-env";
10
11
  //#region src/commands/hook.ts
11
12
  /**
12
13
  * kici hook command
@@ -30,7 +31,7 @@ async function hookInstallCommand(options = {}) {
30
31
  if (options.git) selectedTool = "git";
31
32
  else {
32
33
  const tools = await detectHookTools();
33
- if (tools.length === 0) if (process.stdout.isTTY && process.env.CI !== "true") {
34
+ if (tools.length === 0) if (process.stdout.isTTY && !isCiEnvironment()) {
34
35
  const choice = await select({
35
36
  message: "No pre-commit tool detected. How would you like to install the hook?",
36
37
  choices: [{
@@ -53,7 +54,7 @@ async function hookInstallCommand(options = {}) {
53
54
  else if (tools.length === 1) {
54
55
  selectedTool = tools[0].name;
55
56
  logger.info(pc.gray(`Detected ${selectedTool}, installing hook...`));
56
- } else if (process.stdout.isTTY && process.env.CI !== "true") selectedTool = await select({
57
+ } else if (process.stdout.isTTY && !isCiEnvironment()) selectedTool = await select({
57
58
  message: "Multiple pre-commit tools detected. Which would you like to use?",
58
59
  choices: tools.map((t) => ({
59
60
  name: t.name,
@@ -5,7 +5,9 @@ export { fixtureCommand } from './fixture.js';
5
5
  export type { FixtureOptions } from './fixture.js';
6
6
  export { previewCommand, previewEvent } from './preview.js';
7
7
  export type { PreviewOptions, RemoteRunOptions, RemoteRunResult } from './preview.js';
8
- export { runLocalCommand, runRemoteCommand, printRunLocalUsage } from './run.js';
8
+ export { runRemoteCommand } from './run.js';
9
+ export { runRoutedCommand } from './run-routed.js';
10
+ export type { RunRoutedOptions } from './run-routed.js';
9
11
  export { initCommand } from './init.js';
10
12
  export type { InitOptions } from './init.js';
11
13
  export { hookInstallCommand } from './hook.js';
@@ -26,15 +28,23 @@ export { runsRerunCommand } from './runs/rerun.js';
26
28
  export type { RunsRerunOptions } from './runs/rerun.js';
27
29
  export { runsCancelCommand } from './runs/cancel.js';
28
30
  export type { RunsCancelOptions } from './runs/cancel.js';
31
+ export { runsArtifactsListCommand } from './runs/artifacts/list.js';
32
+ export type { RunsArtifactsListOptions } from './runs/artifacts/list.js';
33
+ export { runsArtifactsDownloadCommand } from './runs/artifacts/download.js';
34
+ export type { RunsArtifactsDownloadOptions } from './runs/artifacts/download.js';
29
35
  export { typesCommand } from './types.js';
30
36
  export type { TypesOptions } from './types.js';
31
37
  export { endpointsCommand } from './endpoints.js';
32
38
  export type { EndpointsOptions } from './endpoints.js';
33
39
  export { diagnosticsCommand } from './diagnostics.js';
34
40
  export type { DiagnosticsOptions } from './diagnostics.js';
41
+ export { doctorCommand } from './doctor.js';
42
+ export type { DoctorOptions } from './doctor.js';
35
43
  export { orgListCommand, orgUseCommand, orgCurrentCommand } from './org.js';
36
44
  export { orchestratorsListCommand, orchestratorsUseCommand } from './orchestrators.js';
37
45
  export type { OrchestratorsOptions } from './orchestrators.js';
46
+ export { localUpCommand, localStatusCommand, localDownCommand, localLogsCommand, localAttachCommand, localDetachCommand, } from './local.js';
47
+ export { localTrustRootCommand } from './local-trust-root.js';
38
48
  export { logoutCommand } from './logout.js';
39
49
  export { approveCommand } from './approve.js';
40
50
  export type { ApproveOptions } from './approve.js';
@@ -48,4 +58,6 @@ export { docsCommand, docsLlmCommand } from './docs.js';
48
58
  export type { DocsOptions, DocsLlmOptions } from './docs.js';
49
59
  export { verifyAttestationCommand } from './verify-attestation.js';
50
60
  export type { VerifyAttestationOptions } from './verify-attestation.js';
61
+ export { notificationsChannelsListCommand, notificationsChannelsAddCommand, notificationsChannelsRemoveCommand, notificationsSubscriptionsListCommand, notificationsSubscriptionsAddCommand, notificationsSubscriptionsRemoveCommand, notificationsRosterListCommand, notificationsRosterAddCommand, notificationsRosterRemoveCommand, } from './notifications.js';
62
+ export type { NotificationsCommonOptions, NotificationsListOptions, ChannelsAddOptions, SubscriptionsAddOptions, RosterAddOptions, } from './notifications.js';
51
63
  //# sourceMappingURL=index.d.ts.map
@@ -1,15 +1,17 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
- import { compileCommand } from "./compile.js";
3
2
  import { approveCommand } from "./approve.js";
3
+ import { compileCommand } from "./compile.js";
4
4
  import { diagnosticsCommand } from "./diagnostics.js";
5
5
  import { docsCommand, docsLlmCommand } from "./docs.js";
6
+ import { doctorCommand } from "./doctor.js";
6
7
  import { drainWorkerCommand } from "./drain-worker.js";
7
8
  import { endpointsCommand } from "./endpoints.js";
8
9
  import { fixtureCommand } from "./fixture.js";
9
10
  import { hookInstallCommand } from "./hook.js";
10
11
  import { watchCommand } from "./watch.js";
11
12
  import { previewCommand, previewEvent } from "./preview.js";
12
- import { printRunLocalUsage, runLocalCommand, runRemoteCommand } from "./run.js";
13
+ import { runRemoteCommand } from "./run.js";
14
+ import { runRoutedCommand } from "./run-routed.js";
13
15
  import { initCommand } from "./init.js";
14
16
  import { loginCommand } from "./login.js";
15
17
  import { secretsListCommand } from "./secrets-list.js";
@@ -19,11 +21,16 @@ import { runsShowCommand } from "./runs/show.js";
19
21
  import { runsLogsCommand } from "./runs/logs.js";
20
22
  import { runsRerunCommand } from "./runs/rerun.js";
21
23
  import { runsCancelCommand } from "./runs/cancel.js";
24
+ import { runsArtifactsListCommand } from "./runs/artifacts/list.js";
25
+ import { runsArtifactsDownloadCommand } from "./runs/artifacts/download.js";
22
26
  import { typesCommand } from "./types.js";
23
27
  import { orgCurrentCommand, orgListCommand, orgUseCommand } from "./org.js";
24
28
  import { orchestratorsListCommand, orchestratorsUseCommand } from "./orchestrators.js";
29
+ import { localAttachCommand, localDetachCommand, localDownCommand, localLogsCommand, localStatusCommand, localUpCommand } from "./local.js";
30
+ import { localTrustRootCommand } from "./local-trust-root.js";
25
31
  import { logoutCommand } from "./logout.js";
26
32
  import { rejectCommand } from "./reject.js";
27
33
  import { workflowsListCommand } from "./workflows.js";
28
34
  import { verifyAttestationCommand } from "./verify-attestation.js";
29
- export { approveCommand, compileCommand, diagnosticsCommand, docsCommand, docsLlmCommand, drainWorkerCommand, endpointsCommand, fixtureCommand, hookInstallCommand, initCommand, loginCommand, logoutCommand, orchestratorsListCommand, orchestratorsUseCommand, orgCurrentCommand, orgListCommand, orgUseCommand, patCreateCommand, previewCommand, previewEvent, printRunLocalUsage, rejectCommand, runLocalCommand, runRemoteCommand, runsCancelCommand, runsListCommand, runsLogsCommand, runsRerunCommand, runsShowCommand, secretsListCommand, typesCommand, verifyAttestationCommand, watchCommand, workflowsListCommand };
35
+ import { notificationsChannelsAddCommand, notificationsChannelsListCommand, notificationsChannelsRemoveCommand, notificationsRosterAddCommand, notificationsRosterListCommand, notificationsRosterRemoveCommand, notificationsSubscriptionsAddCommand, notificationsSubscriptionsListCommand, notificationsSubscriptionsRemoveCommand } from "./notifications.js";
36
+ export { approveCommand, compileCommand, diagnosticsCommand, docsCommand, docsLlmCommand, doctorCommand, drainWorkerCommand, endpointsCommand, fixtureCommand, hookInstallCommand, initCommand, localAttachCommand, localDetachCommand, localDownCommand, localLogsCommand, localStatusCommand, localTrustRootCommand, localUpCommand, loginCommand, logoutCommand, notificationsChannelsAddCommand, notificationsChannelsListCommand, notificationsChannelsRemoveCommand, notificationsRosterAddCommand, notificationsRosterListCommand, notificationsRosterRemoveCommand, notificationsSubscriptionsAddCommand, notificationsSubscriptionsListCommand, notificationsSubscriptionsRemoveCommand, orchestratorsListCommand, orchestratorsUseCommand, orgCurrentCommand, orgListCommand, orgUseCommand, patCreateCommand, previewCommand, previewEvent, rejectCommand, runRemoteCommand, runRoutedCommand, runsArtifactsDownloadCommand, runsArtifactsListCommand, runsCancelCommand, runsListCommand, runsLogsCommand, runsRerunCommand, runsShowCommand, secretsListCommand, typesCommand, verifyAttestationCommand, watchCommand, workflowsListCommand };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Host-OS helpers for `kici init`.
3
+ *
4
+ * The starter templates target `kici:os:linux`. On a macOS or Windows host that
5
+ * label matches no local dev-plane agent, so the first `kici run push --local`
6
+ * dispatches nothing. These helpers rewrite the scaffolded `runsOn` to the
7
+ * host's own `kici:os:*` label so the first run lands, mirroring how `kici init`
8
+ * already rewrites the default branch.
9
+ */
10
+ /**
11
+ * The primary `kici:os:*` label the host reports (linux→kici:os:linux,
12
+ * darwin→kici:os:macos, win32→kici:os:windows). Derived from the engine's
13
+ * canonical mapping — the same derivation the local dev-plane routing uses — so
14
+ * the value is never hand-spelled here and always matches what the plane can
15
+ * satisfy.
16
+ */
17
+ export declare function primaryHostOsLabel(platform: string, arch: string): string;
18
+ /**
19
+ * Rewrite a template's `'kici:os:linux'` runsOn to the host's primary OS label.
20
+ * A no-op on a Linux host (the templates already target it).
21
+ */
22
+ export declare function rewriteRunsOnForHost(content: string, platform: string, arch: string): string;
23
+ /**
24
+ * Whether to offer the post-init `Run it now?` prompt: interactive (TTY, not CI)
25
+ * and with dependencies installed (not `--mjs`, not `--skip-install`), so the
26
+ * offered `kici run push --local` can compile the workflow it just scaffolded.
27
+ */
28
+ export declare function shouldOfferFirstRun(env: {
29
+ isTTY: boolean;
30
+ ci: boolean;
31
+ mjs: boolean;
32
+ skipInstall: boolean;
33
+ }): boolean;
34
+ //# sourceMappingURL=init-host-os.d.ts.map