@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,44 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import { deriveOsArchLabels } from "@kici-dev/engine";
3
+ //#region src/commands/init-host-os.ts
4
+ /**
5
+ * Host-OS helpers for `kici init`.
6
+ *
7
+ * The starter templates target `kici:os:linux`. On a macOS or Windows host that
8
+ * label matches no local dev-plane agent, so the first `kici run push --local`
9
+ * dispatches nothing. These helpers rewrite the scaffolded `runsOn` to the
10
+ * host's own `kici:os:*` label so the first run lands, mirroring how `kici init`
11
+ * already rewrites the default branch.
12
+ */
13
+ const OS_LABEL_PREFIX = "kici:os:";
14
+ /**
15
+ * The primary `kici:os:*` label the host reports (linux→kici:os:linux,
16
+ * darwin→kici:os:macos, win32→kici:os:windows). Derived from the engine's
17
+ * canonical mapping — the same derivation the local dev-plane routing uses — so
18
+ * the value is never hand-spelled here and always matches what the plane can
19
+ * satisfy.
20
+ */
21
+ function primaryHostOsLabel(platform, arch) {
22
+ return deriveOsArchLabels(platform, arch).find((l) => l.startsWith(OS_LABEL_PREFIX)) ?? `${OS_LABEL_PREFIX}${platform}`;
23
+ }
24
+ /**
25
+ * Rewrite a template's `'kici:os:linux'` runsOn to the host's primary OS label.
26
+ * A no-op on a Linux host (the templates already target it).
27
+ */
28
+ function rewriteRunsOnForHost(content, platform, arch) {
29
+ const hostLabel = primaryHostOsLabel(platform, arch);
30
+ if (hostLabel === "kici:os:linux") return content;
31
+ return content.replaceAll(`'kici:os:linux'`, `'${hostLabel}'`);
32
+ }
33
+ /**
34
+ * Whether to offer the post-init `Run it now?` prompt: interactive (TTY, not CI)
35
+ * and with dependencies installed (not `--mjs`, not `--skip-install`), so the
36
+ * offered `kici run push --local` can compile the workflow it just scaffolded.
37
+ */
38
+ function shouldOfferFirstRun(env) {
39
+ return env.isTTY && !env.ci && !env.mjs && !env.skipInstall;
40
+ }
41
+ //#endregion
42
+ export { primaryHostOsLabel, rewriteRunsOnForHost, shouldOfferFirstRun };
43
+
44
+ //# sourceMappingURL=init-host-os.js.map
@@ -29,6 +29,10 @@ export interface InitOptions {
29
29
  privateRegistrySecret?: string;
30
30
  /** Skip writing the .kici/AGENTS.md LLM-authoring context file. Default: write it. */
31
31
  noAgentsMd?: boolean;
32
+ /** Force integrate mode: join .kici/ to the detected workspace (skip the prompt). */
33
+ workspace?: boolean;
34
+ /** Force standalone mode even inside a workspace (skip the prompt). */
35
+ standalone?: boolean;
32
36
  }
