@kici-dev/compiler 0.1.14 → 0.1.16

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 (68) hide show
  1. package/README.md +21 -1
  2. package/dist/cli.d.ts +9 -1
  3. package/dist/cli.js +213 -179
  4. package/dist/commands/approve.d.ts +23 -0
  5. package/dist/commands/approve.js +46 -0
  6. package/dist/commands/compile.js +1 -1
  7. package/dist/commands/docs.js +2 -2
  8. package/dist/commands/endpoints.js +1 -1
  9. package/dist/commands/held-run-client.d.ts +26 -0
  10. package/dist/commands/held-run-client.js +98 -0
  11. package/dist/commands/held-run-resolve.d.ts +45 -0
  12. package/dist/commands/held-run-resolve.js +53 -0
  13. package/dist/commands/hook.js +1 -1
  14. package/dist/commands/index.d.ts +4 -0
  15. package/dist/commands/index.js +3 -1
  16. package/dist/commands/init.js +1 -1
  17. package/dist/commands/login.js +4 -15
  18. package/dist/commands/reject.d.ts +25 -0
  19. package/dist/commands/reject.js +49 -0
  20. package/dist/commands/run.js +13 -2
  21. package/dist/commands/secrets-list.js +1 -1
  22. package/dist/commands/status.js +1 -1
  23. package/dist/commands/test.d.ts +2 -0
  24. package/dist/commands/test.js +1 -1
  25. package/dist/commands/types.js +1 -1
  26. package/dist/commands/watch.js +1 -1
  27. package/dist/execution/executor.js +2 -2
  28. package/dist/execution/sdk-alias.js +1 -1
  29. package/dist/fixtures/compiler.js +2 -2
  30. package/dist/fixtures/defaults/index.js +2 -2
  31. package/dist/hooks/detector.js +1 -1
  32. package/dist/hooks/installer.js +1 -1
  33. package/dist/index.d.ts +1 -1
  34. package/dist/llm-context/llms-full.txt +1141 -349
  35. package/dist/llm-context/llms.txt +4 -2
  36. package/dist/local-executor/index.js +5 -4
  37. package/dist/local-executor/job-runner.js +3 -5
  38. package/dist/local-executor/materializer.d.ts +5 -0
  39. package/dist/local-executor/materializer.js +23 -2
  40. package/dist/local-executor/secret-loader.js +1 -1
  41. package/dist/local-executor/to-event-payload.d.ts +16 -0
  42. package/dist/local-executor/to-event-payload.js +21 -0
  43. package/dist/local-executor/workflow-lock.d.ts +4 -3
  44. package/dist/local-executor/workflow-lock.js +0 -0
  45. package/dist/lockfile/generator.js +22 -5
  46. package/dist/lockfile/hash-files.js +1 -1
  47. package/dist/postinstall.js +1 -1
  48. package/dist/remote/client.d.ts +4 -0
  49. package/dist/remote/config.js +1 -1
  50. package/dist/remote/history.js +1 -1
  51. package/dist/remote/prod-defaults.d.ts +18 -0
  52. package/dist/remote/prod-defaults.js +23 -0
  53. package/dist/remote/secret-upload.d.ts +20 -0
  54. package/dist/remote/secret-upload.js +58 -0
  55. package/dist/remote/uploader.js +1 -1
  56. package/dist/templates/index.js +1 -1
  57. package/dist/templates/package-json.js +1 -1
  58. package/dist/templates/workflows/pr-checks.js +3 -2
  59. package/dist/templates/workflows/pr-checks.ts +4 -2
  60. package/dist/test-runner/git-detector.js +1 -1
  61. package/dist/test-runner/job-executor.js +2 -2
  62. package/dist/test-runner/secrets-file.js +1 -1
  63. package/dist/test-runner/step-context.js +6 -2
  64. package/dist/types.d.ts +33 -2
  65. package/dist/types.js +1 -0
  66. package/dist/workflows/pr-checks.ts +4 -2
  67. package/package.json +13 -9
  68. package/sbom.spdx.json +34 -34
