@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.
- package/dist/auth/headless-detect.d.ts +14 -5
- package/dist/auth/headless-detect.js +50 -9
- package/dist/cli-banner.d.ts +6 -3
- package/dist/cli-banner.js +13 -5
- package/dist/cli.js +180 -48
- package/dist/commands/check-mode.d.ts +1 -1
- package/dist/commands/compile.js +31 -7
- package/dist/commands/diagnostics.js +14 -2
- package/dist/commands/doctor.d.ts +64 -0
- package/dist/commands/doctor.js +413 -0
- package/dist/commands/endpoints.js +6 -0
- package/dist/commands/fixture.js +13 -0
- package/dist/commands/hook.js +3 -2
- package/dist/commands/index.d.ts +13 -1
- package/dist/commands/index.js +10 -3
- package/dist/commands/init-host-os.d.ts +34 -0
- package/dist/commands/init-host-os.js +44 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +160 -37
- package/dist/commands/local-trust-root.d.ts +6 -0
- package/dist/commands/local-trust-root.js +52 -0
- package/dist/commands/local.d.ts +65 -0
- package/dist/commands/local.js +206 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +41 -1
- package/dist/commands/logout.js +7 -0
- package/dist/commands/notifications.d.ts +61 -0
- package/dist/commands/notifications.js +274 -0
- package/dist/commands/preview.js +9 -2
- package/dist/commands/run-banner.d.ts +31 -0
- package/dist/commands/run-banner.js +25 -0
- package/dist/commands/run-routed.d.ts +53 -0
- package/dist/commands/run-routed.js +185 -0
- package/dist/commands/run.d.ts +0 -17
- package/dist/commands/run.js +44 -58
- package/dist/commands/runs/artifacts/download.d.ts +24 -0
- package/dist/commands/runs/artifacts/download.js +154 -0
- package/dist/commands/runs/artifacts/list.d.ts +5 -0
- package/dist/commands/runs/artifacts/list.js +47 -0
- package/dist/commands/runs/cancel.js +2 -2
- package/dist/commands/runs/list.js +8 -2
- package/dist/commands/secrets-list.d.ts +2 -2
- package/dist/commands/secrets-list.js +4 -4
- package/dist/commands/types.d.ts +3 -3
- package/dist/commands/types.js +4 -4
- package/dist/commands/verify-attestation.d.ts +3 -1
- package/dist/commands/verify-attestation.js +18 -7
- package/dist/errors/formatter.d.ts +14 -1
- package/dist/errors/formatter.js +13 -3
- package/dist/errors/index.d.ts +2 -1
- package/dist/errors/index.js +3 -2
- package/dist/errors/source-location.d.ts +20 -0
- package/dist/errors/source-location.js +45 -0
- package/dist/execution/executor.js +32 -12
- package/dist/fixtures/defaults/index.js +2 -1
- package/dist/generators/secrets-dts.d.ts +9 -9
- package/dist/generators/secrets-dts.js +12 -12
- package/dist/llm-context/llms-architecture.txt +50 -21
- package/dist/llm-context/llms-cli.txt +2667 -1454
- package/dist/llm-context/llms-features.txt +484 -414
- package/dist/llm-context/llms-full.txt +6703 -4687
- package/dist/llm-context/llms-getting-started.txt +311 -55
- package/dist/llm-context/llms-patterns.txt +17 -29
- package/dist/llm-context/llms-providers.txt +10 -1
- package/dist/llm-context/llms-sdk-runtime.txt +2013 -0
- package/dist/llm-context/llms-sdk.txt +596 -2157
- package/dist/llm-context/llms.txt +31 -17
- package/dist/local-plane/orchestrator-process.d.ts +70 -0
- package/dist/local-plane/orchestrator-process.js +129 -0
- package/dist/local-plane/os-mismatch-hint.d.ts +16 -0
- package/dist/local-plane/os-mismatch-hint.js +34 -0
- package/dist/local-plane/paths.d.ts +39 -0
- package/dist/local-plane/paths.js +54 -0
- package/dist/local-plane/plane-liveness.d.ts +68 -0
- package/dist/local-plane/plane-liveness.js +145 -0
- package/dist/local-plane/plane-manager.d.ts +193 -0
- package/dist/local-plane/plane-manager.js +480 -0
- package/dist/local-plane/plane-seed.d.ts +76 -0
- package/dist/local-plane/plane-seed.js +59 -0
- package/dist/local-plane/plane-trigger.d.ts +71 -0
- package/dist/local-plane/plane-trigger.js +110 -0
- package/dist/local-plane/platform-attach.d.ts +53 -0
- package/dist/local-plane/platform-attach.js +107 -0
- package/dist/local-plane/port-holder.d.ts +78 -0
- package/dist/local-plane/port-holder.js +227 -0
- package/dist/local-plane/postgres.d.ts +56 -0
- package/dist/local-plane/postgres.js +187 -0
- package/dist/local-plane/resolve-plane.d.ts +37 -0
- package/dist/local-plane/resolve-plane.js +76 -0
- package/dist/local-plane/run-follow.d.ts +61 -0
- package/dist/local-plane/run-follow.js +151 -0
- package/dist/local-plane/scaler-config.d.ts +68 -0
- package/dist/local-plane/scaler-config.js +132 -0
- package/dist/local-plane/secret-seed.d.ts +59 -0
- package/dist/local-plane/secret-seed.js +112 -0
- package/dist/local-plane/source-provider.d.ts +43 -0
- package/dist/local-plane/source-provider.js +159 -0
- package/dist/local-plane/trusted-routing.d.ts +32 -0
- package/dist/local-plane/trusted-routing.js +47 -0
- package/dist/lockfile/generator.d.ts +14 -1
- package/dist/lockfile/generator.js +103 -37
- package/dist/lockfile/index.d.ts +3 -1
- package/dist/lockfile/index.js +3 -2
- package/dist/lockfile/purity-diagnostics.d.ts +31 -0
- package/dist/lockfile/purity-diagnostics.js +52 -0
- package/dist/postinstall.js +2 -1
- package/dist/remote/artifact-extract.d.ts +8 -0
- package/dist/remote/artifact-extract.js +58 -0
- package/dist/remote/config.d.ts +21 -3
- package/dist/remote/config.js +24 -5
- package/dist/remote/dashboard-client.d.ts +46 -9
- package/dist/remote/dashboard-client.js +54 -11
- package/dist/remote/fs-case.d.ts +21 -0
- package/dist/remote/fs-case.js +45 -0
- package/dist/remote/history.d.ts +9 -3
- package/dist/remote/history.js +79 -10
- package/dist/remote/local-repo-identity.d.ts +1 -1
- package/dist/remote/local-repo-identity.js +2 -1
- package/dist/remote/notifications-client.d.ts +149 -0
- package/dist/remote/notifications-client.js +103 -0
- package/dist/remote/oauth.d.ts +13 -0
- package/dist/remote/oauth.js +31 -5
- package/dist/remote/output/summary.js +76 -14
- package/dist/remote/platform-client.d.ts +1 -1
- package/dist/remote/render.js +30 -9
- package/dist/{local-executor → remote}/secret-loader.d.ts +1 -1
- package/dist/{local-executor → remote}/secret-loader.js +4 -4
- package/dist/remote/secret-upload.d.ts +1 -1
- package/dist/remote/secret-upload.js +2 -2
- package/dist/remote/uploader.d.ts +1 -1
- package/dist/remote/uploader.js +7 -6
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +8 -8
- package/dist/templates/index.d.ts +1 -1
- package/dist/templates/index.js +2 -2
- package/dist/templates/package-json.d.ts +15 -0
- package/dist/templates/package-json.js +26 -5
- package/dist/test-runner/dry-run.d.ts +2 -1
- package/dist/test-runner/dry-run.js +18 -1
- package/dist/test-runner/event-types.d.ts +2 -0
- package/dist/test-runner/event-types.js +3 -0
- package/dist/test-runner/job-executor.d.ts +1 -0
- package/dist/test-runner/job-executor.js +82 -44
- package/dist/test-runner/output-formatter.d.ts +5 -2
- package/dist/test-runner/output-formatter.js +6 -4
- package/dist/test-runner/payload-builder.d.ts +7 -1
- package/dist/test-runner/payload-builder.js +11 -2
- package/dist/test-runner/rule-evaluator.d.ts +7 -3
- package/dist/test-runner/rule-evaluator.js +13 -12
- package/dist/{local-executor → test-runner}/runs-on-display.js +1 -1
- package/dist/test-runner/step-context.d.ts +23 -5
- package/dist/test-runner/step-context.js +29 -119
- package/dist/types.d.ts +26 -7
- package/dist/types.js +4 -2
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.js +2 -1
- package/dist/validation/typecheck.d.ts +28 -0
- package/dist/validation/typecheck.js +110 -0
- package/dist/validation/validator.d.ts +9 -4
- package/dist/validation/validator.js +38 -44
- package/package.json +13 -13
- package/sbom.spdx.json +9311 -1528
- package/dist/assets/api-TJJVHrjC.json +0 -118
- package/dist/assets/descriptor-BTtjzN9L.json +0 -1382
- package/dist/assets/package-BpQF9kR8.json +0 -74
- package/dist/assets/package-Ceo2h27X.json +0 -89
- package/dist/assets/source_context-D0atuL28.json +0 -20
- package/dist/assets/type-BFqO8SCZ.json +0 -202
- package/dist/commands/cancel.d.ts +0 -22
- package/dist/commands/detect-package-manager.d.ts +0 -42
- package/dist/commands/held-run-resolve.d.ts +0 -50
- package/dist/commands/status.d.ts +0 -34
- package/dist/commands/test.d.ts +0 -88
- package/dist/errors/codes.d.ts +0 -25
- package/dist/local-executor/dag-scheduler.d.ts +0 -44
- package/dist/local-executor/dag-scheduler.js +0 -183
- package/dist/local-executor/index.d.ts +0 -23
- package/dist/local-executor/index.js +0 -378
- package/dist/local-executor/job-runner.d.ts +0 -47
- package/dist/local-executor/job-runner.js +0 -411
- package/dist/local-executor/materializer.d.ts +0 -44
- package/dist/local-executor/materializer.js +0 -132
- package/dist/local-executor/output-streamer.d.ts +0 -31
- package/dist/local-executor/output-streamer.js +0 -168
- package/dist/local-executor/payload-generator.d.ts +0 -16
- package/dist/local-executor/payload-generator.js +0 -138
- package/dist/local-executor/picker.d.ts +0 -33
- package/dist/local-executor/picker.js +0 -109
- package/dist/local-executor/to-event-payload.d.ts +0 -16
- package/dist/local-executor/to-event-payload.js +0 -21
- package/dist/local-executor/types.d.ts +0 -93
- package/dist/local-executor/types.js +0 -2
- package/dist/local-executor/workflow-lock.d.ts +0 -82
- package/dist/local-executor/workflow-lock.js +0 -0
- package/dist/package-F7UXSDHW.json +0 -74
- package/dist/remote/client.d.ts +0 -210
- package/dist/remote/observer.d.ts +0 -81
- package/dist/test-runner/summary.d.ts +0 -7
- /package/dist/{local-executor → test-runner}/runs-on-display.d.ts +0 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { ExecutionJobStatus, ExecutionRunStatus, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES } from "@kici-dev/engine";
|
|
3
|
+
import { AdminApiClient } from "@kici-dev/orchestrator";
|
|
4
|
+
//#region src/local-plane/run-follow.ts
|
|
5
|
+
/**
|
|
6
|
+
* Follow an offline routed run against the local plane by polling the
|
|
7
|
+
* orchestrator admin API (no SSE in independent mode). Streams step log lines as
|
|
8
|
+
* they arrive and resolves when the run reaches a terminal state.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Job states that mean the job did NOT succeed (failed / stale / cancelled /
|
|
12
|
+
* dropped / unroutable). Read only by the anti-false-green guard below, so a
|
|
13
|
+
* missing member lets a lagging `success` run header be reported verbatim even
|
|
14
|
+
* though a job settled badly.
|
|
15
|
+
*/
|
|
16
|
+
const FAILED_JOB_STATES = /* @__PURE__ */ new Set([
|
|
17
|
+
ExecutionJobStatus.enum.failed,
|
|
18
|
+
ExecutionJobStatus.enum.timed_out_stale,
|
|
19
|
+
ExecutionJobStatus.enum.cancelled,
|
|
20
|
+
ExecutionJobStatus.enum.drift_dropped,
|
|
21
|
+
ExecutionJobStatus.enum.unroutable
|
|
22
|
+
]);
|
|
23
|
+
/** Job states in which no agent has claimed the job yet. */
|
|
24
|
+
const UNCLAIMED_JOB_STATES = /* @__PURE__ */ new Set([ExecutionJobStatus.enum.pending, ExecutionJobStatus.enum.queued]);
|
|
25
|
+
/**
|
|
26
|
+
* How often the acceptance check re-fetches jobs. Deliberately far coarser than
|
|
27
|
+
* the poll interval: at 750 ms a two-minute window would cost ~160 extra admin
|
|
28
|
+
* requests to answer a question that changes once.
|
|
29
|
+
*/
|
|
30
|
+
const ACCEPTANCE_CHECK_INTERVAL_MS = 5e3;
|
|
31
|
+
/** Default window for an agent to claim the run before the follow gives up. */
|
|
32
|
+
const DEFAULT_ACCEPTANCE_TIMEOUT_MS = 12e4;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the acceptance window, falling back to the default for any value that
|
|
35
|
+
* is not a positive number of milliseconds.
|
|
36
|
+
*
|
|
37
|
+
* A malformed override must never reach the deadline arithmetic: `Number('')`
|
|
38
|
+
* is `0` (every run fails instantly) and `Number('2 min')` is `NaN`, which makes
|
|
39
|
+
* `now > deadline` permanently false and silently restores the 900 s hang this
|
|
40
|
+
* window exists to prevent. Both failure modes are worse than ignoring a typo.
|
|
41
|
+
*/
|
|
42
|
+
function resolveAcceptanceTimeoutMs(explicitMs, raw) {
|
|
43
|
+
if (explicitMs !== void 0) return explicitMs;
|
|
44
|
+
if (raw === void 0) return DEFAULT_ACCEPTANCE_TIMEOUT_MS;
|
|
45
|
+
const parsed = Number(raw);
|
|
46
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_ACCEPTANCE_TIMEOUT_MS;
|
|
47
|
+
}
|
|
48
|
+
/** Poll a run to completion, streaming step logs. */
|
|
49
|
+
async function followRun(planeUrl, adminToken, runId, opts = {}) {
|
|
50
|
+
const client = opts.client ?? new AdminApiClient(planeUrl, adminToken);
|
|
51
|
+
const pollIntervalMs = opts.pollIntervalMs ?? 750;
|
|
52
|
+
const idleTimeoutMs = opts.idleTimeoutMs ?? opts.timeoutMs ?? 9e5;
|
|
53
|
+
const maxTotalMs = opts.maxTotalMs ?? 72e5;
|
|
54
|
+
const acceptanceTimeoutMs = resolveAcceptanceTimeoutMs(opts.acceptanceTimeoutMs, process.env.KICI_LOCAL_ACCEPTANCE_TIMEOUT_MS);
|
|
55
|
+
const cursors = /* @__PURE__ */ new Map();
|
|
56
|
+
const stream = !opts.quiet && opts.onLine ? opts.onLine : void 0;
|
|
57
|
+
const startedAt = Date.now();
|
|
58
|
+
let lastProgressAt = startedAt;
|
|
59
|
+
let lastStatus = "";
|
|
60
|
+
let accepted = false;
|
|
61
|
+
let acceptanceDeadline = startedAt + acceptanceTimeoutMs;
|
|
62
|
+
let lastAcceptanceCheck = 0;
|
|
63
|
+
for (;;) {
|
|
64
|
+
const now = Date.now();
|
|
65
|
+
if (now - lastProgressAt > idleTimeoutMs) throw new Error(`offline run: follow timed out (no progress for ${idleTimeoutMs}ms) for run ${runId}`);
|
|
66
|
+
if (now - startedAt > maxTotalMs) throw new Error(`offline run: follow exceeded its max window (${maxTotalMs}ms) for run ${runId}`);
|
|
67
|
+
const { run } = await client.get(`/api/v1/admin/runs/${runId}`);
|
|
68
|
+
if (!accepted && !TERMINAL_RUN_STATES.has(run.status)) {
|
|
69
|
+
if (run.status === ExecutionRunStatus.enum.held) acceptanceDeadline = now + acceptanceTimeoutMs;
|
|
70
|
+
else if (now - lastAcceptanceCheck >= ACCEPTANCE_CHECK_INTERVAL_MS) {
|
|
71
|
+
lastAcceptanceCheck = now;
|
|
72
|
+
const claimedJobs = await fetchJobs(client, runId);
|
|
73
|
+
accepted = claimedJobs.length > 0 && claimedJobs.some((j) => !UNCLAIMED_JOB_STATES.has(j.status));
|
|
74
|
+
}
|
|
75
|
+
if (!accepted && now > acceptanceDeadline) {
|
|
76
|
+
const seconds = Math.round(acceptanceTimeoutMs / 1e3);
|
|
77
|
+
throw new Error(`offline run: no agent picked up this run within ${seconds}s — no scaler label set matched the job's runsOn, or the agent failed to start.` + (opts.hintLogPath ? ` Plane log: ${opts.hintLogPath}` : ""));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
let progressed = false;
|
|
81
|
+
if (run.status !== lastStatus) {
|
|
82
|
+
lastStatus = run.status;
|
|
83
|
+
progressed = true;
|
|
84
|
+
}
|
|
85
|
+
if (stream) {
|
|
86
|
+
if (await drainLogs(client, runId, cursors, stream) > 0) progressed = true;
|
|
87
|
+
}
|
|
88
|
+
if (progressed) lastProgressAt = now;
|
|
89
|
+
if (TERMINAL_RUN_STATES.has(run.status)) {
|
|
90
|
+
const jobs = await fetchJobs(client, runId);
|
|
91
|
+
const allTerminal = jobs.length > 0 && jobs.every((j) => TERMINAL_JOB_STATES.has(j.status));
|
|
92
|
+
const anyFailed = jobs.some((j) => FAILED_JOB_STATES.has(j.status));
|
|
93
|
+
if (allTerminal && !(run.status === "success" && anyFailed)) {
|
|
94
|
+
if (stream) await drainLogs(client, runId, cursors, stream);
|
|
95
|
+
return {
|
|
96
|
+
runId,
|
|
97
|
+
status: run.status,
|
|
98
|
+
jobs
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
await sleep(pollIntervalMs);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/** Fetch the run's jobs mapped to the summary shape. */
|
|
106
|
+
async function fetchJobs(client, runId) {
|
|
107
|
+
const { jobs } = await client.get(`/api/v1/admin/runs/${runId}/jobs`);
|
|
108
|
+
return jobs.map((j) => ({
|
|
109
|
+
name: j.jobName,
|
|
110
|
+
status: j.status,
|
|
111
|
+
durationMs: j.durationMs ?? void 0
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Stream any new step-log lines. Best-effort: a per-step fetch error never
|
|
116
|
+
* aborts the follow (logs are observability, not the terminal signal).
|
|
117
|
+
*/
|
|
118
|
+
async function drainLogs(client, runId, cursors, onLine) {
|
|
119
|
+
let emitted = 0;
|
|
120
|
+
let jobs;
|
|
121
|
+
try {
|
|
122
|
+
jobs = (await client.get(`/api/v1/admin/runs/${runId}/jobs?includeSteps=true`)).jobs;
|
|
123
|
+
} catch {
|
|
124
|
+
return emitted;
|
|
125
|
+
}
|
|
126
|
+
for (const job of jobs) for (const step of job.steps ?? []) {
|
|
127
|
+
const key = `${job.jobId}:${step.stepIndex}`;
|
|
128
|
+
try {
|
|
129
|
+
let cursor = cursors.get(key);
|
|
130
|
+
for (;;) {
|
|
131
|
+
const qs = cursor ? `?cursor=${encodeURIComponent(cursor)}` : "";
|
|
132
|
+
const page = await client.get(`/api/v1/admin/runs/${runId}/jobs/${job.jobId}/steps/${step.stepIndex}/logs${qs}`);
|
|
133
|
+
for (const l of page.lines) {
|
|
134
|
+
onLine(l.value);
|
|
135
|
+
emitted++;
|
|
136
|
+
}
|
|
137
|
+
cursor = page.nextCursor ?? String(page.totalLines);
|
|
138
|
+
cursors.set(key, cursor);
|
|
139
|
+
if (!page.nextCursor) break;
|
|
140
|
+
}
|
|
141
|
+
} catch {}
|
|
142
|
+
}
|
|
143
|
+
return emitted;
|
|
144
|
+
}
|
|
145
|
+
function sleep(ms) {
|
|
146
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
147
|
+
}
|
|
148
|
+
//#endregion
|
|
149
|
+
export { followRun, resolveAcceptanceTimeoutMs };
|
|
150
|
+
|
|
151
|
+
//# sourceMappingURL=run-follow.js.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bare-metal scaler configuration for the local dev plane.
|
|
3
|
+
*
|
|
4
|
+
* A dispatched job needs an agent to run it. The plane orchestrator boots with
|
|
5
|
+
* a single bare-metal scaler pointed at a label set matching the default
|
|
6
|
+
* `runsOn` (`default`), so an offline `kici run --local` dispatch auto-spawns an
|
|
7
|
+
* ephemeral, one-job-then-exit agent on this machine. The spawned binary is a
|
|
8
|
+
* small executable wrapper that execs `node <@kici-dev/agent server entry>` —
|
|
9
|
+
* mirroring the shape proven by the `local-file-source` E2E, and avoiding a
|
|
10
|
+
* dependency on the (non-executable) shipped `kici-agent` script.
|
|
11
|
+
*/
|
|
12
|
+
/** Resolve the built `@kici-dev/agent` server entry the bare-metal scaler runs. */
|
|
13
|
+
export declare function resolveAgentBinary(): string;
|
|
14
|
+
/**
|
|
15
|
+
* Write the executable wrapper the bare-metal scaler spawns. The scaler invokes
|
|
16
|
+
* `spawn(binaryPath, [])` directly, so the target must be an executable file;
|
|
17
|
+
* the shipped agent entry is a plain Node module without an exec bit, so this
|
|
18
|
+
* wrapper bridges the gap. Returns the wrapper path.
|
|
19
|
+
*/
|
|
20
|
+
export declare function writeAgentWrapper(): string;
|
|
21
|
+
/**
|
|
22
|
+
* The non-reserved routing label a `kici run --local --trusted` run appends to
|
|
23
|
+
* every job's `runsOn` so the dispatch lands on the plane's trusted label set.
|
|
24
|
+
* `self-hosted` (not a `kici:`-prefixed reserved label) is also the `runsOn` the
|
|
25
|
+
* CI deploy/CDN workflows already declare, so those route to the trusted profile
|
|
26
|
+
* on this plane by construction.
|
|
27
|
+
*/
|
|
28
|
+
export declare const TRUSTED_ROUTING_LABEL = "self-hosted";
|
|
29
|
+
/**
|
|
30
|
+
* The non-reserved routing label a `kici run --local --trusted --in-place` run
|
|
31
|
+
* appends (alongside `self-hosted`) so the dispatch lands on the plane's trusted
|
|
32
|
+
* **in-place** label set — the agent runs the operator's real working tree
|
|
33
|
+
* directly (no clone). This is the profile KiCI's own routed `deploy:stg` uses.
|
|
34
|
+
*/
|
|
35
|
+
export declare const IN_PLACE_ROUTING_LABEL = "in-place";
|
|
36
|
+
/**
|
|
37
|
+
* Write the plane's bare-metal scaler YAML and return its path. TWO coexisting
|
|
38
|
+
* bare-metal scalers spawn the agent wrapper against the plane orchestrator's
|
|
39
|
+
* localhost WS endpoint — a **sandboxed** pool and a `self-hosted`-**tainted**
|
|
40
|
+
* TRUSTED pool:
|
|
41
|
+
*
|
|
42
|
+
* - `kici-local-bare-metal` (sandboxed) — one `default` label set, no taint. The
|
|
43
|
+
* credential-isolated profile a normal `kici run --local` dispatch (jobs with
|
|
44
|
+
* `runsOn: ['default']` or none) lands on. Its agents inherit no
|
|
45
|
+
* `mandatoryLabels`, so a bare `default` job routes here.
|
|
46
|
+
* - `kici-local-bare-metal-trusted` (TRUSTED) — carries `mandatoryLabels:
|
|
47
|
+
* ['self-hosted']`, so ONLY a job that explicitly requests `self-hosted`
|
|
48
|
+
* (i.e. a `kici run --local --trusted` run, whose lock patch appends the
|
|
49
|
+
* `self-hosted` routing label, or a `runsOn: self-hosted` workflow) is ever
|
|
50
|
+
* routed to it — at BOTH the scaler spawn matcher AND the orchestrator's
|
|
51
|
+
* agent-registry dispatch gate. Two label sets:
|
|
52
|
+
* - `default` + `self-hosted` — the trusted fleet profile
|
|
53
|
+
* (`KICI_TRUSTED_ENV=true`, bwrap off): steps run with the ambient host
|
|
54
|
+
* env passed through, minus the agent's own KiCI identity secrets.
|
|
55
|
+
* - `default` + `self-hosted` + `in-place` — the trusted **in-place**
|
|
56
|
+
* profile (adds `KICI_IN_PLACE=true`) a `kici run --local --trusted
|
|
57
|
+
* --in-place` run lands on: same trusted env, but the agent uses the
|
|
58
|
+
* operator's real working tree directly (no clone) — the profile KiCI's
|
|
59
|
+
* own routed `deploy:stg` uses.
|
|
60
|
+
*
|
|
61
|
+
* The `self-hosted` taint is the isolation guarantee: without it, an idle
|
|
62
|
+
* trusted agent (spawned for an earlier `--trusted` run and lingering for
|
|
63
|
+
* follow-up jobs) would satisfy the agent-registry's subset match for a plain
|
|
64
|
+
* `default` job and leak the ambient host env into a sandboxed run. The taint
|
|
65
|
+
* closes that at the dispatch layer, not just the spawn heuristic.
|
|
66
|
+
*/
|
|
67
|
+
export declare function writeScalerConfig(orchestratorPort: number): string;
|
|
68
|
+
//# sourceMappingURL=scaler-config.d.ts.map
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { planePaths } from "./paths.js";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { stringify } from "yaml";
|
|
6
|
+
//#region src/local-plane/scaler-config.ts
|
|
7
|
+
/**
|
|
8
|
+
* Bare-metal scaler configuration for the local dev plane.
|
|
9
|
+
*
|
|
10
|
+
* A dispatched job needs an agent to run it. The plane orchestrator boots with
|
|
11
|
+
* a single bare-metal scaler pointed at a label set matching the default
|
|
12
|
+
* `runsOn` (`default`), so an offline `kici run --local` dispatch auto-spawns an
|
|
13
|
+
* ephemeral, one-job-then-exit agent on this machine. The spawned binary is a
|
|
14
|
+
* small executable wrapper that execs `node <@kici-dev/agent server entry>` —
|
|
15
|
+
* mirroring the shape proven by the `local-file-source` E2E, and avoiding a
|
|
16
|
+
* dependency on the (non-executable) shipped `kici-agent` script.
|
|
17
|
+
*/
|
|
18
|
+
/** Resolve the built `@kici-dev/agent` server entry the bare-metal scaler runs. */
|
|
19
|
+
function resolveAgentBinary() {
|
|
20
|
+
return createRequire(import.meta.url).resolve("@kici-dev/agent/server");
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Write the executable wrapper the bare-metal scaler spawns. The scaler invokes
|
|
24
|
+
* `spawn(binaryPath, [])` directly, so the target must be an executable file;
|
|
25
|
+
* the shipped agent entry is a plain Node module without an exec bit, so this
|
|
26
|
+
* wrapper bridges the gap. Returns the wrapper path.
|
|
27
|
+
*/
|
|
28
|
+
function writeAgentWrapper() {
|
|
29
|
+
const { agentWrapperFile, root } = planePaths();
|
|
30
|
+
fs.mkdirSync(root, { recursive: true });
|
|
31
|
+
const server = resolveAgentBinary();
|
|
32
|
+
fs.writeFileSync(agentWrapperFile, `#!/usr/bin/env bash\nexec node ${JSON.stringify(server)} "$@"\n`);
|
|
33
|
+
fs.chmodSync(agentWrapperFile, 493);
|
|
34
|
+
return agentWrapperFile;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The non-reserved routing label a `kici run --local --trusted` run appends to
|
|
38
|
+
* every job's `runsOn` so the dispatch lands on the plane's trusted label set.
|
|
39
|
+
* `self-hosted` (not a `kici:`-prefixed reserved label) is also the `runsOn` the
|
|
40
|
+
* CI deploy/CDN workflows already declare, so those route to the trusted profile
|
|
41
|
+
* on this plane by construction.
|
|
42
|
+
*/
|
|
43
|
+
const TRUSTED_ROUTING_LABEL = "self-hosted";
|
|
44
|
+
/**
|
|
45
|
+
* The non-reserved routing label a `kici run --local --trusted --in-place` run
|
|
46
|
+
* appends (alongside `self-hosted`) so the dispatch lands on the plane's trusted
|
|
47
|
+
* **in-place** label set — the agent runs the operator's real working tree
|
|
48
|
+
* directly (no clone). This is the profile KiCI's own routed `deploy:stg` uses.
|
|
49
|
+
*/
|
|
50
|
+
const IN_PLACE_ROUTING_LABEL = "in-place";
|
|
51
|
+
/**
|
|
52
|
+
* Write the plane's bare-metal scaler YAML and return its path. TWO coexisting
|
|
53
|
+
* bare-metal scalers spawn the agent wrapper against the plane orchestrator's
|
|
54
|
+
* localhost WS endpoint — a **sandboxed** pool and a `self-hosted`-**tainted**
|
|
55
|
+
* TRUSTED pool:
|
|
56
|
+
*
|
|
57
|
+
* - `kici-local-bare-metal` (sandboxed) — one `default` label set, no taint. The
|
|
58
|
+
* credential-isolated profile a normal `kici run --local` dispatch (jobs with
|
|
59
|
+
* `runsOn: ['default']` or none) lands on. Its agents inherit no
|
|
60
|
+
* `mandatoryLabels`, so a bare `default` job routes here.
|
|
61
|
+
* - `kici-local-bare-metal-trusted` (TRUSTED) — carries `mandatoryLabels:
|
|
62
|
+
* ['self-hosted']`, so ONLY a job that explicitly requests `self-hosted`
|
|
63
|
+
* (i.e. a `kici run --local --trusted` run, whose lock patch appends the
|
|
64
|
+
* `self-hosted` routing label, or a `runsOn: self-hosted` workflow) is ever
|
|
65
|
+
* routed to it — at BOTH the scaler spawn matcher AND the orchestrator's
|
|
66
|
+
* agent-registry dispatch gate. Two label sets:
|
|
67
|
+
* - `default` + `self-hosted` — the trusted fleet profile
|
|
68
|
+
* (`KICI_TRUSTED_ENV=true`, bwrap off): steps run with the ambient host
|
|
69
|
+
* env passed through, minus the agent's own KiCI identity secrets.
|
|
70
|
+
* - `default` + `self-hosted` + `in-place` — the trusted **in-place**
|
|
71
|
+
* profile (adds `KICI_IN_PLACE=true`) a `kici run --local --trusted
|
|
72
|
+
* --in-place` run lands on: same trusted env, but the agent uses the
|
|
73
|
+
* operator's real working tree directly (no clone) — the profile KiCI's
|
|
74
|
+
* own routed `deploy:stg` uses.
|
|
75
|
+
*
|
|
76
|
+
* The `self-hosted` taint is the isolation guarantee: without it, an idle
|
|
77
|
+
* trusted agent (spawned for an earlier `--trusted` run and lingering for
|
|
78
|
+
* follow-up jobs) would satisfy the agent-registry's subset match for a plain
|
|
79
|
+
* `default` job and leak the ambient host env into a sandboxed run. The taint
|
|
80
|
+
* closes that at the dispatch layer, not just the spawn heuristic.
|
|
81
|
+
*/
|
|
82
|
+
function writeScalerConfig(orchestratorPort) {
|
|
83
|
+
const { scalerConfigFile, root } = planePaths();
|
|
84
|
+
fs.mkdirSync(root, { recursive: true });
|
|
85
|
+
const binaryPath = writeAgentWrapper();
|
|
86
|
+
const orchestratorUrl = `ws://127.0.0.1:${orchestratorPort}/ws`;
|
|
87
|
+
const yaml = stringify({
|
|
88
|
+
version: 1,
|
|
89
|
+
scalers: [{
|
|
90
|
+
name: "kici-local-bare-metal",
|
|
91
|
+
type: "bare-metal",
|
|
92
|
+
maxAgents: 10,
|
|
93
|
+
orchestratorUrl,
|
|
94
|
+
labelSets: [{
|
|
95
|
+
labels: ["default"],
|
|
96
|
+
binaryPath
|
|
97
|
+
}]
|
|
98
|
+
}, {
|
|
99
|
+
name: "kici-local-bare-metal-trusted",
|
|
100
|
+
type: "bare-metal",
|
|
101
|
+
maxAgents: 10,
|
|
102
|
+
orchestratorUrl,
|
|
103
|
+
mandatoryLabels: [TRUSTED_ROUTING_LABEL],
|
|
104
|
+
labelSets: [{
|
|
105
|
+
labels: ["default", TRUSTED_ROUTING_LABEL],
|
|
106
|
+
binaryPath,
|
|
107
|
+
env: {
|
|
108
|
+
KICI_TRUSTED_ENV: "true",
|
|
109
|
+
KICI_SANDBOX: "false"
|
|
110
|
+
}
|
|
111
|
+
}, {
|
|
112
|
+
labels: [
|
|
113
|
+
"default",
|
|
114
|
+
TRUSTED_ROUTING_LABEL,
|
|
115
|
+
IN_PLACE_ROUTING_LABEL
|
|
116
|
+
],
|
|
117
|
+
binaryPath,
|
|
118
|
+
env: {
|
|
119
|
+
KICI_TRUSTED_ENV: "true",
|
|
120
|
+
KICI_SANDBOX: "false",
|
|
121
|
+
KICI_IN_PLACE: "true"
|
|
122
|
+
}
|
|
123
|
+
}]
|
|
124
|
+
}]
|
|
125
|
+
});
|
|
126
|
+
fs.writeFileSync(scalerConfigFile, yaml);
|
|
127
|
+
return scalerConfigFile;
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
export { IN_PLACE_ROUTING_LABEL, TRUSTED_ROUTING_LABEL, resolveAgentBinary, writeAgentWrapper, writeScalerConfig };
|
|
131
|
+
|
|
132
|
+
//# sourceMappingURL=scaler-config.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed a project's local `secrets.yaml` (and `.kici/.secrets` INI) contexts into
|
|
3
|
+
* the local dev plane's real `scoped_secrets` store, preserving context/scope
|
|
4
|
+
* structure so the plane's real `SecretResolver` honors scoping at dispatch —
|
|
5
|
+
* the routed local run resolves scoped secrets through the plane's real
|
|
6
|
+
* resolver rather than a flat merge.
|
|
7
|
+
*
|
|
8
|
+
* Local secret files are READ-ONLY here: values are only READ and transit into
|
|
9
|
+
* the local plane's Postgres via the admin secret API. Nothing is written back
|
|
10
|
+
* to a secret file, and nothing leaves this machine (the plane is local).
|
|
11
|
+
*
|
|
12
|
+
* Scope model: each `secrets.yaml` top-level key is a context name. The seeder
|
|
13
|
+
* creates a context of that name, binds it to a scope pattern equal to the
|
|
14
|
+
* context name, and stores each secret at that scope. So a workflow job bound to
|
|
15
|
+
* context `production` resolves `production`-scoped secrets through the resolver.
|
|
16
|
+
*/
|
|
17
|
+
/** Minimal AdminApiClient surface the seeder needs (for test injection). */
|
|
18
|
+
export interface SecretSeedClient {
|
|
19
|
+
createContext(data: {
|
|
20
|
+
orgId: string;
|
|
21
|
+
name: string;
|
|
22
|
+
allowLocalExecution?: boolean;
|
|
23
|
+
}): Promise<{
|
|
24
|
+
envId: string;
|
|
25
|
+
created: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
bindContext(data: {
|
|
28
|
+
orgId: string;
|
|
29
|
+
name: string;
|
|
30
|
+
scopePattern: string;
|
|
31
|
+
hostPattern?: string;
|
|
32
|
+
}): Promise<unknown>;
|
|
33
|
+
setSecret(orgId: string, scope: string, key: string, value: string): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
/** Result of a seed run: the contexts seeded and how many secret keys landed. */
|
|
36
|
+
export interface SeededSecrets {
|
|
37
|
+
contexts: string[];
|
|
38
|
+
secretCount: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Collect the per-context secrets from a project's `.kici/` directory,
|
|
42
|
+
* preserving context structure. Reads `.kici/.secrets` (INI sections) and
|
|
43
|
+
* `.kici/secrets.yaml` (top-level contexts). The yaml layer wins on key
|
|
44
|
+
* collisions within a context. Flat (context-less) secrets are ignored here —
|
|
45
|
+
* a routed job only resolves secrets for the contexts it binds.
|
|
46
|
+
*/
|
|
47
|
+
export declare function loadLocalSecretContexts(kiciDir: string): Promise<Record<string, Record<string, string>>>;
|
|
48
|
+
/**
|
|
49
|
+
* Seed the local plane's `scoped_secrets` store from a project's `secrets.yaml`
|
|
50
|
+
* / `.secrets` contexts. Idempotent: `createContext` upserts, `bind` is a no-op
|
|
51
|
+
* when the scope is already bound, and `setSecret` overwrites in place. Returns
|
|
52
|
+
* the contexts + secret-key count seeded (never the values).
|
|
53
|
+
*/
|
|
54
|
+
export declare function seedLocalSecrets(planeUrl: string, adminToken: string, opts: {
|
|
55
|
+
orgId: string;
|
|
56
|
+
kiciDir: string;
|
|
57
|
+
client?: SecretSeedClient;
|
|
58
|
+
}): Promise<SeededSecrets>;
|
|
59
|
+
//# sourceMappingURL=secret-seed.d.ts.map
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { parseSecretsFile } from "../test-runner/secrets-file.js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { parse } from "yaml";
|
|
6
|
+
import { AdminApiClient } from "@kici-dev/orchestrator";
|
|
7
|
+
//#region src/local-plane/secret-seed.ts
|
|
8
|
+
/**
|
|
9
|
+
* Seed a project's local `secrets.yaml` (and `.kici/.secrets` INI) contexts into
|
|
10
|
+
* the local dev plane's real `scoped_secrets` store, preserving context/scope
|
|
11
|
+
* structure so the plane's real `SecretResolver` honors scoping at dispatch —
|
|
12
|
+
* the routed local run resolves scoped secrets through the plane's real
|
|
13
|
+
* resolver rather than a flat merge.
|
|
14
|
+
*
|
|
15
|
+
* Local secret files are READ-ONLY here: values are only READ and transit into
|
|
16
|
+
* the local plane's Postgres via the admin secret API. Nothing is written back
|
|
17
|
+
* to a secret file, and nothing leaves this machine (the plane is local).
|
|
18
|
+
*
|
|
19
|
+
* Scope model: each `secrets.yaml` top-level key is a context name. The seeder
|
|
20
|
+
* creates a context of that name, binds it to a scope pattern equal to the
|
|
21
|
+
* context name, and stores each secret at that scope. So a workflow job bound to
|
|
22
|
+
* context `production` resolves `production`-scoped secrets through the resolver.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Read a file, returning null when it does not exist.
|
|
26
|
+
*/
|
|
27
|
+
async function readFileOrNull(filePath) {
|
|
28
|
+
try {
|
|
29
|
+
return await readFile(filePath, "utf-8");
|
|
30
|
+
} catch (err) {
|
|
31
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") return null;
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Parse `secrets.yaml`, PRESERVING its top-level context structure (a flat merge
|
|
37
|
+
* would collapse the contexts). Top-level keys are context names; values are
|
|
38
|
+
* key→value maps. Non-scalar leaf values are stringified.
|
|
39
|
+
*/
|
|
40
|
+
function parseSecretsYamlContexts(content) {
|
|
41
|
+
const parsed = parse(content);
|
|
42
|
+
if (!parsed || typeof parsed !== "object") return {};
|
|
43
|
+
const out = {};
|
|
44
|
+
for (const [contextName, contextSecrets] of Object.entries(parsed)) if (contextSecrets && typeof contextSecrets === "object" && !Array.isArray(contextSecrets)) {
|
|
45
|
+
const map = {};
|
|
46
|
+
for (const [key, value] of Object.entries(contextSecrets)) if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") map[key] = String(value);
|
|
47
|
+
if (Object.keys(map).length > 0) out[contextName] = map;
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Collect the per-context secrets from a project's `.kici/` directory,
|
|
53
|
+
* preserving context structure. Reads `.kici/.secrets` (INI sections) and
|
|
54
|
+
* `.kici/secrets.yaml` (top-level contexts). The yaml layer wins on key
|
|
55
|
+
* collisions within a context. Flat (context-less) secrets are ignored here —
|
|
56
|
+
* a routed job only resolves secrets for the contexts it binds.
|
|
57
|
+
*/
|
|
58
|
+
async function loadLocalSecretContexts(kiciDir) {
|
|
59
|
+
const contexts = {};
|
|
60
|
+
const iniContent = await readFileOrNull(path.join(kiciDir, ".secrets"));
|
|
61
|
+
if (iniContent !== null) {
|
|
62
|
+
const parsed = parseSecretsFile(iniContent);
|
|
63
|
+
for (const [ctx, vals] of Object.entries(parsed.contexts)) contexts[ctx] = {
|
|
64
|
+
...contexts[ctx] ?? {},
|
|
65
|
+
...vals
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const yamlContent = await readFileOrNull(path.join(kiciDir, "secrets.yaml"));
|
|
69
|
+
if (yamlContent !== null) for (const [ctx, vals] of Object.entries(parseSecretsYamlContexts(yamlContent))) contexts[ctx] = {
|
|
70
|
+
...contexts[ctx] ?? {},
|
|
71
|
+
...vals
|
|
72
|
+
};
|
|
73
|
+
return contexts;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Seed the local plane's `scoped_secrets` store from a project's `secrets.yaml`
|
|
77
|
+
* / `.secrets` contexts. Idempotent: `createContext` upserts, `bind` is a no-op
|
|
78
|
+
* when the scope is already bound, and `setSecret` overwrites in place. Returns
|
|
79
|
+
* the contexts + secret-key count seeded (never the values).
|
|
80
|
+
*/
|
|
81
|
+
async function seedLocalSecrets(planeUrl, adminToken, opts) {
|
|
82
|
+
const client = opts.client ?? new AdminApiClient(planeUrl, adminToken);
|
|
83
|
+
const contexts = await loadLocalSecretContexts(opts.kiciDir);
|
|
84
|
+
const seeded = [];
|
|
85
|
+
let secretCount = 0;
|
|
86
|
+
for (const [contextName, secrets] of Object.entries(contexts)) {
|
|
87
|
+
await client.createContext({
|
|
88
|
+
orgId: opts.orgId,
|
|
89
|
+
name: contextName,
|
|
90
|
+
allowLocalExecution: true
|
|
91
|
+
});
|
|
92
|
+
await client.bindContext({
|
|
93
|
+
orgId: opts.orgId,
|
|
94
|
+
name: contextName,
|
|
95
|
+
scopePattern: contextName,
|
|
96
|
+
hostPattern: "**"
|
|
97
|
+
});
|
|
98
|
+
for (const [key, value] of Object.entries(secrets)) {
|
|
99
|
+
await client.setSecret(opts.orgId, contextName, key, value);
|
|
100
|
+
secretCount++;
|
|
101
|
+
}
|
|
102
|
+
seeded.push(contextName);
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
contexts: seeded,
|
|
106
|
+
secretCount
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
export { loadLocalSecretContexts, seedLocalSecrets };
|
|
111
|
+
|
|
112
|
+
//# sourceMappingURL=secret-seed.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LocalSourceProvider — resolve the workdir a `kici run --local` dispatch
|
|
3
|
+
* registers as a `file://` source for the plane.
|
|
4
|
+
*
|
|
5
|
+
* The plane orchestrator's local provider fetches the lock from
|
|
6
|
+
* `<repoBasePath>/.kici/kici.lock.json` and the ephemeral agent clones
|
|
7
|
+
* `file://<repoBasePath>` at a committed sha. So the resolved workdir must be a
|
|
8
|
+
* git repo whose HEAD carries the workflow + lock the run should execute.
|
|
9
|
+
*
|
|
10
|
+
* Two profiles:
|
|
11
|
+
* - **default (isolated):** an isolated tmp clone at HEAD with the local overlay
|
|
12
|
+
* (dirty + untracked files) applied and committed onto a `kici-local` branch,
|
|
13
|
+
* so the clone-by-sha the agent performs sees uncommitted work without
|
|
14
|
+
* touching the developer's tree.
|
|
15
|
+
* - **`--in-place`:** the repo root directly (ambient state, the profile the CI
|
|
16
|
+
* deploy jobs use). Cleanup is a no-op.
|
|
17
|
+
*/
|
|
18
|
+
/** The `kici-local` branch the isolated profile commits its overlay onto. */
|
|
19
|
+
export declare const LOCAL_RUN_BRANCH = "kici-local";
|
|
20
|
+
/** A resolved workdir plus the git coordinates the plane trigger needs. */
|
|
21
|
+
export interface ResolvedWorkdir {
|
|
22
|
+
/** Absolute path registered as the local source `repoBasePath`. */
|
|
23
|
+
dir: string;
|
|
24
|
+
/** Git ref the synthetic push carries (`refs/heads/<branch>`). */
|
|
25
|
+
ref: string;
|
|
26
|
+
/** Committed HEAD sha the agent clones + checks out. */
|
|
27
|
+
sha: string;
|
|
28
|
+
/** Branch short name (matched by the workflow's push filter). */
|
|
29
|
+
branch: string;
|
|
30
|
+
/** Remove the tmp workdir (no-op for `--in-place`). */
|
|
31
|
+
cleanup: () => Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the workdir for an offline routed run.
|
|
35
|
+
*
|
|
36
|
+
* @param opts.inPlace - Use the repo root directly instead of an isolated clone.
|
|
37
|
+
* @param opts.repoRoot - The developer's repo root.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveWorkdir(opts: {
|
|
40
|
+
inPlace: boolean;
|
|
41
|
+
repoRoot: string;
|
|
42
|
+
}): Promise<ResolvedWorkdir>;
|
|
43
|
+
//# sourceMappingURL=source-provider.d.ts.map
|