33
37
  /**
34
38
  * Initialize .kici/ directory with workflow templates
@@ -1,19 +1,22 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
2
  import { agentsMdTemplate } from "../templates/agents-md.js";
3
3
  import { tsconfigTemplate } from "../templates/tsconfig-json.js";
4
- import { generatePackageJson } from "../templates/package-json.js";
4
+ import { generatePackageJson, sdkDependencyRange } from "../templates/package-json.js";
5
5
  import { workflowPaths } from "../templates/index.js";
6
6
  import { detectHookTools, findGitDir } from "../hooks/detector.js";
7
7
  import { installHook } from "../hooks/installer.js";
8
8
  import "../hooks/index.js";
9
9
  import { getTypeScriptPaths } from "../execution/sdk-alias.js";
10
+ import { rewriteRunsOnForHost, shouldOfferFirstRun } from "./init-host-os.js";
10
11
  import path from "node:path";
11
12
  import pc from "picocolors";
12
13
  import { access, mkdir, readFile, rm, writeFile } from "node:fs/promises";
14
+ import { $ } from "zx";
13
15
  import { initZx, logger, toErrorMessage } from "@kici-dev/core";
14
- import { detectPackageManager, installBuildPolicyArgs, installCommand, parsePackageManager } from "@kici-dev/core/package-manager";
16
+ import { detectPackageManager, detectWorkspaceRoot, installBuildPolicyArgs, installCommand, parsePackageManager } from "@kici-dev/core/package-manager";
15
17
  import { checkbox, confirm, select } from "@inquirer/prompts";
16
- import { $ } from "zx";
18
+ import { isCiEnvironment } from "@kici-dev/core/ci-env";
19
+ import os from "node:os";
17
20
  //#region src/commands/init.ts
18
21
  /**
19
22
  * kici init command
@@ -59,6 +62,7 @@ async function initCommand(options = {}) {
59
62
  content = content.replaceAll("targeting('main')", `targeting('${defaultBranch}')`);
60
63
  content = content.replaceAll("targeting the main branch", `targeting the ${defaultBranch} branch`);
61
64
  }
65
+ content = rewriteRunsOnForHost(content, os.platform(), os.arch());
62
66
  await writeFile(path.join(kiciDir, "workflows", `${workflow}.ts`), content, "utf-8");
63
67
  }
64
68
  logger.info(pc.gray("Creating .kici/tests/"));
@@ -73,34 +77,12 @@ async function initCommand(options = {}) {
73
77
  await writeFile(kiciIgnorePath, kiciIgnoreTemplate, "utf-8");
74
78
  }
75
79
  const devMode = options.useVerdaccioLocal || await detectDevelopmentMode();
76
- logger.info(pc.gray("Writing .kici/package.json"));
77
- const pkgContent = generatePackageJson(devMode);
78
- await writeFile(path.join(kiciDir, "package.json"), pkgContent, "utf-8");
80
+ const mode = await resolveScaffoldMode(options);
79
81
  const useVerdaccio = devMode;
80
- if (useVerdaccio) {
81
- logger.info(pc.yellow("Pointing @kici-dev to local Verdaccio registry."));
82
- const npmrc = "@kici-dev:registry=http://verdaccio.local:4873\n";
83
- await writeFile(path.join(kiciDir, ".npmrc"), npmrc, "utf-8");
84
- const rootNpmrc = path.resolve(".npmrc");
85
- if (!await checkExists(rootNpmrc)) {
86
- logger.info(pc.gray("Writing .npmrc (Verdaccio scope)"));
87
- await writeFile(rootNpmrc, npmrc, "utf-8");
88
- }
89
- }
90
- if (!options.mjs) {
91
- logger.info(pc.gray("Writing .kici/tsconfig.json"));
92
- const tsconfigContent = await generateTsConfig();
93
- await writeFile(path.join(kiciDir, "tsconfig.json"), tsconfigContent, "utf-8");
94
- await mkdir(path.join(kiciDir, "types"), { recursive: true });
95
- logger.info(pc.gray("Created .kici/types/ for generated type declarations"));
96
- if (!options.skipInstall) {
97
- const pm = await resolvePackageManager(options.packageManager);
98
- const [bin, action] = installCommand(pm);
99
- const buildPolicyArgs = installBuildPolicyArgs(pm);
100
- logger.info(pc.gray(`Running ${bin} ${action}...`));
101
- await $`cd ${kiciDir} && ${bin} ${action} ${buildPolicyArgs}`;
102
- }
103
- }
82
+ if (mode.kind === "integrate") {
83
+ logger.info(pc.cyan(`Integrating .kici/ into the ${mode.workspaceKind} workspace at ${mode.workspaceRoot}`));
84
+ await wireIntegrateDeps(kiciDir, mode.workspaceRoot, devMode, options);
85
+ } else await wireStandaloneDeps(kiciDir, devMode, options);
104
86
  if (options.privateRegistry) await writePrivateRegistryScaffold(kiciDir, {
105
87
  url: options.privateRegistry,
106
88
  scope: options.privateRegistryScope,
@@ -109,13 +91,17 @@ async function initCommand(options = {}) {
109
91
  if (await shouldWriteAgentsMd(options)) await writeAgentsMd(kiciDir);
110
92
  logger.info(pc.gray("Updating .gitignore"));
111
93
  await updateGitignore(useVerdaccio);
112
- if (process.stdout.isTTY && process.env.CI !== "true") {
94
+ if (process.stdout.isTTY && !isCiEnvironment()) {
113
95
  if (await findGitDir()) await offerHookInstallation(useVerdaccio);
114
96
  }
115
97
  logger.info(pc.green("\n✓ kici initialized successfully!\n"));
116
98
  logger.info(pc.gray("Next steps:"));
117
99
  logger.info(pc.gray(" 1. Edit workflows in .kici/workflows/"));
118
- if (options.mjs || options.skipInstall) {
100
+ if (mode.kind === "integrate") {
101
+ logger.info(pc.gray(" 2. Import your workspace packages from .kici/workflows/ (e.g. @your-scope/utils)"));
102
+ logger.info(pc.gray(" 3. Compile: kici compile"));
103
+ logger.info(pc.gray(" 4. Commit .kici/ to your repository\n"));
104
+ } else if (options.mjs || options.skipInstall) {
119
105
  logger.info(pc.gray(" 2. Run your package manager install in .kici/ to generate a lockfile"));
120
106
  logger.info(pc.gray(" 3. Preview matching: kici preview push"));
121
107
  logger.info(pc.gray(" 4. Commit .kici/ to your repository\n"));
@@ -123,6 +109,23 @@ async function initCommand(options = {}) {
123
109
  logger.info(pc.gray(" 2. Preview matching: kici preview push"));
124
110
  logger.info(pc.gray(" 3. Commit .kici/ to your repository\n"));
125
111
  }
112
+ if (shouldOfferFirstRun({
113
+ isTTY: Boolean(process.stdout.isTTY),
114
+ ci: isCiEnvironment(),
115
+ mjs: Boolean(options.mjs),
116
+ skipInstall: Boolean(options.skipInstall)
117
+ })) {
118
+ if (await confirm({
119
+ message: "Run it now? (kici run push --local)",
120
+ default: false
121
+ })) {
122
+ const { runRoutedCommand } = await import("./run-routed.js");
123
+ await runRoutedCommand({
124
+ event: "push",
125
+ local: true
126
+ });
127
+ }
128
+ }
126
129
  return true;
127
130
  } catch (error) {
128
131
  const message = toErrorMessage(error);
@@ -153,7 +156,7 @@ async function checkExists(targetPath) {
153
156
  * @returns Array of workflow names to include
154
157
  */