@@ -0,0 +1,98 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { loadGlobalConfig } from "../remote/config.js";
3
+ import pc from "picocolors";
4
+ import { logger } from "@kici-dev/core";
5
+ //#region src/commands/held-run-client.ts
6
+ /**
7
+ * Shared HTTP plumbing for the `kici approve` / `kici reject` held-run
8
+ * commands. Resolves auth + endpoint from the global config (PAT preferred,
9
+ * API key fallback; Platform endpoint preferred, orchestrator fallback) and
10
+ * exposes thin list / approve / reject helpers against the Platform dashboard
11
+ * API.
12
+ */
13
+ /**
14
+ * Resolve the auth context, printing a clear error and returning null when the
15
+ * CLI is not authenticated / no active org is set.
16
+ */
17
+ async function resolveHeldRunContext() {
18
+ const config = await loadGlobalConfig();
19
+ const token = config.pat ?? config.token;
20
+ if (!token) {
21
+ logger.error(pc.red("Not authenticated. Run `kici login` to get started."));
22
+ return null;
23
+ }
24
+ const endpoint = config.platformEndpoint ?? config.endpoint;
25
+ if (!endpoint) {
26
+ logger.error(pc.red("No endpoint configured. Run `kici login` to configure."));
27
+ return null;
28
+ }
29
+ if (!config.activeOrgId) {
30
+ logger.error(pc.red("No active organization. Run `kici org use <name>` to set one."));
31
+ return null;
32
+ }
33
+ return {
34
+ endpoint,
35
+ token,
36
+ orgId: config.activeOrgId
37
+ };
38
+ }
39
+ function authHeaders(token) {
40
+ return {
41
+ "Content-Type": "application/json",
42
+ Authorization: `Bearer ${token}`
43
+ };
44
+ }
45
+ /** List the held runs for a single run id. */
46
+ async function listHeldRunsForRun(ctx, runId) {
47
+ const url = `${ctx.endpoint}/api/v1/orgs/${ctx.orgId}/held-runs?runId=${encodeURIComponent(runId)}`;
48
+ const response = await fetch(url, {
49
+ method: "GET",
50
+ headers: authHeaders(ctx.token)
51
+ });
52
+ if (!response.ok) throw new Error(await describeError(response));
53
+ return (await response.json()).heldRuns ?? [];
54
+ }
55
+ /** POST an approve decision for a held run. Returns true on success. */
56
+ async function postApprove(ctx, heldRunId) {
57
+ const url = `${ctx.endpoint}/api/v1/orgs/${ctx.orgId}/held-runs/${heldRunId}/approve`;
58
+ const response = await fetch(url, {
59
+ method: "POST",
60
+ headers: authHeaders(ctx.token)
61
+ });
62
+ if (!response.ok) {
63
+ logger.error(pc.red(await describeError(response)));
64
+ return false;
65
+ }
66
+ return true;
67
+ }
68
+ /** POST a reject decision (with reason) for a held run. Returns true on success. */
69
+ async function postReject(ctx, heldRunId, reason) {
70
+ const url = `${ctx.endpoint}/api/v1/orgs/${ctx.orgId}/held-runs/${heldRunId}/reject`;
71
+ const response = await fetch(url, {
72
+ method: "POST",
73
+ headers: authHeaders(ctx.token),
74
+ body: JSON.stringify({ reason })
75
+ });
76
+ if (!response.ok) {
77
+ logger.error(pc.red(await describeError(response)));
78
+ return false;
79
+ }
80
+ return true;
81
+ }
82
+ /** Build a user-facing error string from a failed response. */
83
+ async function describeError(response) {
84
+ let detail;
85
+ try {
86
+ detail = (await response.json()).error;
87
+ } catch {}
88
+ switch (response.status) {
89
+ case 401: return "Authentication failed. Run `kici login` to re-authenticate.";
90
+ case 403: return `Access denied${detail ? `: ${detail}` : ""}.`;
91
+ case 404: return `Held run not found${detail ? `: ${detail}` : ""}.`;
92
+ default: return detail ?? `Request failed with status ${response.status}.`;
93
+ }
94
+ }
95
+ //#endregion
96
+ export { listHeldRunsForRun, postApprove, postReject, resolveHeldRunContext };
97
+
98
+ //# sourceMappingURL=held-run-client.js.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Shared held-run resolution for the `kici approve` / `kici reject` commands.
3
+ *
4
+ * Both commands first list the pending holds for a run, then resolve the one
5
+ * the user named via `--job` / `--step` (or the sole pending hold when there is
6
+ * exactly one and no filter is given). The resolution is a pure function so it
7
+ * can be unit-tested without HTTP.
8
+ */
9
+ /** Hold scope, mirroring the engine `HoldScope` enum. */
10
+ export type HeldRunScope = 'workflow' | 'job' | 'step';
11
+ /** A pending-hold row as returned by `GET /orgs/:orgId/held-runs`. */
12
+ export interface HeldRunSummary {
13
+ id: string;
14
+ runId: string;
15
+ jobId?: string;
16
+ holdScope?: HeldRunScope;
17
+ stepIndex?: number | null;
18
+ status: string;
19
+ }
20
+ /** Filters supplied on the command line. */
21
+ export interface HeldRunFilter {
22
+ /** Match a hold by its job name. */
23
+ job?: string;
24
+ /** Match a step-scoped hold by its step index (compared as a string). */
25
+ step?: string;
26
+ }
27
+ /** Resolution result: either a held-run id or a user-facing error message. */
28
+ export type ResolveResult = {
29
+ ok: true;
30
+ heldRunId: string;
31
+ hold: HeldRunSummary;
32
+ } | {
33
+ ok: false;
34
+ error: string;
35
+ };
36
+ /**
37
+ * Resolve the held-run id matching the filter from a list of pending holds.
38
+ *
39
+ * - `--step` requires `--job` and matches a `step`-scoped hold whose step index
40
+ * equals the given value.
41
+ * - `--job` alone matches a `job`/`workflow`-scoped hold for that job.
42
+ * - With no filter, the sole pending hold is used; ambiguity is an error.
43
+ */
44
+ export declare function resolveHeldRunId(holds: readonly HeldRunSummary[], filter: HeldRunFilter): ResolveResult;
45
+ //# sourceMappingURL=held-run-resolve.d.ts.map
@@ -0,0 +1,53 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ //#region src/commands/held-run-resolve.ts
3
+ /**
4
+ * Resolve the held-run id matching the filter from a list of pending holds.
5
+ *
6
+ * - `--step` requires `--job` and matches a `step`-scoped hold whose step index
7
+ * equals the given value.
8
+ * - `--job` alone matches a `job`/`workflow`-scoped hold for that job.
9
+ * - With no filter, the sole pending hold is used; ambiguity is an error.
10
+ */
11
+ function resolveHeldRunId(holds, filter) {
12
+ const pending = holds.filter((h) => h.status === "pending");
13
+ if (pending.length === 0) return {
14
+ ok: false,
15
+ error: "No pending approval holds found for this run."
16
+ };
17
+ if (filter.step !== void 0) {
18
+ if (!filter.job) return {
19
+ ok: false,
20
+ error: "--step requires --job to identify the held step."
21
+ };
22
+ return pickSingle(pending.filter((h) => h.holdScope === "step" && h.jobId === filter.job && String(h.stepIndex ?? "") === filter.step), `step ${filter.step} of job '${filter.job}'`);
23
+ }
24
+ if (filter.job !== void 0) return pickSingle(pending.filter((h) => h.jobId === filter.job && h.holdScope !== "step"), `job '${filter.job}'`);
25
+ if (pending.length > 1) return {
26
+ ok: false,
27
+ error: "Multiple pending holds for this run. Use --job <name> (and --step <index>) to choose one."
28
+ };
29
+ return {
30
+ ok: true,
31
+ heldRunId: pending[0].id,
32
+ hold: pending[0]
33
+ };
34
+ }
35
+ function pickSingle(matches, label) {
36
+ if (matches.length === 0) return {
37
+ ok: false,
38
+ error: `No pending hold found for ${label}.`
39
+ };
40
+ if (matches.length > 1) return {
41
+ ok: false,
42
+ error: `Multiple pending holds match ${label}; cannot disambiguate.`
43
+ };
44
+ return {
45
+ ok: true,
46
+ heldRunId: matches[0].id,
47
+ hold: matches[0]
48
+ };
49
+ }
50
+ //#endregion
51
+ export { resolveHeldRunId };
52
+
53
+ //# sourceMappingURL=held-run-resolve.js.map
@@ -2,9 +2,9 @@ import "../chunk-gOLHoazu.js";
2
2
  import { detectHookTools, findGitDir } from "../hooks/detector.js";
