@kici-dev/compiler 0.1.14 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1,21 @@
1
- TBD
1
+ # @kici-dev/compiler
2
+
3
+ Compiler and CLI for KiCI workflows. Compiles `.kici/workflows/*.ts` to a `kici.lock.json` file consumed by the orchestrator and agents, and runs workflows locally or against a remote orchestrator.
4
+
5
+ Part of [KiCI](https://kici.dev) — CI/CD workflows as TypeScript code: author them with full language power, dry-run them locally, and run them on your own infrastructure.
6
+
7
+ ## Install
8
+
9
+ Usually consumed through the [`kici`](https://www.npmjs.com/package/kici) wrapper CLI:
10
+
11
+ ```bash
12
+ npm install -g kici
13
+ ```
14
+
15
+ Direct install (`npm install --save-dev @kici-dev/compiler`) works too when you want the library API.
16
+
17
+ ## Links
18
+
19
+ - Documentation: <https://docs.kici.dev/user/cli-reference/>
20
+ - Source: <https://github.com/kici-dev/kici-public/tree/main/packages/compiler>
21
+ - License: Apache-2.0
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { shouldSuppressBanner } from "./cli-banner.js";
4
4
  import { Argument, Command, Option } from "commander";
5
5
  import pc from "picocolors";
6
6
  //#region src/cli.ts
7
- const version = "0.1.14";
7
+ const version = "0.1.15";
8
8
  const program = new Command();
9
9
  program.name("kici").description("KiCI workflow compiler").version(version);
10
10
  program.hook("preAction", (_thisCommand, actionCommand) => {
@@ -68,9 +68,12 @@ runCommand.command("local").argument("[event]", "Event type (e.g., push, pr:open
68
68
  });
69
69
  process.exit(success ? 0 : 1);
70
70
  });
71
- runCommand.command("remote").argument("[fixture]", "Fixture name or glob pattern (omit to list available)").description("Execute fixtures remotely via orchestrator").option("--workflow <name>", "Run a specific workflow directly (bypass triggers)").option("--all", "Run all available fixtures", false).option("--parallel", "Run matching fixtures concurrently", false).option("--no-wait", "Fire and forget (print runIds, don't stream)").option("--quiet", "Suppress output except final result", false).option("--json", "Output structured JSON result", false).option("--junit <path>", "Output JUnit XML result").option("--history", "Show recent run history", false).option("--routing-key <key>", "Override routing key for this run").option("--debug", "Verbose internals", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--secret <key=value>", "Inject flat secret (repeatable)", (val, prev) => [...prev, val], []).option("--context <ctx.key=value>", "Inject context secret (repeatable)", (val, prev) => [...prev, val], []).action(async (fixture, options) => {
71
+ runCommand.command("remote").argument("[fixture]", "Fixture name or glob pattern (omit to list available)").description("Execute fixtures remotely via orchestrator").option("--workflow <name>", "Run a specific workflow directly (bypass triggers)").option("--all", "Run all available fixtures", false).option("--parallel", "Run matching fixtures concurrently", false).option("--no-wait", "Fire and forget (print runIds, don't stream)").option("--quiet", "Suppress output except final result", false).option("--json", "Output structured JSON result", false).option("--junit <path>", "Output JUnit XML result").option("--history", "Show recent run history", false).option("--routing-key <key>", "Override routing key for this run").option("--debug", "Verbose internals", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--context <ctx.key=value>", "Inject a namespaced context secret, uploaded encrypted to the orchestrator (repeatable)", (val, prev) => [...prev, val], []).option("--env <KEY=VALUE>", "Provide a per-run secret (repeatable); uploaded encrypted to the orchestrator", (val, prev) => [...prev, val], []).action(async (fixture, options) => {
72
72
  const { runRemoteCommand } = await import("./commands/index.js");
73
- const success = await runRemoteCommand(fixture, options);
73
+ const success = await runRemoteCommand(fixture, {
74
+ ...options,
75
+ envFlags: options.env
76
+ });
74
77
  process.exit(success ? 0 : 1);
75
78
  });
76
79
  program.command("test").argument("[event]", "Event type to preview (e.g., push, pr:open, schedule)").description("Preview which workflows match a trigger event (dry-run)").option("--branch <name>", "Override target branch for trigger matching (default: main)").option("--sha <hash>", "Override commit SHA").option("--workflow <name>", "Filter to specific workflow in display").option("--job <name>", "Filter to specific job in display").option("--debug", "Verbose internals", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--files <path>", "Simulate changed file path for trigger matching (repeatable)", (val, prev) => [...prev, val], []).option("--secret <key=value>", "Inject flat secret (repeatable)", (val, prev) => [...prev, val], []).option("--context <ctx.key=value>", "Inject context secret (repeatable)", (val, prev) => [...prev, val], []).action(async (event, options) => {
@@ -1,6 +1,7 @@
1
1
  import "../chunk-gOLHoazu.js";
2
2
  import { getConfigPath, mergeGlobalConfig } from "../remote/config.js";
3
3
  import { deviceFlow, exchangeTokenForPat, pkceFlow } from "../remote/oauth.js";
4
+ import "../remote/prod-defaults.js";
4
5
  import { isHeadless } from "../auth/headless-detect.js";
5
6
  import pc from "picocolors";
6
7
  import { toErrorMessage } from "@kici-dev/core";
@@ -45,21 +46,9 @@ function checkPatExpiry(expiresAt) {
45
46
  * 4. Save PAT to global config
46
47
  */
47
48
  async function oauthLogin(options) {
48
- const platformUrl = options.platformEndpoint || process.env.KICI_PLATFORM_URL || "";
49
- const issuer = process.env.KICI_OIDC_ISSUER || "";
50
- const clientId = process.env.KICI_OIDC_CLIENT_ID || "";
51
- const missing = [];
52
- if (!platformUrl) missing.push("KICI_PLATFORM_URL");
53
- if (!issuer) missing.push("KICI_OIDC_ISSUER");
54
- if (!clientId) missing.push("KICI_OIDC_CLIENT_ID");
55
- if (missing.length > 0) {
56
- console.error(pc.red(`Error: missing required env var(s) for OAuth login: ${missing.join(", ")}`));
57
- console.error(pc.gray(" Set them to your Platform and IdP endpoints, for example:"));
58
- console.error(pc.gray(" export KICI_PLATFORM_URL=https://your-platform.example.com"));
59
- console.error(pc.gray(" export KICI_OIDC_ISSUER=https://your-idp.example.com"));
60
- console.error(pc.gray(" export KICI_OIDC_CLIENT_ID=<cli-client-id>"));
61
- return false;
62
- }
49
+ const platformUrl = options.platformEndpoint || process.env.KICI_PLATFORM_URL || "https://api.kici.dev";
50
+ const issuer = process.env.KICI_OIDC_ISSUER || "https://auth.kici.dev/realms/kici-internal";
51
+ const clientId = process.env.KICI_OIDC_CLIENT_ID || "kici-cli";
63
52
  console.log(pc.cyan("\n Step 1/4: Detecting environment..."));
64
53
  const browserCmdSet = !!process.env.KICI_BROWSER_CMD;
65
54
  const useDeviceFlow = options.device || !browserCmdSet && isHeadless();
@@ -5,6 +5,7 @@ import { AuthenticationError, ConnectionError, OrchestratorClient } from "../rem
5
5
  import { loadGlobalConfig } from "../remote/config.js";
6
6
  import { RunHistory } from "../remote/history.js";
7
7
  import { ObserverClient } from "../remote/observer.js";
8
+ import { buildEncryptedSecrets } from "../remote/secret-upload.js";
8
9
  import { createOverlayTarball, getSizeWarning, uploadTarball } from "../remote/uploader.js";
9
10
  import { formatJsonResult } from "../remote/output/json.js";
10
11
  import { formatJunitResult } from "../remote/output/junit.js";
@@ -185,7 +186,7 @@ async function runSingleFixture(fixture, client, options, config, history) {
185
186
  let routingKey = options.routingKey ?? config.routingKey ?? "default";
186
187
  if (!hasRemote) {
187
188
  routingKey = `local:${path.basename(repoRoot)}`;
188
- logger.warn("No remote detected -- steps that use git commands will fail (no .git directory)");
189
+ if (!options.quiet) logger.warn("No remote detected -- steps that use git commands will fail (no .git directory)");
189
190
  }
190
191
  let inlineLockFile;
191
192
  if (!hasRemote) inlineLockFile = await readFile(path.join(kiciDir, "kici.lock.json"), "utf-8");
@@ -217,6 +218,7 @@ async function runSingleFixture(fixture, client, options, config, history) {
217
218
  };
218
219
  }
219
220
  if (!options.quiet) logger.info(pc.gray("Triggering test run..."));
221
+ const encrypted = await buildEncryptedSecrets(kiciDir, options.envFlags, options.context, upload.publicKey);
220
222
  const triggerResult = await client.triggerTest({
221
223
  fixtureId: fixture.id,
222
224
  event,
@@ -224,6 +226,10 @@ async function runSingleFixture(fixture, client, options, config, history) {
224
226
  uploadId: upload.uploadId,
225
227
  cliPublicKey: uploadResult.cliPublicKey.toString("base64"),
226
228
  secrets: opts.secrets,
229
+ ...encrypted && {
230
+ encryptedSecrets: encrypted.encryptedSecrets,
231
+ encryptedSecretsKey: encrypted.cliPublicKey
232
+ },
227
233
  workflowName: opts.workflowName,
228
234
  inlineLockFile,
229
235
  fullRepo: !hasRemote || void 0
@@ -516,6 +522,7 @@ async function runDirectWorkflow(workflowName, options) {
516
522
  const repoName = !hasRemote ? path.basename(repoRoot) : void 0;
517
523
  const payload = {};
518
524
  if (!hasRemote) payload.repository = { full_name: `local/${repoName}` };
525
+ const encrypted = await buildEncryptedSecrets(kiciDir, options.envFlags, options.context, upload.publicKey);
519
526
  const result = await client.triggerTest({
520
527
  fixtureId: `direct:${workflowName}`,
521
528
  event: {
@@ -526,6 +533,10 @@ async function runDirectWorkflow(workflowName, options) {
526
533
  routingKey,
527
534
  uploadId: upload.uploadId,
528
535
  cliPublicKey: directUploadResult.cliPublicKey.toString("base64"),
536
+ ...encrypted && {
537
+ encryptedSecrets: encrypted.encryptedSecrets,
538
+ encryptedSecretsKey: encrypted.cliPublicKey
539
+ },
529
540
  workflowName,
530
541
  inlineLockFile,
531
542
  fullRepo: !hasRemote || void 0
@@ -47,7 +47,7 @@ async function secretsListCommand(options) {
47
47
  const contexts = ((await res.json()).environments ?? []).filter((e) => e.allow_local_execution);
48
48
  if (contexts.length === 0) {
49
49
  console.log(pc.yellow("No test-available secret contexts found."));
50
- console.log(pc.gray("Set allowLocalExecution=true on an environment to make its secrets available for test runs."));
50
+ console.log(pc.gray("Enable test runs (allowLocalExecution) on an environment to make its secrets available for test runs."));
51
51
  return true;
52
52
  }
53
53
  console.log(pc.bold("\nTest-available secret contexts:\n"));
@@ -15,7 +15,7 @@ import { formatDuration, logger, toErrorMessage } from "@kici-dev/core";
15
15
  * Looks up local history first, then fetches from the orchestrator for
16
16
  * up-to-date status and logs.
17
17
  */
18
- const CLI_VERSION = "0.1.14";
18
+ const CLI_VERSION = "0.1.15";
19
19
  /**
20
20
  * Show status and details of a test run.
21
21
  *
@@ -32,6 +32,8 @@ export interface RemoteRunOptions extends TestOptions {
32
32
  routingKey?: string;
33
33
  /** Show recent run history */
34
34
  history?: boolean;
35
+ /** --env KEY=VALUE flag values, uploaded as per-run secrets. */
36
+ envFlags?: string[];
35
37
  }
36
38
  /** Result of a single remote fixture run */
37
39
  export interface RemoteRunResult {