155
158
  async function selectWorkflows() {
156
- if (!process.stdout.isTTY || process.env.CI === "true") return ["hello-world", "pr-checks"];
159
+ if (!process.stdout.isTTY || isCiEnvironment()) return ["hello-world", "pr-checks"];
157
160
  const selected = await checkbox({
158
161
  message: "Which workflows would you like to include?",
159
162
  choices: [{
@@ -217,13 +220,133 @@ async function detectDevelopmentMode() {
217
220
  *
218
221
  * @param override - The raw `--package-manager` flag value, if provided.
219
222
  */
220
- async function resolvePackageManager(override) {
223
+ async function resolvePackageManager(override, dir = process.cwd()) {
221
224
  if (override) {
222
225
  const parsed = parsePackageManager(override);
223
226
  if (!parsed) throw new Error(`Invalid --package-manager value '${override}'. Expected one of: npm, pnpm, yarn.`);
224
227
  return parsed;
225
228
  }
226
- return detectPackageManager(process.cwd());
229
+ return detectPackageManager(dir);
230
+ }
231
+ /** The @kici-dev scope → local Verdaccio registry line written in dev mode. */
232
+ const VERDACCIO_NPMRC = "@kici-dev:registry=http://verdaccio.local:4873\n";
233
+ /** Write .kici/tsconfig.json + the empty types/ dir (TypeScript mode only). */
234
+ async function writeTsConfigAndTypesDir(kiciDir) {
235
+ logger.info(pc.gray("Writing .kici/tsconfig.json"));
236
+ await writeFile(path.join(kiciDir, "tsconfig.json"), await generateTsConfig(), "utf-8");
237
+ await mkdir(path.join(kiciDir, "types"), { recursive: true });
238
+ logger.info(pc.gray("Created .kici/types/ for generated type declarations"));
239
+ }
240
+ /** Run the given package manager's install in `dir`, with pnpm's build-gate flag. */
241
+ async function runInstall(pm, dir) {
242
+ const [bin, action] = installCommand(pm);
243
+ const buildPolicyArgs = installBuildPolicyArgs(pm);
244
+ logger.info(pc.gray(`Running ${bin} ${action}...`));
245
+ await $`cd ${dir} && ${bin} ${action} ${buildPolicyArgs}`;
246
+ }
247
+ /**
248
+ * Standalone dep wiring: write .kici/package.json (+ .kici/.npmrc and root
249
+ * .npmrc in dev mode), then tsconfig + isolated install in TypeScript mode.
250
+ */
251
+ async function wireStandaloneDeps(kiciDir, devMode, options) {
252
+ logger.info(pc.gray("Writing .kici/package.json"));
253
+ await writeFile(path.join(kiciDir, "package.json"), generatePackageJson(devMode), "utf-8");
254
+ if (devMode) {
255
+ logger.info(pc.yellow("Pointing @kici-dev to local Verdaccio registry."));
256
+ await writeFile(path.join(kiciDir, ".npmrc"), VERDACCIO_NPMRC, "utf-8");
257
+ const rootNpmrc = path.resolve(".npmrc");
258
+ if (!await checkExists(rootNpmrc)) {
259
+ logger.info(pc.gray("Writing .npmrc (Verdaccio scope)"));
260
+ await writeFile(rootNpmrc, VERDACCIO_NPMRC, "utf-8");
261
+ }
262
+ }
263
+ if (!options.mjs) {
264
+ await writeTsConfigAndTypesDir(kiciDir);
265
+ if (!options.skipInstall) await runInstall(await resolvePackageManager(options.packageManager), kiciDir);
266
+ }
267
+ }
268
+ /**
269
+ * Integrate dep wiring: NO .kici/package.json (its absence is the
270
+ * externally-managed signal the compiler honors). Add @kici-dev/sdk to the
271
+ * workspace-root manifest, write a root .npmrc in dev mode, write .kici/tsconfig
272
+ * in TypeScript mode, and run a root install.
273
+ */
274
+ async function wireIntegrateDeps(kiciDir, workspaceRoot, devMode, options) {
275
+ await addSdkToRootManifest(workspaceRoot, devMode);
276
+ if (devMode) {
277
+ const rootNpmrc = path.join(workspaceRoot, ".npmrc");
278
+ if (!await checkExists(rootNpmrc)) {
279
+ logger.info(pc.gray("Writing workspace-root .npmrc (Verdaccio scope)"));
280
+ await writeFile(rootNpmrc, VERDACCIO_NPMRC, "utf-8");
281
+ }
282
+ }
283
+ if (!options.mjs) await writeTsConfigAndTypesDir(kiciDir);
284
+ if (!options.skipInstall) await runInstall(await resolvePackageManager(options.packageManager, workspaceRoot), workspaceRoot);
285
+ }
286
+ /**
287
+ * Add @kici-dev/sdk to the workspace-root package.json devDependencies.
288
+ * Never clobbers an existing @kici-dev/sdk declaration (dev or prod dep).
289
+ */
290
+ async function addSdkToRootManifest(workspaceRoot, devMode) {
291
+ const manifestPath = path.join(workspaceRoot, "package.json");
292
+ let raw;
293
+ try {
294
+ raw = await readFile(manifestPath, "utf-8");
295
+ } catch {
296
+ throw new Error(`Cannot integrate: no package.json at workspace root ${workspaceRoot}`);
297
+ }
298
+ const pkg = JSON.parse(raw);
299
+ const existing = pkg.devDependencies?.["@kici-dev/sdk"] ?? pkg.dependencies?.["@kici-dev/sdk"];
300
+ if (existing) {
301
+ logger.info(pc.gray(`@kici-dev/sdk already declared in ${manifestPath} (${existing}) — leaving as-is`));
302
+ return;
303
+ }
304
+ const range = sdkDependencyRange(devMode);
305
+ pkg.devDependencies = {
306
+ ...pkg.devDependencies ?? {},
307
+ "@kici-dev/sdk": range
308
+ };
309
+ await writeFile(manifestPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
310
+ logger.info(pc.gray(`Added @kici-dev/sdk (${range}) to ${manifestPath}`));
311
+ }
312
+ /**
313
+ * Decide standalone vs integrate. Flags win; otherwise, when a workspace is
314
+ * detected, prompt in interactive mode and default to standalone in CI/non-TTY.
315
+ * With no workspace and no --workspace, always standalone (unchanged behavior).
316
+ */
317
+ async function resolveScaffoldMode(options) {
318
+ if (options.workspace && options.standalone) throw new Error("Cannot combine --workspace and --standalone.");
319
+ if (options.standalone) return { kind: "standalone" };
320
+ const ws = await detectWorkspaceRoot(process.cwd());
321
+ if (options.workspace) {
322
+ if (!ws) throw new Error("Cannot integrate: no pnpm/npm/yarn workspace found at or above the current directory. Run from a workspace root, or omit --workspace for a standalone .kici/.");
323
+ return {
324
+ kind: "integrate",
325
+ workspaceRoot: ws.root,
326
+ workspaceKind: ws.kind
327
+ };
328
+ }
329
+ if (!ws) return { kind: "standalone" };
330
+ if (!process.stdout.isTTY || isCiEnvironment()) return { kind: "standalone" };
331
+ return await promptScaffoldMode(ws.kind) === "integrate" ? {
332
+ kind: "integrate",
333
+ workspaceRoot: ws.root,
334
+ workspaceKind: ws.kind
335
+ } : { kind: "standalone" };
336
+ }
337
+ /** Interactive standalone-vs-integrate select. Defaults to standalone. */
338
+ async function promptScaffoldMode(kind) {
339
+ return await select({
340
+ message: `A ${kind} workspace was detected. How should the workflows be set up?`,
341
+ choices: [{
342
+ name: "Standalone — self-contained .kici/ with its own package.json",
343
+ value: "standalone"
344
+ }, {
345
+ name: "Integrate — join the workspace; workflows can import your other packages",
346
+ value: "integrate"
347
+ }],
348
+ default: "standalone"
349
+ });
227
350
  }
228
351
  /**
229
352
  * Generate tsconfig.json content with optional TypeScript path mappings.
@@ -280,7 +403,7 @@ async function writePrivateRegistryScaffold(kiciDir, args) {
280
403
  //
281
404
  // The agent renders these into the .kici/.npmrc before running \`npm install\`.
282
405
  // The token is resolved from the qualified secret reference at dispatch time
283
- // (the orchestrator looks it up under the named environment's scoped secrets).
406
+ // (the orchestrator looks it up under the named context's scoped secrets).
284
407
  import { workflow, job, step } from '@kici-dev/sdk';
285
408
 
286
409
  export default workflow('private-registry-example', {
@@ -355,7 +478,7 @@ coverage/
355
478
  */
356
479
  async function shouldWriteAgentsMd(options) {
357
480
  if (options.noAgentsMd) return false;
358
- if (!process.stdout.isTTY || process.env.CI === "true") return true;
481
+ if (!process.stdout.isTTY || isCiEnvironment()) return true;
359
482
  return await confirm({
360
483
  message: "Add LLM authoring context (.kici/AGENTS.md)?",
361
484
  default: true
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Write the local dev plane's `{ issuer, jwks }` trust root to `outFile`.
3
+ * Returns true on success.
4
+ */
5
+ export declare function localTrustRootCommand(outFile: string): Promise<boolean>;
6
+ //# sourceMappingURL=local-trust-root.d.ts.map
@@ -0,0 +1,52 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import { devIdentityPublicJwkFile } from "../local-plane/plane-manager.js";
3
+ import fs from "node:fs";
4
+ import pc from "picocolors";
5
+ import { logger } from "@kici-dev/core";
6
+ //#region src/commands/local-trust-root.ts
7
+ /**
8
+ * `kici local trust-root <file>` — export the offline local dev plane's
9
+ * dev-signed identity trust root as a self-contained `{ issuer, jwks }` file.
10
+ *
11
+ * The plane's dev identity mints tokens with issuer `kici-local` (clearly
12
+ * non-prod). To self-test a dev-signed attestation offline, `kici
13
+ * verify-attestation --trust-root <file>` needs the plane's public JWKS + its
14
+ * issuer, supplied out-of-band. This command writes exactly the shape
15
+ * `verify-attestation`'s `--trust-root` file path consumes.
16
+ *
17
+ * The exported issuer is the fixed sentinel `kici-local` — it can NEVER
18
+ * masquerade as the prod issuer (`https://api.kici.dev`), so verifying the same
19
+ * bundle against the default (prod) trust root still rejects structurally.
20
+ */
21
+ /** The plane's fixed non-prod dev-identity issuer. */
22
+ const KICI_LOCAL_ISSUER = "kici-local";
23
+ /**
24
+ * Write the local dev plane's `{ issuer, jwks }` trust root to `outFile`.
25
+ * Returns true on success.
26
+ */
27
+ async function localTrustRootCommand(outFile) {
28
+ if (!outFile) {
29
+ logger.error(pc.red("Error: an output file path is required (`kici local trust-root <file>`)."));
30
+ return false;
31
+ }
32
+ const pubFile = devIdentityPublicJwkFile();
33
+ let pubJwk;
34
+ try {
35
+ pubJwk = JSON.parse(fs.readFileSync(pubFile, "utf-8"));
36
+ } catch {
37
+ logger.error(pc.red("Error: no dev-signed identity found for the local plane. Boot the plane first (`kici local up`) so it generates + publishes its public key."));
38
+ return false;
39
+ }
40
+ const trustRoot = {
41
+ issuer: KICI_LOCAL_ISSUER,
42
+ jwks: { keys: [pubJwk] }
43
+ };
44
+ fs.writeFileSync(outFile, JSON.stringify(trustRoot, null, 2) + "\n");
45
+ logger.info(`${pc.green("✓")} Wrote local dev trust root to ${pc.bold(outFile)} ` + pc.dim(`(issuer ${KICI_LOCAL_ISSUER} — NOT prod)`));
46
+ logger.info(pc.dim(`Verify a dev-signed bundle offline with:\n kici verify-attestation --bundle <bundle> --trust-root ${outFile}`));
47
+ return true;
48
+ }
49
+ //#endregion
50
+ export { localTrustRootCommand };
51
+
52
+ //# sourceMappingURL=local-trust-root.js.map
@@ -0,0 +1,65 @@
1
+ /**
2
+ * kici local commands
3
+ *
4
+ * Manage the warm, per-user local dev orchestrator plane: a real independent
5
+ * orchestrator plus a local Postgres (embedded, with a podman fallback) that
6
+ * `kici run --local` dispatches through. `up` boots or reuses the plane,
7
+ * `status` reports it plus the control commands, `down` stops it, and `logs`
8
+ * prints the orchestrator log path.
9
+ */
10
+ import type { PlaneStatus, PlaneMode } from '../local-plane/plane-manager.js';
11
+ import type { PlaneState } from '../local-plane/plane-liveness.js';
12
+ /**
13
+ * Boot (or reuse) the local dev plane, honoring the durable attachment record.
14
+ *
15
+ * Routes through the same `resolvePlaneForRun` resolver `kici run --local` uses,
16
+ * so the two commands share one plane-resolution path and never diverge: an
17
+ * attached + reachable plane comes up hybrid, an attached-but-unreachable plane
18
+ * falls back to offline with a loud banner, and a never-attached plane comes up
19
+ * offline. `--offline` forces the independent boot (without clearing the durable
20
+ * attachment record — only `detach` does that); `--connected` requires an
21
+ * attached, reachable Platform.
22
+ */
23
+ export declare function localUpCommand(flags?: {
24
+ offline?: boolean;
25
+ connected?: boolean;
26
+ }): Promise<boolean>;
27
+ /**
28
+ * The machine-readable projection of a plane status.
29
+ *
30
+ * An explicit allow-list, NOT `JSON.stringify(status)`. `PlaneStatus` carries
31
+ * `adminToken` — the bootstrap admin token the CLI presents to the plane's
32
+ * admin API — so serializing the whole object would publish it on stdout, and
33
+ * from there into any consumer's logs. `attachment` is omitted for the same
34
+ * reason in miniature: no consumer needs it, and a field that is never emitted
35
+ * cannot leak a field added to it later.
36
+ */
37
+ export interface LocalStatusJson {
38
+ state: PlaneState;
39
+ running: boolean;
40
+ pid: number | null;
41
+ port: number | null;
42
+ url: string | null;
43
+ pgKind: 'embedded' | 'podman' | null;
44
+ stampVersion: number | null;
45
+ mode: PlaneMode | null;
46
+ }
47
+ /** Project a PlaneStatus onto the published JSON shape, absent fields as null. */
48
+ export declare function toLocalStatusJson(status: PlaneStatus): LocalStatusJson;
49
+ /** Show the local dev plane status and its control commands. */
50
+ export declare function localStatusCommand(options?: {
51
+ json?: boolean;
52
+ }): Promise<boolean>;
53
+ /** Stop the local dev plane, reporting success only once the port is released. */
54
+ export declare function localDownCommand(): Promise<boolean>;
55
+ /** Print the local dev plane orchestrator log path. */
56
+ export declare function localLogsCommand(): Promise<boolean>;
57
+ /**
58
+ * Attach the local dev plane to the hosted Platform so `kici run --local` uses
59
+ * real Platform-minted OIDC + attestation. Mints an org-scoped orchestrator key
60
+ * with the logged-in PAT, then (re)boots the plane hybrid.
61
+ */
62
+ export declare function localAttachCommand(): Promise<boolean>;
63
+ /** Detach the local dev plane from the Platform and reboot it offline (independent). */
64
+ export declare function localDetachCommand(): Promise<boolean>;
65
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1,206 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import { loadGlobalConfig } from "../remote/config.js";
3
+ import { attachPlane, detachPlane, planeDown, planeLogPath, planeStatus } from "../local-plane/plane-manager.js";
4
+ import { resolvePlaneForRun } from "../local-plane/resolve-plane.js";
5
+ import pc from "picocolors";
6
+ import { toErrorMessage } from "@kici-dev/core";
7
+ //#region src/commands/local.ts
8
+ /**
9
+ * kici local commands
10
+ *
11
+ * Manage the warm, per-user local dev orchestrator plane: a real independent
12
+ * orchestrator plus a local Postgres (embedded, with a podman fallback) that
13
+ * `kici run --local` dispatches through. `up` boots or reuses the plane,
14
+ * `status` reports it plus the control commands, `down` stops it, and `logs`
15
+ * prints the orchestrator log path.
16
+ */
17
+ /** Print the control commands a user needs once the plane is running. */
18
+ function printControlHints() {
19
+ console.log("");
20
+ console.log(pc.dim("Control commands:"));
21
+ console.log(` ${pc.cyan("kici local status")} Show plane status`);
22
+ console.log(` ${pc.cyan("kici local logs")} Print the orchestrator log path`);
23
+ console.log(` ${pc.cyan("kici local down")} Stop the plane`);
24
+ }
25
+ /**
26
+ * Boot (or reuse) the local dev plane, honoring the durable attachment record.
27
+ *
28
+ * Routes through the same `resolvePlaneForRun` resolver `kici run --local` uses,
29
+ * so the two commands share one plane-resolution path and never diverge: an
30
+ * attached + reachable plane comes up hybrid, an attached-but-unreachable plane
31
+ * falls back to offline with a loud banner, and a never-attached plane comes up
32
+ * offline. `--offline` forces the independent boot (without clearing the durable
33
+ * attachment record — only `detach` does that); `--connected` requires an
34
+ * attached, reachable Platform.
35
+ */
36
+ async function localUpCommand(flags = {}) {
37
+ console.log(pc.dim("Starting the local dev plane…"));
38
+ const resolved = await resolvePlaneForRun({
39
+ offline: flags.offline ?? false,
40
+ connected: flags.connected ?? false
41
+ });
42
+ if ("error" in resolved) {
43
+ console.log(pc.red(`✗ ${resolved.error}`));
44
+ return false;
45
+ }
46
+ const { plane } = resolved;
47
+ const url = plane.url ?? "";
48
+ const pg = pc.dim(`(postgres: ${plane.pgKind ?? "unknown"})`);
49
+ if (resolved.kind === "attached") console.log(pc.green("✓") + ` Local dev plane running (hybrid → Platform, org: ${pc.bold(resolved.orgId)}) at ${pc.bold(url)} ` + pg);
50
+ else {
51
+ console.log(pc.green("✓") + ` Local dev plane running (independent/offline) at ${pc.bold(url)} ` + pg);
52
+ if (resolved.kind === "fallback") console.log(pc.yellow(` ⚠ Attached, but booted offline: ${resolved.reason}`));
53
+ }
54
+ printControlHints();
55
+ return true;
56
+ }
57
+ /**
58
+ * Render the branch for a plane port held by a process that is not a KiCI plane
59
+ * orchestrator. Kept apart from the not-serving branch because `kici local down`
60
+ * deliberately refuses to signal such a holder, so pointing at it here would
61
+ * send the operator to a command that cannot act.
62
+ */
63
+ function printForeignHolder(status) {
64
+ console.log(pc.yellow("⚠") + ` Port ${pc.bold(String(status.port))} is held by a process that is not a KiCI plane orchestrator.`);
65
+ console.log(pc.dim(` pid: ${status.pid ?? "unknown"}`));
66
+ console.log("The local dev plane cannot start while that process holds the port.");
67
+ console.log(`Stop it yourself, or point the plane elsewhere with ${pc.cyan("KICI_LOCAL_ORCH_PORT")}.`);
68
+ }
69
+ /**
70
+ * Render the branch for a plane port held by a KiCI plane orchestrator that is
71
+ * not serving this config dir: our own stamped orchestrator failing its
72
+ * readiness probe, or a plane no stamp here accounts for. Split out of
73
+ * `localStatusCommand` so each branch stays readable.
74
+ *
75
+ * The two get different headlines because only one of them has been probed:
76
+ * readiness is checked for a plane we stamped, so `unready` is a measurement,
77
+ * while a plane we did not stamp is only known to be holding the port.
78
+ */
79
+ function printNotServing(status) {
80
+ if (status.state === "foreign-kici") {
81
+ console.log(pc.yellow("⚠") + ` Port ${pc.bold(String(status.port))} is held by a KiCI plane orchestrator this config dir did not start.`);
82
+ console.log(pc.dim(` pid: ${status.pid ?? "unknown"}`));
83
+ console.log(pc.dim(" owner: another KiCI plane — no stamp in this config dir"));
84
+ console.log(`Stop it with ${pc.cyan("kici local down")}.`);
85
+ return;
86
+ }
87
+ console.log(pc.yellow("⚠") + ` Local dev plane is running but NOT ready at ${pc.bold(status.url ?? "")}`);
88
+ console.log(pc.dim(` port: ${status.port}`));
89
+ console.log(pc.dim(` pid: ${status.pid ?? "unknown"}`));
90
+ if (status.checks && Object.keys(status.checks).length > 0) {
91
+ const rendered = Object.entries(status.checks).map(([name, ok]) => `${name}=${ok}`).join(" ");
92
+ console.log(pc.dim(` checks: ${rendered}`));
93
+ }
94
+ console.log(`Stop it with ${pc.cyan("kici local down")}.`);
95
+ }
96
+ /** Project a PlaneStatus onto the published JSON shape, absent fields as null. */
97
+ function toLocalStatusJson(status) {
98
+ return {
99
+ state: status.state,
100
+ running: status.running,
101
+ pid: status.pid ?? null,
102
+ port: status.port ?? null,
103
+ url: status.url ?? null,
104
+ pgKind: status.pgKind ?? null,
105
+ stampVersion: status.stampVersion ?? null,
106
+ mode: status.mode ?? null
107
+ };
108
+ }
109
+ /** Show the local dev plane status and its control commands. */
110
+ async function localStatusCommand(options) {
111
+ const status = await planeStatus();
112
+ if (options?.json) {
113
+ console.log(JSON.stringify(toLocalStatusJson(status)));
114
+ return true;
115
+ }
116
+ if (status.state === "stopped") {
117
+ console.log(pc.yellow("Local dev plane is not running."));
118
+ console.log(`Start it with ${pc.cyan("kici local up")}.`);
119
+ return true;
120
+ }
121
+ if (status.state === "foreign-unknown") {
122
+ printForeignHolder(status);
123
+ return true;
124
+ }
125
+ if (status.state !== "ready") {
126
+ printNotServing(status);
127
+ return true;
128
+ }
129
+ console.log(pc.green("✓") + ` Local dev plane running at ${pc.bold(status.url ?? "")}`);
130
+ console.log(pc.dim(` port: ${status.port}`));
131
+ console.log(pc.dim(` pid: ${status.pid ?? "unknown"}`));
132
+ console.log(pc.dim(` postgres: ${status.pgKind ?? "unknown"}`));
133
+ if (status.mode === "hybrid" && status.attachment) console.log(pc.dim(` attached: hybrid → Platform (org: ${status.attachment.orgId})`));
134
+ else console.log(pc.dim(" attached: no (independent/offline)"));
135
+ printControlHints();
136
+ return true;
137
+ }
138
+ /** Stop the local dev plane, reporting success only once the port is released. */
139
+ async function localDownCommand() {
140
+ console.log(pc.dim("Stopping the local dev plane…"));
141
+ const result = await planeDown();
142
+ if (!result.stopped) {
143
+ console.error(pc.red(`✗ Local dev plane NOT stopped: ${result.reason ?? "port still held"}`));
144
+ if (result.holderPid !== void 0) console.error(pc.dim(` holder pid: ${result.holderPid} port: ${result.port}`));
145
+ return false;
146
+ }
147
+ console.log(pc.green("✓") + " Local dev plane stopped.");
148
+ return true;
149
+ }
150
+ /** Print the local dev plane orchestrator log path. */
151
+ async function localLogsCommand() {
152
+ console.log(planeLogPath());
153
+ return true;
154
+ }
155
+ /**
156
+ * Attach the local dev plane to the hosted Platform so `kici run --local` uses
157
+ * real Platform-minted OIDC + attestation. Mints an org-scoped orchestrator key
158
+ * with the logged-in PAT, then (re)boots the plane hybrid.
159
+ */
160
+ async function localAttachCommand() {
161
+ const config = await loadGlobalConfig();
162
+ if (!config.pat) {
163
+ console.error(pc.red("Not authenticated. Run `kici login` first."));
164
+ return false;
165
+ }
166
+ if (!config.platformEndpoint) {
167
+ console.error(pc.red("No Platform endpoint configured. Run `kici login` first."));
168
+ return false;
169
+ }
170
+ const orgId = config.activeOrgId;
171
+ if (!orgId) {
172
+ console.error(pc.red("No active organization. Select one with `kici org use <org>` before attaching."));
173
+ return false;
174
+ }
175
+ try {
176
+ console.log(pc.dim("Attaching the local dev plane to the Platform…"));
177
+ const status = await attachPlane({
178
+ apiBase: config.platformEndpoint,
179
+ pat: config.pat,
180
+ orgId
181
+ });
182
+ console.log(pc.green("✓") + ` Local dev plane attached (hybrid) at ${pc.bold(status.url ?? "")} ` + pc.dim(`(org: ${orgId})`));
183
+ console.log(pc.dim("`kici run --local` now uses real Platform OIDC + attestation. Detach: ") + pc.cyan("kici local detach"));
184
+ return true;
185
+ } catch (err) {
186
+ console.error(pc.red(`Attach failed: ${toErrorMessage(err)}`));
187
+ return false;
188
+ }
189
+ }
190
+ /** Detach the local dev plane from the Platform and reboot it offline (independent). */
191
+ async function localDetachCommand() {
192
+ const config = await loadGlobalConfig();
193
+ try {
194
+ console.log(pc.dim("Detaching the local dev plane…"));
195
+ await detachPlane({ pat: config.pat });
196
+ console.log(pc.green("✓") + " Local dev plane detached (independent/offline).");
197
+ return true;
198
+ } catch (err) {
199
+ console.error(pc.red(`Detach failed: ${toErrorMessage(err)}`));
200
+ return false;
201
+ }
202
+ }
203
+ //#endregion
204
+ export { localAttachCommand, localDetachCommand, localDownCommand, localLogsCommand, localStatusCommand, localUpCommand, toLocalStatusJson };
205
+
206
+ //# sourceMappingURL=local.js.map