3
3
  import { installHook } from "../hooks/installer.js";
4
4
  import "../hooks/index.js";
5
+ import path from "node:path";
5
6
  import pc from "picocolors";
6
7
  import { readFile } from "node:fs/promises";
7
- import path from "node:path";
8
8
  import { logger, toErrorMessage } from "@kici-dev/core";
9
9
  import { select } from "@inquirer/prompts";
10
10
  //#region src/commands/hook.ts
@@ -24,6 +24,10 @@ export { orgListCommand, orgUseCommand, orgCurrentCommand } from './org.js';
24
24
  export { logoutCommand } from './logout.js';
25
25
  export { cancelCommand } from './cancel.js';
26
26
  export type { CancelOptions } from './cancel.js';
27
+ export { approveCommand } from './approve.js';
28
+ export type { ApproveOptions } from './approve.js';
29
+ export { rejectCommand } from './reject.js';
30
+ export type { RejectOptions } from './reject.js';
27
31
  export { workflowsListCommand } from './workflows.js';
28
32
  export type { WorkflowsListOptions } from './workflows.js';
29
33
  export { drainWorkerCommand } from './drain-worker.js';
@@ -1,5 +1,6 @@
1
1
  import "../chunk-gOLHoazu.js";
2
2
  import { compileCommand } from "./compile.js";
