@kici-dev/compiler 0.5.0 → 0.6.1
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/dist/cli.js +46 -8
- package/dist/commands/approve.d.ts +12 -0
- package/dist/commands/approve.js +5 -2
- package/dist/commands/compile.js +4 -2
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/endpoints.js +4 -6
- package/dist/commands/feedback.d.ts +53 -0
- package/dist/commands/feedback.js +142 -0
- package/dist/commands/held-run-client.d.ts +21 -1
- package/dist/commands/held-run-client.js +34 -15
- package/dist/commands/hook.js +22 -20
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.js +3 -1
- package/dist/commands/init.d.ts +9 -2
- package/dist/commands/init.js +43 -16
- package/dist/commands/login.js +1 -1
- package/dist/commands/orchestrators.js +3 -2
- package/dist/commands/reject.d.ts +12 -0
- package/dist/commands/reject.js +5 -2
- package/dist/commands/report/collect.d.ts +82 -0
- package/dist/commands/report/collect.js +234 -0
- package/dist/commands/report/identity.d.ts +48 -0
- package/dist/commands/report/identity.js +49 -0
- package/dist/commands/report/index.d.ts +63 -0
- package/dist/commands/report/index.js +119 -0
- package/dist/commands/report/upload.d.ts +38 -0
- package/dist/commands/report/upload.js +64 -0
- package/dist/commands/run-hold-watch.js +2 -2
- package/dist/commands/run.js +6 -3
- package/dist/commands/runs/show.js +80 -1
- package/dist/commands/types.js +51 -8
- package/dist/execution/sdk-alias.js +4 -2
- package/dist/fixtures/compiler.js +2 -1
- package/dist/format.js +3 -3
- package/dist/generators/secrets-dts.d.ts +8 -2
- package/dist/generators/secrets-dts.js +3 -2
- package/dist/hooks/installer.js +2 -1
- package/dist/llm-context/llms-architecture.txt +35 -13
- package/dist/llm-context/llms-cli-remote.txt +2347 -0
- package/dist/llm-context/llms-cli.txt +284 -2470
- package/dist/llm-context/llms-features-execution.txt +2028 -0
- package/dist/llm-context/llms-features.txt +298 -1483
- package/dist/llm-context/llms-full.txt +6153 -4639
- package/dist/llm-context/llms-getting-started.txt +292 -12
- package/dist/llm-context/llms-patterns.txt +176 -1
- package/dist/llm-context/llms-providers.txt +11 -27
- package/dist/llm-context/llms-sdk-runtime.txt +25 -4
- package/dist/llm-context/llms-sdk.txt +31 -1
- package/dist/llm-context/llms.txt +33 -18
- package/dist/local-plane/paths.d.ts +15 -0
- package/dist/local-plane/paths.js +22 -1
- package/dist/local-plane/plane-manager.js +2 -2
- package/dist/local-plane/port-holder.js +1 -1
- package/dist/local-plane/postgres.d.ts +3 -16
- package/dist/local-plane/postgres.js +10 -15
- package/dist/lockfile/generator.d.ts +12 -0
- package/dist/lockfile/generator.js +47 -14
- package/dist/postinstall.js +2 -1
- package/dist/remote/config.d.ts +2 -15
- package/dist/remote/config.js +2 -16
- package/dist/remote/dashboard-client.d.ts +39 -0
- package/dist/remote/dashboard-client.js +41 -0
- package/dist/remote/oauth.js +7 -5
- package/dist/remote/uploader.js +2 -2
- package/dist/templates/package-json.js +1 -1
- package/dist/test-runner/dry-run.js +4 -2
- package/dist/test-runner/git-detector.js +2 -1
- package/dist/test-runner/job-executor.js +2 -1
- package/dist/test-runner/payload-builder.js +11 -17
- package/dist/types.d.ts +33 -3
- package/dist/validation/validator.js +23 -6
- package/package.json +16 -11
- package/sbom.spdx.json +953 -901
|
@@ -109,7 +109,7 @@ An orchestrator enforces a few limits, each surfaced as a clear step error when
|
|
|
109
109
|
- A **per-org storage quota** (20 GiB by default) across all non-expired artifacts.
|
|
110
110
|
- An **expiry** (30 days by default) after which an artifact is no longer downloadable or listed.
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
Each of the four is a cluster-wide default an operator can raise or lower per organization; see the [orchestrator storage layout](https://docs.kici.dev/operator/orchestrator/storage-layout/#artifacts) for the operator-facing knobs.
|
|
113
113
|
|
|
114
114
|
When an upload or download fails for a reason that is **not** one of these limits — the orchestrator has no artifact storage configured, or it could not service the request — the step error says exactly that, instead of reporting a quota rejection or a missing artifact. So an error that names a limit really is a limit you can act on, and an error that names an orchestrator problem is one to take to whoever runs it.
|
|
115
115
|
|
|
@@ -266,7 +266,7 @@ Source: https://docs.kici.dev/user/sdk/event-payloads/
|
|
|
266
266
|
|
|
267
267
|
## The envelope
|
|
268
268
|
|
|
269
|
-
The normalized event envelope is the single event contract in KiCI. Rules receive it as `ctx.event`, and every dynamic function — `
|
|
269
|
+
The normalized event envelope is the single event contract in KiCI. Rules receive it as `ctx.event`, and every dynamic function — `context:`, `env:`, and `concurrencyGroup:` resolvers, generated jobs, and a workflow's `concurrency.group` — receives the same envelope as its argument.
|
|
270
270
|
|
|
271
271
|
Narrow on the `type` field to branch per trigger kind (`if (event.type === 'push')`). The raw provider webhook body is nested at `payload`; the typed variants below describe its shape per event type.
|
|
272
272
|
|
|
@@ -712,7 +712,7 @@ export const setup = job('setup', {
|
|
|
712
712
|
|
|
713
713
|
## `checkStep(name, options)`
|
|
714
714
|
|
|
715
|
-
The check-mode-aware sibling of `idempotentStep()`. It takes
|
|
715
|
+
The check-mode-aware sibling of `idempotentStep()`. It takes a closely related option shape, but behaves differently when a run is started in check mode (`kici run --check`):
|
|
716
716
|
|
|
717
717
|
| Factory | Behavior under `kici run --check` |
|
|
718
718
|
| ---------------- | ----------------------------------------- |
|
|
@@ -730,10 +730,16 @@ Use `checkStep()` for deploy-style steps where you want a dry-run preview of pen
|
|
|
730
730
|
| `apply` | `(ctx, drift: TDrift) => Promise<TApplied>` | Yes | Brings the system to the desired state. Runs only in apply mode (skipped under `kici run --check`). |
|
|
731
731
|
| `summarize` | `(drift: TDrift) => string` | Yes | Human-readable summary of what `apply()` would do; shown in check-mode drift output. |
|
|
732
732
|
| `whenInSync` | `(ctx) => Promise<TInSync>` | No | Runs when `check()` returned `null` (already in sync). |
|
|
733
|
+
| `outputs` | `OutputSchema` | No | Zod schema validating the step's outputs at runtime. |
|
|
733
734
|
| `continueOnError` | `boolean` | No | When true, the job proceeds even if this step fails. |
|
|
734
735
|
| `timeout` | `number` | No | Step-level timeout in milliseconds. |
|
|
736
|
+
| `retry` | `number \| RetryConfig` | No | Retry policy for the step; `retry: N` is shorthand for `{ maxAttempts: N }`. |
|
|
737
|
+
| `cache` | `CacheInput` | No | Declarative cache restored before the step and saved after it succeeds. |
|
|
738
|
+
| `rules` | `Rule[]` | No | Step-level conditional rules, evaluated agent-side. |
|
|
735
739
|
|
|
736
|
-
|
|
740
|
+
Everything from `outputs` down is a plain [`step()` option](https://docs.kici.dev/user/sdk/core/) forwarded to the underlying step. The three step options `checkStep` does **not** accept are `onCancel`, `cleanup`, and `approval`.
|
|
741
|
+
|
|
742
|
+
There are two signature differences from `idempotentStep`. First, `apply` and `whenInSync` receive `ctx` as their first argument, so the apply logic has access to `ctx.$`, `ctx.log`, and `ctx.secrets`. Second, `summarize` is **required** here, because it is what check mode prints; `idempotentStep` defaults it to a JSON dump of the drift. `idempotentStep` also takes none of the step-option passthroughs above.
|
|
737
743
|
|
|
738
744
|
### Result
|
|
739
745
|
|
|
@@ -841,6 +847,21 @@ const patch = job('patch', {
|
|
|
841
847
|
});
|
|
842
848
|
```
|
|
843
849
|
|
|
850
|
+
### Which hosts are targets
|
|
851
|
+
|
|
852
|
+
`runsOnAll` targets the hosts you declare as members of your fleet. A host becomes
|
|
853
|
+
a target when it registers with the orchestrator under a stable agent identity, or
|
|
854
|
+
when an operator declares it with `kici-admin host declare`.
|
|
855
|
+
|
|
856
|
+
Agents that an auto-scaler starts are **not** targets, even when their labels match
|
|
857
|
+
the predicate. An auto-scaler starts an agent at the fixed shape of its pool, so a
|
|
858
|
+
pinned child would run at that shape and not at its own. Auto-scaler agents stay
|
|
859
|
+
available to `runsOn` and to the queue, and `ctx.kici.inventory` continues to list
|
|
860
|
+
them.
|
|
861
|
+
|
|
862
|
+
The fleet preview and the host detail page in the web UI apply the same rule, so
|
|
863
|
+
they show the hosts a run targets.
|
|
864
|
+
|
|
844
865
|
### Input forms
|
|
845
866
|
|
|
846
867
|
`runsOnAll` accepts three shapes:
|
|
@@ -961,7 +961,7 @@ Source: https://docs.kici.dev/user/sdk/rules-matrix-dynamic/
|
|
|
961
961
|
|
|
962
962
|
Rules control conditional execution of workflows and jobs. A rule that returns `false` (or whose check function returns `false`) prevents execution.
|
|
963
963
|
|
|
964
|
-
A rule's check function that **returns `false`** cleanly skips the job or step. A check function that **throws**
|
|
964
|
+
A rule's check function that **returns `false`** cleanly skips the job or step. A check function that **throws** counts as an evaluation failure, not a skip. The job or step **fails** with the error surfaced (both on a remote run and when running locally with `kici run --local`), so a broken rule can never silently pass as a green run. For example, `rule('main only', (ctx) => ctx.event.ref.endsWith('main'))` throws on an event whose `ref` is undefined — that run fails with the error instead of quietly skipping every step. Fix the thrown error (guard the access) rather than relying on the skip.
|
|
965
965
|
|
|
966
966
|
### rule(label) / rule(label, check)
|
|
967
967
|
|
|
@@ -2435,6 +2435,36 @@ workflow('post-deploy', {
|
|
|
2435
2435
|
|
|
2436
2436
|
The orchestrator automatically emits system events for workflow and job completions. You do not need to call `ctx.emit()` for these -- they are generated by the orchestrator after execution. Listen for them with `workflowComplete()` and `jobComplete()` triggers.
|
|
2437
2437
|
|
|
2438
|
+
### Event scaler events
|
|
2439
|
+
|
|
2440
|
+
The [event scaler backend](https://docs.kici.dev/operator/orchestrator/event-scaler/) emits two reserved events that your provisioning and teardown workflows subscribe to. The SDK exports their names and payload schemas, so a workflow imports the contract instead of re-declaring it.
|
|
2441
|
+
|
|
2442
|
+
| Export | What it is |
|
|
2443
|
+
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
|
|
2444
|
+
| `SCALER_EVENT_NAMES` | The two reserved event names: `SCALER_EVENT_NAMES.scaleUp` and `SCALER_EVENT_NAMES.scaleDown`. |
|
|
2445
|
+
| `ScalerScaleUpPayload` | Schema of the scale-up payload. `.parse(ctx.rawPayload)` returns the typed payload and rejects a malformed one. |
|
|
2446
|
+
| `ScalerScaleDownPayload` | Schema of the scale-down payload, including the narrowed `reason`. |
|
|
2447
|
+
| `ScaleDownReason` | Why the scaler asked for a teardown: `idle`, `job-complete`, `heartbeat-timeout`, `spawn-timeout`, `drain`, `shutdown`. |
|
|
2448
|
+
|
|
2449
|
+
```ts
|
|
2450
|
+
import { workflow, job, kiciEvent, SCALER_EVENT_NAMES, ScalerScaleUpPayload } from '@kici-dev/sdk';
|
|
2451
|
+
|
|
2452
|
+
export default workflow('provision', {
|
|
2453
|
+
on: [kiciEvent({ name: SCALER_EVENT_NAMES.scaleUp, match: { '$.scalerName': 'hetzner' } })],
|
|
2454
|
+
jobs: [
|
|
2455
|
+
job('provision', {
|
|
2456
|
+
runsOn: ['kici:os:linux'],
|
|
2457
|
+
run: async (ctx) => {
|
|
2458
|
+
const payload = ScalerScaleUpPayload.parse(ctx.rawPayload);
|
|
2459
|
+
ctx.log.info(`provision agent ${payload.agentId}`);
|
|
2460
|
+
},
|
|
2461
|
+
}),
|
|
2462
|
+
],
|
|
2463
|
+
});
|
|
2464
|
+
```
|
|
2465
|
+
|
|
2466
|
+
These names are reserved. `ctx.emit()` rejects any event name that starts with `kici.`, so a workflow step cannot forge a scaler event. For every payload field, see the [event contract reference](https://docs.kici.dev/operator/orchestrator/event-scaler-events/). For complete provisioning and teardown workflows, see [autoscaling workflows](https://docs.kici.dev/user/workflows/autoscaling-workflows/).
|
|
2467
|
+
|
|
2438
2468
|
---
|
|
2439
2469
|
|
|
2440
2470
|
## SDK reference
|
|
@@ -4,32 +4,39 @@
|
|
|
4
4
|
|
|
5
5
|
The full markdown bundle of every page indexed here is available at https://docs.kici.dev/llms-full.txt.
|
|
6
6
|
|
|
7
|
+
Found a mismatch between what these docs advertise and what KiCI does? Read https://docs.kici.dev/user/reporting-discrepancies/ (or run `kici feedback`) before reporting it: a report needs a reproduction, and you draft it but a human decides to file it.
|
|
8
|
+
|
|
7
9
|
## Bundles
|
|
8
10
|
|
|
9
11
|
Each bundle below is a self-contained markdown file for one authoring task. Fetch only the one your task needs instead of the full bundle:
|
|
10
12
|
|
|
11
|
-
- [getting-started](https://docs.kici.dev/llms-getting-started.txt) (
|
|
12
|
-
- [patterns](https://docs.kici.dev/llms-patterns.txt) (
|
|
13
|
-
- [sdk](https://docs.kici.dev/llms-sdk.txt) (
|
|
14
|
-
- [sdk-runtime](https://docs.kici.dev/llms-sdk-runtime.txt) (
|
|
15
|
-
- [cli](https://docs.kici.dev/llms-cli.txt) (
|
|
16
|
-
- [
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
13
|
+
- [getting-started](https://docs.kici.dev/llms-getting-started.txt) (65 KB) — Adopt KiCI: why it exists, how workflows execute, migrating from GitHub Actions, installing the SDK, and writing/compiling/testing your first workflow
|
|
14
|
+
- [patterns](https://docs.kici.dev/llms-patterns.txt) (57 KB) — Copy-paste workflow recipes: triggers, conditionals, matrix, scheduling, integrations
|
|
15
|
+
- [sdk](https://docs.kici.dev/llms-sdk.txt) (127 KB) — Core authoring API: workflow/job/step factories, triggers, rules, matrix, dynamic jobs, cross-job outputs
|
|
16
|
+
- [sdk-runtime](https://docs.kici.dev/llms-sdk-runtime.txt) (114 KB) — Runtime and advanced authoring: step runtime context, event payloads, host fan-out, idempotent steps, caching, artifacts, waiting
|
|
17
|
+
- [cli](https://docs.kici.dev/llms-cli.txt) (90 KB) — Running the CLI locally: compile, test, run local, hooks, lock-file drift, common failures
|
|
18
|
+
- [cli-remote](https://docs.kici.dev/llms-cli-remote.txt) (106 KB) — Auth, org and orchestrator selection, runs, approvals, notifications, diagnostics, and the MCP server a coding agent connects to
|
|
19
|
+
- [features](https://docs.kici.dev/llms-features.txt) (90 KB) — Deployment contexts, scoped secrets, private registries, approvals, provenance, dashboard and account access
|
|
20
|
+
- [features-execution](https://docs.kici.dev/llms-features-execution.txt) (121 KB) — Concurrency, dynamic values, events, container jobs, environment variables, global workflows, idempotent steps
|
|
21
|
+
- [providers](https://docs.kici.dev/llms-providers.txt) (35 KB) — Connecting sources: GitHub App, universal-git (Forgejo/Gitea/GitLab), local file://
|
|
22
|
+
- [architecture](https://docs.kici.dev/llms-architecture.txt) (99 KB) — How the runtime works: three-tier relay model, data flows, configuration
|
|
19
23
|
|
|
20
24
|
## Getting started
|
|
21
25
|
|
|
22
26
|
- [User guide](https://docs.kici.dev/user/): Writing and testing CI/CD workflows in TypeScript, running on infrastructure you control
|
|
23
27
|
- [How your workflow code executes](https://docs.kici.dev/user/execution-model/): When and where your workflow TypeScript runs — compile time, orchestrator time, and agent time
|
|
28
|
+
- [Getting help](https://docs.kici.dev/user/getting-help/): How to report a problem to KiCI and send the diagnostic context privately
|
|
24
29
|
- [Getting started with workflows](https://docs.kici.dev/user/getting-started/): Install the SDK, write your first workflow, compile and test locally
|
|
25
30
|
- [Migrating from GitHub Actions](https://docs.kici.dev/user/migrating-from-github-actions/): Map GitHub Actions concepts to KiCI, translate a real workflow side-by-side, and see what has no equivalent yet
|
|
26
31
|
- [5-minute quickstart](https://docs.kici.dev/user/quickstart/): Stand up a KiCI orchestrator + agent and run your first workflow
|
|
32
|
+
- [Reporting a discrepancy](https://docs.kici.dev/user/reporting-discrepancies/): For coding agents — how to report a mismatch between what KiCI's docs advertise and what the tooling does, with the reproduction and the approval a report needs.
|
|
27
33
|
- [Why KiCI](https://docs.kici.dev/user/why-kici/): The case for running CI on infrastructure you control, with typed TypeScript workflows you test locally
|
|
28
34
|
|
|
29
35
|
## Workflow patterns
|
|
30
36
|
|
|
31
37
|
- [Basic workflow patterns](https://docs.kici.dev/user/patterns/basic/): Basic CI, PR-only / push-only filters, multiple triggers, manual-only workflows
|
|
32
38
|
- [Conditionals & matrix patterns](https://docs.kici.dev/user/patterns/conditionals-matrix/): Conditional execution with rules, matrix builds (static + dynamic), dynamic job generation
|
|
39
|
+
- [Git credentials](https://docs.kici.dev/user/patterns/git-credentials/): Authenticated git in a workflow — declaring credentials from the secrets backend, and pushing
|
|
33
40
|
- [Host restart & wait-for-alive](https://docs.kici.dev/user/patterns/host-restart/): Reboot the host a workflow runs on and continue after it comes back
|
|
34
41
|
- [Integration patterns](https://docs.kici.dev/user/patterns/integrations/): Workflow chaining, generic webhooks, Stripe, self-hosted git forges, plain GitHub repos
|
|
35
42
|
- [Pattern reference](https://docs.kici.dev/user/patterns/reference/): Step context, examples repository, GitHub check run output — cross-cutting reference for all patterns
|
|
@@ -55,36 +62,44 @@ Each bundle below is a self-contained markdown file for one authoring task. Fetc
|
|
|
55
62
|
- [SDK reference: temp directories](https://docs.kici.dev/user/sdk/temp-directories/): Allocate job-scoped scratch dirs and files with ctx.mktemp() / ctx.mktempFile()
|
|
56
63
|
- [SDK reference: waitFor](https://docs.kici.dev/user/sdk/wait-for/): Polling helpers for steps that pause until an external condition becomes true
|
|
57
64
|
|
|
58
|
-
## CLI
|
|
65
|
+
## CLI: authoring on your own machine
|
|
59
66
|
|
|
60
|
-
- [
|
|
61
|
-
- [CLI authentication](https://docs.kici.dev/user/cli-auth/): Authenticate the KiCI CLI with browser OAuth, device flow, or API key paste
|
|
62
|
-
- [CLI reference](https://docs.kici.dev/user/cli-reference/): All CLI commands: compile, preview, local, fixture, types, workflows, hook, docs, run, runs, approve, reject, login, logout, init, org, pat, secrets, admin, orchestrators, endpoints, notifications, verify-attestation, diagnostics, doctor
|
|
67
|
+
- [CLI reference](https://docs.kici.dev/user/cli-reference/): All CLI commands: compile, preview, local, fixture, types, workflows, hook, docs, run, runs, approve, reject, login, logout, init, org, pat, secrets, admin, orchestrators, endpoints, notifications, verify-attestation, diagnostics, doctor, report, feedback
|
|
63
68
|
- [Common failures](https://docs.kici.dev/user/common-failures/): Symptom-to-fix reference for the failures workflow authors hit most — no jobs dispatched, lock-file drift, missing webhooks, and agents that won't connect
|
|
64
69
|
- [Lifecycle hooks](https://docs.kici.dev/user/hooks/): SDK hook API for cancel, cleanup, success, failure, and step-level callbacks
|
|
65
70
|
- [Lock file and workflow drift](https://docs.kici.dev/user/lock-file-and-drift/): Keep the lock file in sync with your workflow source and avoid drift
|
|
66
71
|
- [Testing guide](https://docs.kici.dev/user/testing-guide/): Running remote test fixtures with kici run remote
|
|
67
72
|
- [Workflow patterns](https://docs.kici.dev/user/workflow-patterns/): Common patterns: monorepo builds, conditional jobs, dynamic matrices, generic webhooks, scheduling
|
|
68
|
-
- [kici: account & org](https://docs.kici.dev/user/cli/account-and-org/): Login, org selection, personal access tokens, secrets, and admin
|
|
69
73
|
- [kici: authoring & local dev](https://docs.kici.dev/user/cli/authoring-and-local/): Compile, preview, local execution, fixtures, types, workflows, hooks, and docs
|
|
74
|
+
|
|
75
|
+
## CLI: driving a deployed orchestrator
|
|
76
|
+
|
|
77
|
+
- [Drive KiCI from your coding agent](https://docs.kici.dev/user/ai-agents/): Point a coding agent at KiCI's MCP server and let it trigger, read, and re-run your CI under your own identity.
|
|
78
|
+
- [CLI authentication](https://docs.kici.dev/user/cli-auth/): Authenticate the KiCI CLI with browser OAuth, device flow, or API key paste
|
|
79
|
+
- [kici: account & org](https://docs.kici.dev/user/cli/account-and-org/): Login, org selection, personal access tokens, secrets, and admin
|
|
70
80
|
- [kici: notifications & diagnostics](https://docs.kici.dev/user/cli/notifications-and-diagnostics/): Notification channels, attestation verification, and diagnostics
|
|
71
81
|
- [kici: runs & approvals](https://docs.kici.dev/user/cli/runs-and-approvals/): Run push and inspection plus approval / rejection of held runs
|
|
72
82
|
|
|
73
|
-
## Workflow features
|
|
83
|
+
## Workflow features: access and approval
|
|
74
84
|
|
|
75
85
|
- [Account and sign-in](https://docs.kici.dev/user/account-and-login/): How your KiCI account relates to sign-in methods, and how to change the way you sign in.
|
|
76
86
|
- [Approval gates](https://docs.kici.dev/user/approvals/): Pause a workflow for human sign-off at step, job, or workflow granularity with approval
|
|
77
|
-
- [Concurrency groups](https://docs.kici.dev/user/concurrency/): Control parallel execution with auto-cancel and queue modes
|
|
78
87
|
- [Contexts](https://docs.kici.dev/user/contexts/): Configure deployment contexts with variables, secrets, and protection rules
|
|
79
88
|
- [Dashboard](https://docs.kici.dev/user/dashboard/): Web UI for monitoring workflow runs, managing sources, secrets, and organization settings.
|
|
89
|
+
- [Private npm registries](https://docs.kici.dev/user/private-registries/): Authenticate `npm install` against private registries (CodeArtifact, GitHub Packages, Verdaccio, …) from a workflow's `.kici/package.json`
|
|
90
|
+
- [Build provenance and attestations](https://docs.kici.dev/user/provenance/): Generate and verify signed SLSA provenance for the artifacts your workflows build
|
|
91
|
+
- [Secrets](https://docs.kici.dev/user/secrets/): How to access secrets in KiCI workflow steps
|
|
92
|
+
|
|
93
|
+
## Workflow features: execution
|
|
94
|
+
|
|
95
|
+
- [Concurrency groups](https://docs.kici.dev/user/concurrency/): Control parallel execution with auto-cancel and queue modes
|
|
96
|
+
- [Container jobs](https://docs.kici.dev/user/container-jobs/): Run a job inside any container image, including a private one, without that image shipping Node or git
|
|
80
97
|
- [Dynamic values](https://docs.kici.dev/user/dynamic-values/): Compute a job's context, env, and concurrencyGroup at runtime from the incoming event
|
|
81
98
|
- [Environment variables](https://docs.kici.dev/user/env-vars/): Environment variable reference for the CLI
|
|
82
99
|
- [Event system](https://docs.kici.dev/user/events/): How KiCI's event model works -- event types, the registration model, event matching, and circuit breaker protection
|
|
83
100
|
- [Global workflows](https://docs.kici.dev/user/global-workflows/): Cross-repo workflows that run on events from any repo in the same org
|
|
84
101
|
- [Idempotent steps and check mode](https://docs.kici.dev/user/idempotent-steps/): Declare desired state with a step check facet, then run in apply or --check preview mode
|
|
85
|
-
- [
|
|
86
|
-
- [Build provenance and attestations](https://docs.kici.dev/user/provenance/): Generate and verify signed SLSA provenance for the artifacts your workflows build
|
|
87
|
-
- [Secrets](https://docs.kici.dev/user/secrets/): How to access secrets in KiCI workflow steps
|
|
102
|
+
- [Autoscaling workflows](https://docs.kici.dev/user/workflows/autoscaling-workflows/): Write TypeScript provisioning and teardown workflows that boot and delete ephemeral cloud agents in response to the event scaler
|
|
88
103
|
|
|
89
104
|
## Providers
|
|
90
105
|
|
|
@@ -7,6 +7,21 @@ export declare const PLANE_STAMP_VERSION = 3;
|
|
|
7
7
|
/**
|
|
8
8
|
* Root directory of the local dev plane's state, following the same
|
|
9
9
|
* `KICI_CONFIG_DIR` → `~/.kici` convention the rest of the CLI uses.
|
|
10
|
+
*
|
|
11
|
+
* RESOLVED THROUGH SYMLINKS, deliberately. The plane is a singleton on fixed
|
|
12
|
+
* ports, so a caller may reach it through a config dir that only symlinks
|
|
13
|
+
* `local` at the durable one — `pnpm deploy:stg` does exactly that, to run
|
|
14
|
+
* against a throwaway config dir carrying no credentials while still reusing
|
|
15
|
+
* the warm plane.
|
|
16
|
+
*
|
|
17
|
+
* Without resolving, the plane's Postgres is started with a data directory
|
|
18
|
+
* addressed through that ephemeral path and keeps it open. When the caller
|
|
19
|
+
* removes its temp dir, Postgres PANICs — `could not open file
|
|
20
|
+
* "<tmp>/local/pgdata/global/pg_control"` — and shuts the whole plane down,
|
|
21
|
+
* taking every later phase with it. Resolving first means Postgres only ever
|
|
22
|
+
* sees the durable path, so a caller's temp dir can come and go beneath it.
|
|
23
|
+
*
|
|
24
|
+
* A path that does not exist yet resolves to itself: a fresh plane creates it.
|
|
10
25
|
*/
|
|
11
26
|
export declare function planeRoot(): string;
|
|
12
27
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import fs from "node:fs";
|
|
3
4
|
import os from "node:os";
|
|
4
5
|
//#region src/local-plane/paths.ts
|
|
5
6
|
/**
|
|
@@ -11,10 +12,30 @@ const PLANE_STAMP_VERSION = 3;
|
|
|
11
12
|
/**
|
|
12
13
|
* Root directory of the local dev plane's state, following the same
|
|
13
14
|
* `KICI_CONFIG_DIR` → `~/.kici` convention the rest of the CLI uses.
|
|
15
|
+
*
|
|
16
|
+
* RESOLVED THROUGH SYMLINKS, deliberately. The plane is a singleton on fixed
|
|
17
|
+
* ports, so a caller may reach it through a config dir that only symlinks
|
|
18
|
+
* `local` at the durable one — `pnpm deploy:stg` does exactly that, to run
|
|
19
|
+
* against a throwaway config dir carrying no credentials while still reusing
|
|
20
|
+
* the warm plane.
|
|
21
|
+
*
|
|
22
|
+
* Without resolving, the plane's Postgres is started with a data directory
|
|
23
|
+
* addressed through that ephemeral path and keeps it open. When the caller
|
|
24
|
+
* removes its temp dir, Postgres PANICs — `could not open file
|
|
25
|
+
* "<tmp>/local/pgdata/global/pg_control"` — and shuts the whole plane down,
|
|
26
|
+
* taking every later phase with it. Resolving first means Postgres only ever
|
|
27
|
+
* sees the durable path, so a caller's temp dir can come and go beneath it.
|
|
28
|
+
*
|
|
29
|
+
* A path that does not exist yet resolves to itself: a fresh plane creates it.
|
|
14
30
|
*/
|
|
15
31
|
function planeRoot() {
|
|
16
32
|
const base = process.env.KICI_CONFIG_DIR ?? path.join(os.homedir(), ".kici");
|
|
17
|
-
|
|
33
|
+
const root = path.join(base, "local");
|
|
34
|
+
try {
|
|
35
|
+
return fs.realpathSync(root);
|
|
36
|
+
} catch {
|
|
37
|
+
return root;
|
|
38
|
+
}
|
|
18
39
|
}
|
|
19
40
|
/**
|
|
20
41
|
* Absolute paths for every artefact the plane persists under its state root.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* `TS_CONST_PINS` in hack/containers-lock.ts (identity
|
|
4
4
|
* docker.io/library/postgres+alpine), so a lock bump rewrites it in place.
|
|
5
5
|
*/
|
|
6
|
-
export declare const PLANE_PG_IMAGE = "docker.io/library/postgres:18.
|
|
6
|
+
export declare const PLANE_PG_IMAGE = "docker.io/library/postgres:18.6-alpine";
|
|
7
7
|
/** Name of the fallback podman Postgres container. */
|
|
8
8
|
export declare const PLANE_PG_CONTAINER = "kici-local-postgres";
|
|
9
9
|
export type PlanePgHandle = {
|
|
@@ -11,13 +11,6 @@ export type PlanePgHandle = {
|
|
|
11
11
|
kind: 'embedded' | 'podman';
|
|
12
12
|
stop(): Promise<void>;
|
|
13
13
|
};
|
|
14
|
-
declare let readyPoller: typeof defaultReadyPoller;
|
|
15
|
-
/** Test seam: override the podman readiness poller. */
|
|
16
|
-
export declare function __setReadyPollerForTest(fn: typeof readyPoller): void;
|
|
17
|
-
declare let embeddedDaemon: typeof defaultEmbeddedDaemon;
|
|
18
|
-
/** Test seam: override the embedded postmaster daemonizer. */
|
|
19
|
-
export declare function __setEmbeddedDaemonForTest(fn: typeof embeddedDaemon): void;
|
|
20
|
-
declare function defaultReadyPoller(_port: number): Promise<boolean>;
|
|
21
14
|
/**
|
|
22
15
|
* Whether this plane's embedded postmaster is already serving `port`.
|
|
23
16
|
*
|
|
@@ -31,13 +24,6 @@ declare function defaultReadyPoller(_port: number): Promise<boolean>;
|
|
|
31
24
|
* one this plane can reuse.
|
|
32
25
|
*/
|
|
33
26
|
export declare function embeddedClusterIsServing(port: number): Promise<boolean>;
|
|
34
|
-
/**
|
|
35
|
-
* Start a detached embedded postmaster via `pg_ctl` so it survives the exit of
|
|
36
|
-
* this CLI process (embedded-postgres's in-process server is killed by its own
|
|
37
|
-
* exit hook, so it cannot back a warm plane). A cluster already serving this
|
|
38
|
-
* plane's port is reused as-is.
|
|
39
|
-
*/
|
|
40
|
-
declare function defaultEmbeddedDaemon(port: number): Promise<void>;
|
|
41
27
|
/**
|
|
42
28
|
* Stop the plane's Postgres by backend kind. Handle-independent so a separate
|
|
43
29
|
* CLI invocation (`kici local down`) can tear down what `up` started.
|
|
@@ -51,6 +37,7 @@ export declare function stopPlanePostgres(kind: 'embedded' | 'podman'): Promise<
|
|
|
51
37
|
*/
|
|
52
38
|
export declare function startPlanePostgres(opts?: {
|
|
53
39
|
forcePodman?: boolean;
|
|
40
|
+
readyPoller?: (port: number) => Promise<boolean>;
|
|
41
|
+
embeddedDaemon?: (port: number) => Promise<void>;
|
|
54
42
|
}): Promise<PlanePgHandle>;
|
|
55
|
-
export {};
|
|
56
43
|
//# sourceMappingURL=postgres.d.ts.map
|
|
@@ -13,19 +13,9 @@ import EmbeddedPostgres from "embedded-postgres";
|
|
|
13
13
|
* `TS_CONST_PINS` in hack/containers-lock.ts (identity
|
|
14
14
|
* docker.io/library/postgres+alpine), so a lock bump rewrites it in place.
|
|
15
15
|
*/
|
|
16
|
-
const PLANE_PG_IMAGE = "docker.io/library/postgres:18.
|
|
16
|
+
const PLANE_PG_IMAGE = "docker.io/library/postgres:18.6-alpine";
|
|
17
17
|
/** Name of the fallback podman Postgres container. */
|
|
18
18
|
const PLANE_PG_CONTAINER = "kici-local-postgres";
|
|
19
|
-
let readyPoller = defaultReadyPoller;
|
|
20
|
-
/** Test seam: override the podman readiness poller. */
|
|
21
|
-
function __setReadyPollerForTest(fn) {
|
|
22
|
-
readyPoller = fn;
|
|
23
|
-
}
|
|
24
|
-
let embeddedDaemon = defaultEmbeddedDaemon;
|
|
25
|
-
/** Test seam: override the embedded postmaster daemonizer. */
|
|
26
|
-
function __setEmbeddedDaemonForTest(fn) {
|
|
27
|
-
embeddedDaemon = fn;
|
|
28
|
-
}
|
|
29
19
|
async function defaultReadyPoller(_port) {
|
|
30
20
|
for (let i = 0; i < 60; i++) try {
|
|
31
21
|
await $`podman exec ${PLANE_PG_CONTAINER} pg_isready -U kici`.quiet();
|
|
@@ -56,7 +46,8 @@ function resolvePgCtl() {
|
|
|
56
46
|
"win32:x64": "@embedded-postgres/windows-x64"
|
|
57
47
|
}[`${platform}:${arch}`];
|
|
58
48
|
if (!pkg) throw new Error(`unsupported platform for embedded Postgres: ${platform}/${arch}`);
|
|
59
|
-
const
|
|
49
|
+
const require = createRequire(import.meta.url);
|
|
50
|
+
const entry = createRequire(require.resolve("embedded-postgres")).resolve(pkg);
|
|
60
51
|
const binName = platform === "win32" ? "pg_ctl.exe" : "pg_ctl";
|
|
61
52
|
return path.resolve(path.dirname(entry), "..", "native", "bin", binName);
|
|
62
53
|
}
|
|
@@ -119,13 +110,15 @@ async function embeddedClusterIsServing(port) {
|
|
|
119
110
|
async function defaultEmbeddedDaemon(port) {
|
|
120
111
|
const { pgData, logFile } = planePaths();
|
|
121
112
|
if (await embeddedClusterIsServing(port)) return;
|
|
122
|
-
|
|
113
|
+
const pgCtl = resolvePgCtl();
|
|
114
|
+
await $`${pgCtl} -D ${pgData} -o ${`-p ${port}`} -l ${`${logFile}.pg`} -w start`.quiet();
|
|
123
115
|
}
|
|
124
116
|
/** Stop the detached embedded postmaster (handle-independent, reads the data dir). */
|
|
125
117
|
async function stopEmbeddedDaemon() {
|
|
126
118
|
const { pgData } = planePaths();
|
|
127
119
|
if (!fs.existsSync(path.join(pgData, "postmaster.pid"))) return;
|
|
128
|
-
|
|
120
|
+
const pgCtl = resolvePgCtl();
|
|
121
|
+
await $`${pgCtl} -D ${pgData} stop -m fast`.quiet().catch(() => {});
|
|
129
122
|
}
|
|
130
123
|
/**
|
|
131
124
|
* Stop the plane's Postgres by backend kind. Handle-independent so a separate
|
|
@@ -142,6 +135,8 @@ async function stopPlanePostgres(kind) {
|
|
|
142
135
|
* (or when forced via `forcePodman` / `KICI_LOCAL_PG_MODE=podman`).
|
|
143
136
|
*/
|
|
144
137
|
async function startPlanePostgres(opts = {}) {
|
|
138
|
+
const readyPoller = opts.readyPoller ?? defaultReadyPoller;
|
|
139
|
+
const embeddedDaemon = opts.embeddedDaemon ?? defaultEmbeddedDaemon;
|
|
145
140
|
const { postgres: port } = planePorts();
|
|
146
141
|
const url = `postgres://kici:kici@127.0.0.1:${port}/kici_local`;
|
|
147
142
|
if (!(opts.forcePodman || process.env.KICI_LOCAL_PG_MODE === "podman")) try {
|
|
@@ -182,6 +177,6 @@ async function startPlanePostgres(opts = {}) {
|
|
|
182
177
|
};
|
|
183
178
|
}
|
|
184
179
|
//#endregion
|
|
185
|
-
export { PLANE_PG_CONTAINER, PLANE_PG_IMAGE,
|
|
180
|
+
export { PLANE_PG_CONTAINER, PLANE_PG_IMAGE, embeddedClusterIsServing, startPlanePostgres, stopPlanePostgres };
|
|
186
181
|
|
|
187
182
|
//# sourceMappingURL=postgres.js.map
|
|
@@ -36,6 +36,18 @@ export declare function detectGitRoot(): string;
|
|
|
36
36
|
* For yarn the prefix also carries the flavor (`yarn-classic` / `yarn-berry`),
|
|
37
37
|
* so a classic-layout dep-cache tarball is never restored into a berry install.
|
|
38
38
|
*
|
|
39
|
+
* The detected manager only orders the search; it never restricts it. Detection
|
|
40
|
+
* falls back to the AMBIENT `npm_config_user_agent` when a directory carries no
|
|
41
|
+
* signal of its own, so a repo whose root holds neither a `package.json` nor a
|
|
42
|
+
* lockfile is reported as whatever manager happened to invoke the compiler. A
|
|
43
|
+
* repo compiled under pnpm that keeps an npm `.kici/package-lock.json` was
|
|
44
|
+
* therefore searched for `pnpm-lock.yaml` only, found none, and got no hash at
|
|
45
|
+
* all — which silently disables the orchestrator's dependency cache for it, so
|
|
46
|
+
* every agent installs from the registry and an agent with no registry route
|
|
47
|
+
* cannot run the job at all. Searching every manager's candidates after the
|
|
48
|
+
* detected one's keeps the detected manager authoritative where it has real
|
|
49
|
+
* evidence, and still finds the lockfile that is actually on disk.
|
|
50
|
+
*
|
|
39
51
|
* @param gitRoot - Absolute path to git repository root
|
|
40
52
|
* @returns Hex SHA-256 hash string, or null if no lockfile is found
|
|
41
53
|
*/
|
|
@@ -66,16 +66,39 @@ function detectGitRoot() {
|
|
|
66
66
|
* For yarn the prefix also carries the flavor (`yarn-classic` / `yarn-berry`),
|
|
67
67
|
* so a classic-layout dep-cache tarball is never restored into a berry install.
|
|
68
68
|
*
|
|
69
|
+
* The detected manager only orders the search; it never restricts it. Detection
|
|
70
|
+
* falls back to the AMBIENT `npm_config_user_agent` when a directory carries no
|
|
71
|
+
* signal of its own, so a repo whose root holds neither a `package.json` nor a
|
|
72
|
+
* lockfile is reported as whatever manager happened to invoke the compiler. A
|
|
73
|
+
* repo compiled under pnpm that keeps an npm `.kici/package-lock.json` was
|
|
74
|
+
* therefore searched for `pnpm-lock.yaml` only, found none, and got no hash at
|
|
75
|
+
* all — which silently disables the orchestrator's dependency cache for it, so
|
|
76
|
+
* every agent installs from the registry and an agent with no registry route
|
|
77
|
+
* cannot run the job at all. Searching every manager's candidates after the
|
|
78
|
+
* detected one's keeps the detected manager authoritative where it has real
|
|
79
|
+
* evidence, and still finds the lockfile that is actually on disk.
|
|
80
|
+
*
|
|
69
81
|
* @param gitRoot - Absolute path to git repository root
|
|
70
82
|
* @returns Hex SHA-256 hash string, or null if no lockfile is found
|
|
71
83
|
*/
|
|
72
84
|
function computeLockfileHash(gitRoot) {
|
|
73
85
|
const pm = detectPackageManagerSync(gitRoot) === PackageManager.Npm ? detectPackageManagerSync(path.join(gitRoot, ".kici")) : detectPackageManagerSync(gitRoot);
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
86
|
+
const byManager = (m) => m === PackageManager.Pnpm ? [path.join(gitRoot, "pnpm-lock.yaml"), path.join(gitRoot, ".kici", "pnpm-lock.yaml")] : m === PackageManager.Yarn ? [path.join(gitRoot, "yarn.lock"), path.join(gitRoot, ".kici", "yarn.lock")] : [path.join(gitRoot, ".kici", "package-lock.json")];
|
|
87
|
+
const order = [pm, ...[
|
|
88
|
+
PackageManager.Npm,
|
|
89
|
+
PackageManager.Pnpm,
|
|
90
|
+
PackageManager.Yarn
|
|
91
|
+
].filter((m) => m !== pm)];
|
|
92
|
+
for (const manager of order) for (const lockfilePath of byManager(manager)) {
|
|
93
|
+
let content;
|
|
94
|
+
try {
|
|
95
|
+
content = readFileSync(lockfilePath, "utf-8");
|
|
96
|
+
} catch {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const prefix = manager === PackageManager.Yarn ? `${manager}-${detectYarnFlavorSync(path.dirname(lockfilePath))}` : manager;
|
|
100
|
+
return sha256(`${prefix}\n${content}`);
|
|
101
|
+
}
|
|
79
102
|
return null;
|
|
80
103
|
}
|
|
81
104
|
/**
|
|
@@ -112,16 +135,17 @@ function generateLockFile(workflowsWithSource) {
|
|
|
112
135
|
const workflows = workflowsWithSource.map(({ workflow, source, bundleSource }) => {
|
|
113
136
|
return transformWorkflow(workflow, path.relative(gitRoot, source.file).replaceAll("\\", "/"), formatExportRef(source), bundleSource, gitRoot);
|
|
114
137
|
});
|
|
138
|
+
const contentHash = sha256(JSON.stringify({
|
|
139
|
+
schemaVersion: SCHEMA_VERSION$1,
|
|
140
|
+
minReaderVersion: BREAKING_FLOOR$1,
|
|
141
|
+
source: topLevelSource,
|
|
142
|
+
workflows
|
|
143
|
+
}));
|
|
115
144
|
return {
|
|
116
145
|
schemaVersion: SCHEMA_VERSION$1,
|
|
117
146
|
minReaderVersion: BREAKING_FLOOR$1,
|
|
118
147
|
source: topLevelSource,
|
|
119
|
-
contentHash
|
|
120
|
-
schemaVersion: SCHEMA_VERSION$1,
|
|
121
|
-
minReaderVersion: BREAKING_FLOOR$1,
|
|
122
|
-
source: topLevelSource,
|
|
123
|
-
workflows
|
|
124
|
-
})),
|
|
148
|
+
contentHash,
|
|
125
149
|
...lockfileHash && { lockfileHash },
|
|
126
150
|
workflows
|
|
127
151
|
};
|
|
@@ -209,12 +233,14 @@ function serializeRegexEntry(entry, ctx) {
|
|
|
209
233
|
try {
|
|
210
234
|
re = new RegExp(pattern, flags);
|
|
211
235
|
} catch (err) {
|
|
212
|
-
|
|
236
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
237
|
+
throw compilerError("E123", `${ctx}: invalid regex — ${reason}`);
|
|
213
238
|
}
|
|
214
239
|
try {
|
|
215
240
|
assertSafeRegex(re.source, re.flags, ctx);
|
|
216
241
|
} catch (err) {
|
|
217
|
-
|
|
242
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
243
|
+
throw compilerError("E123", `${ctx}: ${reason}`);
|
|
218
244
|
}
|
|
219
245
|
return `/${re.source}/${re.flags}`;
|
|
220
246
|
}
|
|
@@ -660,7 +686,7 @@ function transformJob(job, configPath, index, gitRoot, uuidToName) {
|
|
|
660
686
|
location: jobLocation,
|
|
661
687
|
suggestion: "Set exactly one of runsOn (single agent) or runsOnAll (fan-out to every matching agent)."
|
|
662
688
|
});
|
|
663
|
-
if (job.runsOn === void 0 && job.runsOnAll === void 0) throw compilerError("E109", `job '${job.name}': one of runsOn or runsOnAll is required`, {
|
|
689
|
+
if (job.invoke === void 0 && job.runsOn === void 0 && job.runsOnAll === void 0) throw compilerError("E109", `job '${job.name}': one of runsOn or runsOnAll is required`, {
|
|
664
690
|
location: jobLocation,
|
|
665
691
|
suggestion: "Add runsOn: \"kici:os:linux\" (or another agent label) to the job."
|
|
666
692
|
});
|
|
@@ -700,8 +726,15 @@ function transformJob(job, configPath, index, gitRoot, uuidToName) {
|
|
|
700
726
|
...job.runsOnAll !== void 0 && { runsOnAll: normalizeRunsOnAllToMatchers(job.runsOnAll, `job '${job.name}' runsOnAll`) },
|
|
701
727
|
...job.onUnreachable !== void 0 && { onUnreachable: job.onUnreachable },
|
|
702
728
|
...job.includeUninitialized !== void 0 && { includeUninitialized: job.includeUninitialized },
|
|
729
|
+
...job.gitCredentials !== void 0 && { gitCredentials: job.gitCredentials },
|
|
703
730
|
...job.maxParallel !== void 0 && { maxParallel: job.maxParallel },
|
|
704
731
|
...job.failFast !== void 0 && { failFast: job.failFast },
|
|
732
|
+
...job.invoke !== void 0 && { invoke: {
|
|
733
|
+
event: job.invoke.event,
|
|
734
|
+
scope: job.invoke.scope,
|
|
735
|
+
...job.invoke.payload !== void 0 && { payload: job.invoke.payload },
|
|
736
|
+
...job.invoke.optional === true && { optional: true }
|
|
737
|
+
} },
|
|
705
738
|
...resolveNeedsForLock(job.needs, uuidToName),
|
|
706
739
|
steps: transformSteps(job.steps, gitRoot, jobLocation),
|
|
707
740
|
matrix: job.matrix ? transformMatrix(job.matrix, job.name, configPath) : void 0,
|
package/dist/postinstall.js
CHANGED
|
@@ -26,7 +26,8 @@ async function detectDevelopmentMode() {
|
|
|
26
26
|
if (process.env.KICI_DEV === "true") return true;
|
|
27
27
|
try {
|
|
28
28
|
const rootDir = process.env.INIT_CWD || process.cwd();
|
|
29
|
-
const
|
|
29
|
+
const rootPkgPath = path.join(rootDir, "package.json");
|
|
30
|
+
const content = await readFile(rootPkgPath, "utf-8");
|
|
30
31
|
return JSON.parse(content).kici?.development === true;
|
|
31
32
|
} catch {
|
|
32
33
|
return false;
|
package/dist/remote/config.d.ts
CHANGED
|
@@ -35,22 +35,9 @@ export interface GlobalConfig {
|
|
|
35
35
|
*
|
|
36
36
|
* Resolution order:
|
|
37
37
|
* 1. `KICI_CONFIG_DIR`, when set to a non-empty value.
|
|
38
|
-
* 2.
|
|
39
|
-
* machine's `~/.kici/config` names a real endpoint and carries a live
|
|
40
|
-
* PAT, so a test process that reads it authenticates against whatever
|
|
41
|
-
* that config points at — in practice, production. Every test that needs
|
|
42
|
-
* a config must name its own isolated directory.
|
|
43
|
-
* 3. `~/.kici`.
|
|
38
|
+
* 2. `~/.kici`.
|
|
44
39
|
*
|
|
45
|
-
* `
|
|
46
|
-
* `hack/lib/vitest-isolation.ts`. It is deliberately a KiCI-owned name rather
|
|
47
|
-
* than the runner's `VITEST`: `kici` is a compat-protected CLI, and `VITEST`
|
|
48
|
-
* is a third-party marker that propagates into spawned children, so keying off
|
|
49
|
-
* it would break a customer whose vitest test shells out to `kici`.
|
|
50
|
-
*
|
|
51
|
-
* `env` is injectable so this module's own tests can exercise every branch.
|
|
52
|
-
* It is NOT an opt-out: production call sites pass no argument and inherit the
|
|
53
|
-
* guard.
|
|
40
|
+
* `env` is injectable so this module's own tests can exercise both branches.
|
|
54
41
|
*/
|
|
55
42
|
export declare function getConfigDir(env?: NodeJS.ProcessEnv): string;
|
|
56
43
|
/**
|
package/dist/remote/config.js
CHANGED
|
@@ -33,26 +33,12 @@ function sanitizeConfig(raw) {
|
|
|
33
33
|
*
|
|
34
34
|
* Resolution order:
|
|
35
35
|
* 1. `KICI_CONFIG_DIR`, when set to a non-empty value.
|
|
36
|
-
* 2.
|
|
37
|
-
* machine's `~/.kici/config` names a real endpoint and carries a live
|
|
38
|
-
* PAT, so a test process that reads it authenticates against whatever
|
|
39
|
-
* that config points at — in practice, production. Every test that needs
|
|
40
|
-
* a config must name its own isolated directory.
|
|
41
|
-
* 3. `~/.kici`.
|
|
36
|
+
* 2. `~/.kici`.
|
|
42
37
|
*
|
|
43
|
-
* `
|
|
44
|
-
* `hack/lib/vitest-isolation.ts`. It is deliberately a KiCI-owned name rather
|
|
45
|
-
* than the runner's `VITEST`: `kici` is a compat-protected CLI, and `VITEST`
|
|
46
|
-
* is a third-party marker that propagates into spawned children, so keying off
|
|
47
|
-
* it would break a customer whose vitest test shells out to `kici`.
|
|
48
|
-
*
|
|
49
|
-
* `env` is injectable so this module's own tests can exercise every branch.
|
|
50
|
-
* It is NOT an opt-out: production call sites pass no argument and inherit the
|
|
51
|
-
* guard.
|
|
38
|
+
* `env` is injectable so this module's own tests can exercise both branches.
|
|
52
39
|
*/
|
|
53
40
|
function getConfigDir(env = process.env) {
|
|
54
41
|
if (env.KICI_CONFIG_DIR) return env.KICI_CONFIG_DIR;
|
|
55
|
-
if (env.KICI_TEST_ISOLATION) throw new Error("Refusing to read the ambient ~/.kici config from a test process. Set KICI_CONFIG_DIR to an isolated directory for this run — the developer machine config may point at production.");
|
|
56
42
|
return path.join(os.homedir(), ".kici");
|
|
57
43
|
}
|
|
58
44
|
/**
|