3
+ import { approveCommand } from "./approve.js";
3
4
  import { cancelCommand } from "./cancel.js";
4
5
  import { docsCommand, docsLlmCommand } from "./docs.js";
5
6
  import { drainWorkerCommand } from "./drain-worker.js";
@@ -16,5 +17,6 @@ import { statusCommand } from "./status.js";
16
17
  import { typesCommand } from "./types.js";
17
18
  import { orgCurrentCommand, orgListCommand, orgUseCommand } from "./org.js";
18
19
  import { logoutCommand } from "./logout.js";
20
+ import { rejectCommand } from "./reject.js";
19
21
  import { workflowsListCommand } from "./workflows.js";
20
- export { cancelCommand, compileCommand, docsCommand, docsLlmCommand, drainWorkerCommand, endpointsCommand, fixtureCommand, hookInstallCommand, initCommand, loginCommand, logoutCommand, orgCurrentCommand, orgListCommand, orgUseCommand, runLocalCommand, runRemoteCommand, secretsListCommand, statusCommand, testCommand, testDryRun, typesCommand, watchCommand, workflowsListCommand };
22
+ export { approveCommand, cancelCommand, compileCommand, docsCommand, docsLlmCommand, drainWorkerCommand, endpointsCommand, fixtureCommand, hookInstallCommand, initCommand, loginCommand, logoutCommand, orgCurrentCommand, orgListCommand, orgUseCommand, rejectCommand, runLocalCommand, runRemoteCommand, secretsListCommand, statusCommand, testCommand, testDryRun, typesCommand, watchCommand, workflowsListCommand };
@@ -7,9 +7,9 @@ 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 path from "node:path";
10
11
  import pc from "picocolors";
11
12
  import { access, mkdir, readFile, rm, writeFile } from "node:fs/promises";
12
- import path from "node:path";
13
13
  import { initZx, logger, toErrorMessage } from "@kici-dev/core";
14
14
  import { detectPackageManager, installBuildPolicyArgs, installCommand, parsePackageManager } from "@kici-dev/core/package-manager";
15
15
  import { checkbox, confirm, select } from "@inquirer/prompts";
@@ -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();
@@ -0,0 +1,25 @@
1
+ /**
2
+ * kici reject command
3
+ *
4
+ * Rejects a held approval gate for a run (requires `--reason`). Resolves the
5
+ * held element by `--job` / `--step` (or the sole pending hold), then records
6
+ * the rejection via the Platform dashboard API (PAT auth).
7
+ */
8
+ /** Options for the reject command. */
9
+ export interface RejectOptions {
10
+ /** Match a hold by its job name. */
11
+ job?: string;
12
+ /** Match a step-scoped hold by its step index. */
13
+ step?: string;
14
+ /** Required rejection reason. */
15
+ reason?: string;
16
+ }
17
+ /**
18
+ * Reject a held approval gate.
19
+ *
20
+ * @param runId - The run whose hold to reject.
21
+ * @param options - Job/step filters plus the required reason.
22
+ * @returns true on success, false on error.
23
+ */
24
+ export declare function rejectCommand(runId: string, options?: RejectOptions): Promise<boolean>;
25
+ //# sourceMappingURL=reject.d.ts.map
@@ -0,0 +1,49 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { listHeldRunsForRun, postReject, resolveHeldRunContext } from "./held-run-client.js";
3
+ import { resolveHeldRunId } from "./held-run-resolve.js";
4
+ import pc from "picocolors";
5
+ import { logger, toErrorMessage } from "@kici-dev/core";
6
+ //#region src/commands/reject.ts
7
+ /**
8
+ * kici reject command
9
+ *
10
+ * Rejects a held approval gate for a run (requires `--reason`). Resolves the
11
+ * held element by `--job` / `--step` (or the sole pending hold), then records
12
+ * the rejection via the Platform dashboard API (PAT auth).
13
+ */
14
+ /**
15
+ * Reject a held approval gate.
16
+ *
17
+ * @param runId - The run whose hold to reject.
18
+ * @param options - Job/step filters plus the required reason.
19
+ * @returns true on success, false on error.
20
+ */
21
+ async function rejectCommand(runId, options = {}) {
22
+ try {
23
+ if (!options.reason) {
24
+ logger.error(pc.red("A rejection reason is required. Pass --reason <text>."));
25
+ return false;
26
+ }
27
+ const ctx = await resolveHeldRunContext();
28
+ if (!ctx) return false;
29
+ const resolution = resolveHeldRunId(await listHeldRunsForRun(ctx, runId), {
30
+ job: options.job,
31
+ step: options.step
32
+ });
33
+ if (!resolution.ok) {
34
+ logger.error(pc.red(resolution.error));
35
+ return false;
36
+ }
37
+ logger.info(`Rejecting held run ${pc.cyan(resolution.heldRunId)} for run ${pc.cyan(runId)}...`);
38
+ if (!await postReject(ctx, resolution.heldRunId, options.reason)) return false;
39
+ logger.info(pc.yellow("Rejection recorded. The held element will fail."));
40
+ return true;
41
+ } catch (error) {
42
+ logger.error(pc.red(`Error: ${toErrorMessage(error)}`));
43
+ return false;
44
+ }
45
+ }
46
+ //#endregion
47
+ export { rejectCommand };
48
+
49
+ //# sourceMappingURL=reject.js.map
@@ -5,15 +5,16 @@ 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";
11
12
  import { StreamingFormatter } from "../remote/output/streaming.js";
12
13
  import { formatErrorHighlight, formatMultiFixtureSummary, formatSummary } from "../remote/output/summary.js";
13
14
  import { compileFixtures, filterFixtures } from "../fixtures/compiler.js";
15
+ import path from "node:path";
14
16
  import pc from "picocolors";
15
17
  import { readFile, writeFile } from "node:fs/promises";
16
- import path from "node:path";
17
18
  import { formatBytes, logger, toErrorMessage } from "@kici-dev/core";
18
19
  //#region src/commands/run.ts
19
20
  /**
@@ -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.16";
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 {
@@ -6,9 +6,9 @@ import { displayDryRun } from "../test-runner/dry-run.js";
6
6
  import { parseEventArg } from "../test-runner/event-types.js";
7
7
  import { buildEventPayload } from "../test-runner/payload-builder.js";
8
8
  import { loadSecretsFile } from "../test-runner/secrets-file.js";
9
+ import path from "node:path";
9
10
  import pc from "picocolors";
10
11
  import { readFile } from "node:fs/promises";
11
- import path from "node:path";
12
12
  import { logger, toErrorMessage } from "@kici-dev/core";
13
13
  import { matchAllWorkflows, normalizeRunsOn } from "@kici-dev/engine";
14
14
  //#region src/commands/test.ts
@@ -1,9 +1,9 @@
1
1
  import "../chunk-gOLHoazu.js";
2
2
  import { loadGlobalConfig } from "../remote/config.js";
3
3
  import { generateSecretsDts } from "../generators/secrets-dts.js";
4
+ import path from "node:path";
4
5
  import pc from "picocolors";
5
6
  import fs from "node:fs/promises";
6
- import path from "node:path";
7
7
  import { toErrorMessage } from "@kici-dev/core";
8
8
  //#region src/commands/types.ts
9
9
  /**
@@ -2,8 +2,8 @@ import "../chunk-gOLHoazu.js";
2
2
  import { resolveKiciDir } from "../execution/executor.js";
3
3
  import "../execution/index.js";
4
4
  import { compileCommand } from "./compile.js";
5
- import pc from "picocolors";
6
5
  import path from "node:path";
6
+ import pc from "picocolors";
7
7
  import { logger, toErrorMessage } from "@kici-dev/core";
8
8
  import chokidar from "chokidar";
9
9
  //#region src/commands/watch.ts
@@ -2,10 +2,10 @@ import "../chunk-gOLHoazu.js";
2
2
  import { compilerError } from "../errors/formatter.js";
3
3
  import "../errors/index.js";
4
4
  import { ensureTsLoaderHook } from "./ts-loader.js";
5
+ import { pathToFileURL } from "node:url";
6
+ import path from "node:path";
5
7
  import { existsSync } from "node:fs";
6
8
  import fs from "node:fs/promises";
7
- import path from "node:path";
8
- import { pathToFileURL } from "node:url";
9
9
  //#region src/execution/executor.ts
10
10
  /**
11
11
  * Load a TypeScript workflow/config module by direct dynamic import.
@@ -1,7 +1,7 @@
1
1
  import "../chunk-gOLHoazu.js";
2
+ import path from "node:path";
2
3
  import { existsSync } from "node:fs";
3
4
  import { readFile } from "node:fs/promises";
4
- import path from "node:path";
5
5
  import { logger } from "@kici-dev/core";
6
6
  //#region src/execution/sdk-alias.ts
7
7
  /**
@@ -1,8 +1,8 @@
1
1
  import "../chunk-gOLHoazu.js";
2
2
  import { ensureTsLoaderHook } from "../execution/ts-loader.js";
3
- import fs from "node:fs/promises";
4
- import path from "node:path";
5
3
  import { fileURLToPath, pathToFileURL } from "node:url";
4
+ import path from "node:path";
5
+ import fs from "node:fs/promises";
6
6
  import picomatch from "picomatch";
7
7
  //#region src/fixtures/compiler.ts
8
8
  /**
@@ -1,7 +1,7 @@
1
1
  import "../../chunk-gOLHoazu.js";
2
- import { readFileSync } from "node:fs";
3
- import { dirname, join } from "node:path";
4
2
  import { fileURLToPath } from "node:url";
3
+ import { dirname, join } from "node:path";
4
+ import { readFileSync } from "node:fs";
5
5
  //#region src/fixtures/defaults/index.ts
6
6
  /**
7
7
  * Built-in fixture registry for common GitHub webhook events.
@@ -1,6 +1,6 @@
1
1
  import "../chunk-gOLHoazu.js";
2
- import { readFile, stat } from "node:fs/promises";
3
2
  import path from "node:path";
3
+ import { readFile, stat } from "node:fs/promises";
4
4
  //#region src/hooks/detector.ts
5
5
  const TOOL_CONFIGS = [
6
6
  {
@@ -1,8 +1,8 @@
1
1
  import "../chunk-gOLHoazu.js";
2
2
  import { findGitDir } from "./detector.js";
3
3
  import { getHookTemplate, hasKiciHook } from "./templates.js";
4
- import { chmod, mkdir, readFile, stat, writeFile } from "node:fs/promises";
5
4
  import path from "node:path";
5
+ import { chmod, mkdir, readFile, stat, writeFile } from "node:fs/promises";
6
6
  import { exec } from "node:child_process";
7
7
  import { promisify } from "node:util";
8
8
  //#region src/hooks/installer.ts
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { validateConfig } from './validation/index.js';
4
4
  export type { ValidationResult } from './validation/index.js';
5
5
  export { generateLockFile, serializeLockFile } from './lockfile/index.js';
6
6
  export { SCHEMA_VERSION, isLockStaticJob } from './types.js';
7
- export type { LockFile, LockWorkflow, LockJob, LockDynamicJobFn, LockJobOrFactory, LockTrigger, LockPrTrigger, LockPushTrigger, LockMatrix, LockRule, LockStep, LockSource, LockBranchPattern, } from './types.js';
7
+ export type { LockFile, LockWorkflow, LockJob, LockDynamicJobFn, LockJobOrFactory, LockTrigger, LockPrTrigger, LockPushTrigger, LockMatrix, LockRule, LockStep, LockApproval, LockSource, LockBranchPattern, } from './types.js';
8
8
  export { formatError, compilerError, isCompilerError } from './errors/index.js';
9
9
  export type { SourceLocation, CompilerError } from './errors/index.js';
10
10
  export { CapabilityGapError, formatCapabilityGapError } from './errors/index.js';