@kici-dev/agent 0.0.0 → 0.1.2
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/LICENSE +661 -0
- package/README.md +1 -6
- package/dist/checkout/git-clone.d.ts +59 -0
- package/dist/checkout/ssh-auth.d.ts +34 -0
- package/dist/config.d.ts +109 -0
- package/dist/execution/console-capture.d.ts +35 -0
- package/dist/execution/dep-installer.d.ts +44 -0
- package/dist/execution/dep-packer.d.ts +25 -0
- package/dist/execution/dep-restore.d.ts +85 -0
- package/dist/execution/download.d.ts +29 -0
- package/dist/execution/dynamic-job-serializer.d.ts +51 -0
- package/dist/execution/hook-executor.d.ts +46 -0
- package/dist/execution/init-runner.d.ts +33 -0
- package/dist/execution/job-runner.d.ts +266 -0
- package/dist/execution/log-streamer.d.ts +126 -0
- package/dist/execution/npm-registry-config.d.ts +63 -0
- package/dist/execution/npm-resolver.d.ts +40 -0
- package/dist/execution/overlay-applier.d.ts +51 -0
- package/dist/execution/rule-evaluator.d.ts +11 -0
- package/dist/execution/sandbox/bare-metal-sandbox.d.ts +69 -0
- package/dist/execution/sandbox/container-sandbox.d.ts +100 -0
- package/dist/execution/sandbox/env-sanitizer.d.ts +43 -0
- package/dist/execution/sandbox/firecracker-sandbox.d.ts +65 -0
- package/dist/execution/sandbox/fork-runner.d.ts +94 -0
- package/dist/execution/sandbox/index.d.ts +14 -0
- package/dist/execution/sandbox/ipc-protocol.d.ts +311 -0
- package/dist/execution/sandbox/log-masker.d.ts +45 -0
- package/dist/execution/sandbox/secret-encryption.d.ts +37 -0
- package/dist/execution/sandbox/secret-merge.d.ts +18 -0
- package/dist/execution/sandbox/step-loop.d.ts +77 -0
- package/dist/execution/sandbox/types.d.ts +142 -0
- package/dist/execution/sandbox/workflow-runner.d.ts +17 -0
- package/dist/execution/source-packer.d.ts +18 -0
- package/dist/execution/source-restore.d.ts +23 -0
- package/dist/execution/timeout-util.d.ts +11 -0
- package/dist/execution/workflow-loader.d.ts +70 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +128 -0
- package/dist/metrics/metrics-reporter.d.ts +32 -0
- package/dist/metrics/prometheus.d.ts +95 -0
- package/dist/routes/health.d.ts +27 -0
- package/dist/server.d.ts +20 -0
- package/dist/server.js +5347 -0
- package/dist/workflow-runner.js +2978 -0
- package/dist/ws/event-buffer.d.ts +16 -0
- package/dist/ws/log-buffer.d.ts +15 -0
- package/dist/ws/orchestrator-client.d.ts +269 -0
- package/package.json +59 -7
- package/sbom.spdx.json +10125 -0
- package/index.js +0 -3
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured clone auth. Mirrors `gitAuthSchema` on the orchestrator-agent
|
|
3
|
+
* protocol so a single shape carries both HTTPS Basic (GitHub App tokens,
|
|
4
|
+
* PATs) and SSH (universal-git, pinned host keys).
|
|
5
|
+
*/
|
|
6
|
+
export interface GitAuth {
|
|
7
|
+
kind: 'basic' | 'ssh';
|
|
8
|
+
/** Basic-auth username. Omit for SSH. */
|
|
9
|
+
user?: string;
|
|
10
|
+
/** Basic-auth password/PAT, or PEM-encoded SSH private key. */
|
|
11
|
+
secret: string;
|
|
12
|
+
/** SSH-only. `accept-new` (default) or `pinned`. */
|
|
13
|
+
sshHostKeyPolicy?: 'accept-new' | 'pinned';
|
|
14
|
+
/** SSH-only. Required when `sshHostKeyPolicy === 'pinned'`. */
|
|
15
|
+
sshKnownHostsPem?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Options for cloning a git repository.
|
|
19
|
+
*/
|
|
20
|
+
interface CloneOptions {
|
|
21
|
+
/** Full HTTPS repo URL (e.g., https://github.com/org/repo.git) */
|
|
22
|
+
repoUrl: string;
|
|
23
|
+
/** Git ref to checkout (branch name or tag) */
|
|
24
|
+
ref: string;
|
|
25
|
+
/** Expected commit SHA (for verification after clone) */
|
|
26
|
+
sha: string;
|
|
27
|
+
/** Directory to clone into */
|
|
28
|
+
workDir: string;
|
|
29
|
+
/**
|
|
30
|
+
* Optional auth token (GitHub installation token or personal token).
|
|
31
|
+
* Deprecated in favour of `gitAuth`; retained for backward compatibility
|
|
32
|
+
* during the Phase 4 universal-git rollout. When both are set, `gitAuth`
|
|
33
|
+
* wins.
|
|
34
|
+
*/
|
|
35
|
+
token?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Structured auth material. When `kind === 'basic'`, gitAuth is used
|
|
38
|
+
* instead of `token` via the same `http.extraHeader` path. When
|
|
39
|
+
* `kind === 'ssh'`, the clone uses `GIT_SSH_COMMAND` with a temp
|
|
40
|
+
* private key (and optional pinned known_hosts).
|
|
41
|
+
*/
|
|
42
|
+
gitAuth?: GitAuth;
|
|
43
|
+
/** Clone depth (default: 1 for shallow clone) */
|
|
44
|
+
depth?: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Shallow-clone a git repository at a specific ref with optional token auth.
|
|
48
|
+
*
|
|
49
|
+
* Token authentication uses git's `-c http.extraHeader` mechanism which keeps
|
|
50
|
+
* the token out of the clone URL (not visible in `git remote -v` or logs).
|
|
51
|
+
*
|
|
52
|
+
* After clone, verifies that HEAD matches the expected SHA to prevent
|
|
53
|
+
* wrong-ref execution.
|
|
54
|
+
*
|
|
55
|
+
* @throws Error if clone fails or SHA does not match
|
|
56
|
+
*/
|
|
57
|
+
export declare function gitClone(options: CloneOptions): Promise<void>;
|
|
58
|
+
export {};
|
|
59
|
+
//# sourceMappingURL=git-clone.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface SshAuthSetup {
|
|
2
|
+
/** Value for the `GIT_SSH_COMMAND` env var. */
|
|
3
|
+
gitSshCommand: string;
|
|
4
|
+
/** Absolute path of the tempdir — used by tests. Not safe to log. */
|
|
5
|
+
tempDir: string;
|
|
6
|
+
/** Removes the tempdir and its contents. Safe to call multiple times. */
|
|
7
|
+
cleanup(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export interface SetupSshAuthOpts {
|
|
10
|
+
/** PEM-encoded private key. Must include trailing newline. */
|
|
11
|
+
privateKey: string;
|
|
12
|
+
/** 'accept-new' (default) trusts first-seen host keys; 'pinned' requires `knownHosts`. */
|
|
13
|
+
hostKeyPolicy?: 'accept-new' | 'pinned';
|
|
14
|
+
/** OpenSSH known_hosts content. Required when `hostKeyPolicy === 'pinned'`. */
|
|
15
|
+
knownHosts?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Materialize an SSH private key (and optional pinned known_hosts) into a
|
|
19
|
+
* tempdir and build the `GIT_SSH_COMMAND` that `git clone` needs.
|
|
20
|
+
*
|
|
21
|
+
* Permissions:
|
|
22
|
+
* - private key mode 0o600 (required by OpenSSH — refuses to use world-
|
|
23
|
+
* readable keys).
|
|
24
|
+
* - known_hosts mode 0o600.
|
|
25
|
+
* - tempdir mode 0o700.
|
|
26
|
+
*
|
|
27
|
+
* SSH flags composed:
|
|
28
|
+
* - `-i <keyfile>` — identity file.
|
|
29
|
+
* - `-o IdentitiesOnly=yes` — don't try other keys from ssh-agent / ~/.ssh.
|
|
30
|
+
* - `-o BatchMode=yes` — never prompt for passwords / passphrases.
|
|
31
|
+
* - host-key checking flags based on `hostKeyPolicy`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function setupSshAuth(opts: SetupSshAuthOpts): Promise<SshAuthSetup>;
|
|
34
|
+
//# sourceMappingURL=ssh-auth.d.ts.map
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Execution mode for the agent's sandbox backend. Mirrors the runtime enum. */
|
|
3
|
+
export declare const ExecutionMode: z.ZodEnum<{
|
|
4
|
+
container: "container";
|
|
5
|
+
"bare-metal": "bare-metal";
|
|
6
|
+
firecracker: "firecracker";
|
|
7
|
+
}>;
|
|
8
|
+
export type ExecutionMode = z.infer<typeof ExecutionMode>;
|
|
9
|
+
declare const configSchema: z.ZodObject<{
|
|
10
|
+
orchestratorUrl: z.ZodString;
|
|
11
|
+
agentId: z.ZodOptional<z.ZodString>;
|
|
12
|
+
labels: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<string[], string>>;
|
|
13
|
+
roles: z.ZodPipe<z.ZodPipe<z.ZodOptional<z.ZodString>, z.ZodTransform<string[] | undefined, string | undefined>>, z.ZodTransform<string[] | undefined, string[] | undefined>>;
|
|
14
|
+
port: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
15
|
+
logLevel: z.ZodDefault<z.ZodEnum<{
|
|
16
|
+
error: "error";
|
|
17
|
+
debug: "debug";
|
|
18
|
+
info: "info";
|
|
19
|
+
warn: "warn";
|
|
20
|
+
}>>;
|
|
21
|
+
agentToken: z.ZodOptional<z.ZodString>;
|
|
22
|
+
githubToken: z.ZodOptional<z.ZodString>;
|
|
23
|
+
maxLogSizeBytes: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
24
|
+
defaultStepTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
25
|
+
dockerKeepFailed: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<boolean, string>>;
|
|
26
|
+
jobHeartbeatIntervalMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
27
|
+
backpressureMode: z.ZodDefault<z.ZodEnum<{
|
|
28
|
+
pause: "pause";
|
|
29
|
+
drop: "drop";
|
|
30
|
+
}>>;
|
|
31
|
+
sandbox: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<boolean, string>>;
|
|
32
|
+
sandboxNetwork: z.ZodDefault<z.ZodEnum<{
|
|
33
|
+
isolated: "isolated";
|
|
34
|
+
host: "host";
|
|
35
|
+
}>>;
|
|
36
|
+
scalerManaged: z.ZodPipe<z.ZodOptional<z.ZodString>, z.ZodTransform<boolean, string | undefined>>;
|
|
37
|
+
scalerIdleTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
38
|
+
scalerPendingDispatchTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
39
|
+
executionMode: z.ZodOptional<z.ZodEnum<{
|
|
40
|
+
container: "container";
|
|
41
|
+
"bare-metal": "bare-metal";
|
|
42
|
+
firecracker: "firecracker";
|
|
43
|
+
}>>;
|
|
44
|
+
otelExporterOtlpEndpoint: z.ZodOptional<z.ZodString>;
|
|
45
|
+
concurrencyWaitTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
46
|
+
}, z.core.$strip>;
|
|
47
|
+
/**
|
|
48
|
+
* App configuration type. Includes computed agentId when not provided.
|
|
49
|
+
*/
|
|
50
|
+
export type AppConfig = z.infer<typeof configSchema> & {
|
|
51
|
+
/** Unique identifier for this agent instance */
|
|
52
|
+
agentId: string;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Env-var definition for the agent. Exported so the docs generator and the
|
|
56
|
+
* deploy-stg pre-validator can inspect / re-parse without round-tripping
|
|
57
|
+
* through process.env.
|
|
58
|
+
*/
|
|
59
|
+
export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
|
|
60
|
+
orchestratorUrl: string;
|
|
61
|
+
labels: string[];
|
|
62
|
+
roles: string[] | undefined;
|
|
63
|
+
port: number;
|
|
64
|
+
logLevel: "error" | "debug" | "info" | "warn";
|
|
65
|
+
maxLogSizeBytes: number;
|
|
66
|
+
defaultStepTimeoutMs: number;
|
|
67
|
+
dockerKeepFailed: boolean;
|
|
68
|
+
jobHeartbeatIntervalMs: number;
|
|
69
|
+
backpressureMode: "pause" | "drop";
|
|
70
|
+
sandbox: boolean;
|
|
71
|
+
sandboxNetwork: "isolated" | "host";
|
|
72
|
+
scalerManaged: boolean;
|
|
73
|
+
scalerIdleTimeoutMs: number;
|
|
74
|
+
scalerPendingDispatchTimeoutMs: number;
|
|
75
|
+
concurrencyWaitTimeoutMs: number;
|
|
76
|
+
agentId?: string | undefined;
|
|
77
|
+
agentToken?: string | undefined;
|
|
78
|
+
githubToken?: string | undefined;
|
|
79
|
+
executionMode?: "container" | "bare-metal" | "firecracker" | undefined;
|
|
80
|
+
otelExporterOtlpEndpoint?: string | undefined;
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* Load and validate agent configuration from environment variables.
|
|
84
|
+
*
|
|
85
|
+
* Maps env vars with KICI_ prefix:
|
|
86
|
+
* - KICI_ORCHESTRATOR_URL (required)
|
|
87
|
+
* - KICI_AGENT_ID (optional, auto-generated from hostname-uuid8)
|
|
88
|
+
* - KICI_LABELS (comma-separated, e.g. "linux,docker"). Labels with 'kici-' prefix are reserved.
|
|
89
|
+
* - KICI_ROLES (comma-separated agent roles, e.g. "builder,init-runner". undefined=all, empty=execution-only)
|
|
90
|
+
* - KICI_PORT (default: 8080)
|
|
91
|
+
* - KICI_LOG_LEVEL (default: info)
|
|
92
|
+
* - KICI_AGENT_TOKEN (optional, kat_ prefixed PSK for orchestrator authentication)
|
|
93
|
+
* - KICI_GITHUB_TOKEN (optional)
|
|
94
|
+
* - KICI_MAX_LOG_SIZE_BYTES (default: 10MB)
|
|
95
|
+
* - KICI_DEFAULT_STEP_TIMEOUT_MS (default: 30 min)
|
|
96
|
+
* - KICI_DOCKER_KEEP_FAILED (default: false)
|
|
97
|
+
* - KICI_JOB_HEARTBEAT_INTERVAL_MS (default: 60000)
|
|
98
|
+
* - KICI_BACKPRESSURE_MODE (default: pause, options: pause | drop)
|
|
99
|
+
* - KICI_SANDBOX (default: false) — enable bubblewrap (bwrap) namespace isolation for bare-metal execution
|
|
100
|
+
* - KICI_SANDBOX_NETWORK (default: isolated, options: isolated | host) — when sandbox=true, controls bwrap network namespace
|
|
101
|
+
* - KICI_SCALER_MANAGED (set to "1" by the orchestrator's auto-scaler — agent self-shuts down on idle)
|
|
102
|
+
* - KICI_SCALER_IDLE_TIMEOUT (ms, default 5000) — how long a scaler-managed agent waits before shutdown after going idle
|
|
103
|
+
* - KICI_SCALER_PENDING_DISPATCH_TIMEOUT (ms, default 60000) — extended idle window when register.ack signals a queued bound job
|
|
104
|
+
* - KICI_EXECUTION_MODE (optional, options: container | bare-metal | firecracker) — override the runner's mode-pick logic
|
|
105
|
+
* - KICI_CONCURRENCY_WAIT_TIMEOUT_MS (default: 3_600_000) — workflow-runner timeout when long-polling for a slot-release follow-up `concurrency.ack`
|
|
106
|
+
*/
|
|
107
|
+
export declare function loadConfig(): AppConfig;
|
|
108
|
+
export {};
|
|
109
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sink for captured console lines.
|
|
3
|
+
*
|
|
4
|
+
* The agent wires this to a per-job LogStreamer so captured lines become
|
|
5
|
+
* log.chunk messages to the orchestrator and dashboard.
|
|
6
|
+
*/
|
|
7
|
+
export interface CaptureSink {
|
|
8
|
+
addLine(line: string): void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Install monkey-patches on console.log / error / warn / info / debug.
|
|
12
|
+
*
|
|
13
|
+
* Idempotent: subsequent calls are no-ops.
|
|
14
|
+
*
|
|
15
|
+
* Does NOT patch process.stdout.write or process.stderr.write. Winston's
|
|
16
|
+
* Console transport writes through those streams directly, so patching them
|
|
17
|
+
* at the agent level would leak agent-internal logger output into user step
|
|
18
|
+
* streams whenever Winston fires on an async stack descended from a user
|
|
19
|
+
* function. Winston bypasses console.*, so patching only console.* is
|
|
20
|
+
* collision-free.
|
|
21
|
+
*/
|
|
22
|
+
export declare function installConsoleCapture(): void;
|
|
23
|
+
/**
|
|
24
|
+
* Run `fn` with the given sink active. console.* calls inside `fn` and any
|
|
25
|
+
* async descendants route to the sink until the returned promise resolves.
|
|
26
|
+
*
|
|
27
|
+
* If `installConsoleCapture()` has not been called, the sink is still tracked
|
|
28
|
+
* in ALS but console.* calls are not intercepted.
|
|
29
|
+
*/
|
|
30
|
+
export declare function runCaptured<T>(sink: CaptureSink, fn: () => T | Promise<T>): Promise<T>;
|
|
31
|
+
/** Test helper: uninstall the console.* patches and restore originals. */
|
|
32
|
+
export declare function _uninstallConsoleCaptureForTests(): void;
|
|
33
|
+
/** Test helper: read the currently active sink, if any. */
|
|
34
|
+
export declare function _getActiveSinkForTests(): CaptureSink | undefined;
|
|
35
|
+
//# sourceMappingURL=console-capture.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline dependency installation for graceful degradation.
|
|
3
|
+
*
|
|
4
|
+
* When dep cache is unavailable or download fails, the agent falls back
|
|
5
|
+
* to running npm install directly.
|
|
6
|
+
*
|
|
7
|
+
* Only npm is supported — it ships with every Node.js installation.
|
|
8
|
+
* .kici/package.json is required — its presence signals deps should be installed.
|
|
9
|
+
*
|
|
10
|
+
* Security: npm runs with an isolated per-invocation cache directory to prevent
|
|
11
|
+
* cache poisoning across build jobs. A malicious package.json in one repo cannot
|
|
12
|
+
* taint the cache used by subsequent builds. The same pressure rules out letting
|
|
13
|
+
* lifecycle scripts see synthesized auth env vars — npm runs with
|
|
14
|
+
* `--ignore-scripts` whenever a private registry is configured.
|
|
15
|
+
*/
|
|
16
|
+
import { type NpmRegistrySpec } from './npm-registry-config.js';
|
|
17
|
+
export interface InstallDepsOptions {
|
|
18
|
+
/** Resolved private npm registries from the orchestrator dispatch. */
|
|
19
|
+
npmRegistries?: readonly NpmRegistrySpec[];
|
|
20
|
+
/** Bare-name secrets to project as install-subprocess env vars. */
|
|
21
|
+
installEnvSecrets?: Record<string, string>;
|
|
22
|
+
/** Short job-scoped nonce — used as suffix on synthesized env-var names. */
|
|
23
|
+
jobIdShort?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Install dependencies inline using npm.
|
|
27
|
+
*
|
|
28
|
+
* Falls back to this when the dep cache is unavailable or download fails.
|
|
29
|
+
*
|
|
30
|
+
* npm runs with an isolated cache directory (created in os.tmpdir()) to prevent
|
|
31
|
+
* cache poisoning between build jobs. The cache is removed after installation.
|
|
32
|
+
*
|
|
33
|
+
* If `opts.npmRegistries` / `opts.installEnvSecrets` is provided, the helper
|
|
34
|
+
* synthesizes a job-scoped `.kici/.npmrc` overlay for the install, restores
|
|
35
|
+
* the original file in `finally`, and runs npm with `--ignore-scripts` so
|
|
36
|
+
* lifecycle scripts in committed `package.json` cannot exfiltrate the
|
|
37
|
+
* synthesized token env vars.
|
|
38
|
+
*
|
|
39
|
+
* @param kiciDir - Path to the .kici/ directory containing package.json
|
|
40
|
+
* @param opts - Optional registry / installEnv configuration. When absent,
|
|
41
|
+
* behavior is identical to the pre-private-registry version.
|
|
42
|
+
*/
|
|
43
|
+
export declare function installDeps(kiciDir: string, opts?: InstallDepsOptions): Promise<void>;
|
|
44
|
+
//# sourceMappingURL=dep-installer.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node_modules tarball creation for build agents.
|
|
3
|
+
*
|
|
4
|
+
* After installing dependencies in .kici/, packs node_modules
|
|
5
|
+
* into a gzip tarball for upload to the dep cache.
|
|
6
|
+
*
|
|
7
|
+
* Uses tar.gz format (Node.js built-in zlib, no external binary needed).
|
|
8
|
+
* Uses portable mode to strip user/group info for cross-machine consistency.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Pack node_modules into a gzip tarball and compute its SHA-256 hash.
|
|
12
|
+
*
|
|
13
|
+
* Creates a tar.gz archive of the `node_modules/` directory relative to
|
|
14
|
+
* kiciDir. The tarball is created in-memory and returned as a Buffer
|
|
15
|
+
* along with its content hash.
|
|
16
|
+
*
|
|
17
|
+
* @param kiciDir - Path to the .kici/ directory containing node_modules/
|
|
18
|
+
* @returns Object with tarball Buffer and SHA-256 hash string
|
|
19
|
+
* @throws Error if node_modules/ does not exist in kiciDir
|
|
20
|
+
*/
|
|
21
|
+
export declare function packNodeModules(kiciDir: string): Promise<{
|
|
22
|
+
tarball: Buffer;
|
|
23
|
+
hash: string;
|
|
24
|
+
}>;
|
|
25
|
+
//# sourceMappingURL=dep-packer.d.ts.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency restoration from cached tarballs.
|
|
3
|
+
*
|
|
4
|
+
* Downloads a pre-built dependency tarball, verifies SHA-256 integrity,
|
|
5
|
+
* and extracts to .kici/node_modules/ in the work directory.
|
|
6
|
+
*
|
|
7
|
+
* HTTP/HTTPS downloads use a streaming pipeline (response -> hash transform ->
|
|
8
|
+
* gunzip -> tar extract) to avoid buffering entire tarballs in memory.
|
|
9
|
+
* file:// URLs use a buffer-based approach (local, no streaming benefit).
|
|
10
|
+
*
|
|
11
|
+
* Streaming downloads have a 5-minute timeout and up to 2 retries.
|
|
12
|
+
*/
|
|
13
|
+
/** Download timeout: 5 minutes. */
|
|
14
|
+
export declare const DOWNLOAD_TIMEOUT_MS: number;
|
|
15
|
+
/** Maximum number of retries for HTTP downloads (0 = no retries). */
|
|
16
|
+
export declare const MAX_RETRIES = 2;
|
|
17
|
+
/**
|
|
18
|
+
* Stream download and extract an HTTP/HTTPS tarball.
|
|
19
|
+
*
|
|
20
|
+
* Computes SHA-256 hash on the fly via a Transform stream.
|
|
21
|
+
* Returns the computed hash of the compressed tarball data.
|
|
22
|
+
*/
|
|
23
|
+
export declare function streamFetchAndExtract(url: string, targetDir: string): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Glob suitable for `.gitignore` / `.git/info/exclude` that matches every
|
|
26
|
+
* scratch dir created by `extractIntoScratch`, anchored to the workflow
|
|
27
|
+
* working tree's `.kici/` subdir.
|
|
28
|
+
*/
|
|
29
|
+
export declare const SCRATCH_DIR_GIT_EXCLUDE_GLOB = ".kici/.dep-restore-scratch-*";
|
|
30
|
+
/**
|
|
31
|
+
* Append `SCRATCH_DIR_GIT_EXCLUDE_GLOB` to `${repoWorkDir}/.git/info/exclude`
|
|
32
|
+
* so any in-flight or orphaned dep-restore scratch dirs are invisible to
|
|
33
|
+
* `git status` / `git add` inside the customer's cloned working tree.
|
|
34
|
+
*
|
|
35
|
+
* Why `.git/info/exclude` and not `.gitignore`:
|
|
36
|
+
* - `.gitignore` lives in the customer's repo and is committed; we MUST NOT
|
|
37
|
+
* modify it. Doing so would surface the rule in their PRs and create a
|
|
38
|
+
* diff customers never asked for.
|
|
39
|
+
* - `.git/info/exclude` is per-clone, on-disk only, and exactly the git
|
|
40
|
+
* mechanism for "ignore these patterns in THIS working tree". Git creates
|
|
41
|
+
* an empty (template-commented) file on `git init` / `git clone`, so it
|
|
42
|
+
* already exists by the time we're called.
|
|
43
|
+
*
|
|
44
|
+
* Why this lives next to `extractIntoScratch`:
|
|
45
|
+
* - The exclude glob is tied 1:1 to the scratch dir naming convention. If
|
|
46
|
+
* the prefix ever changes, the rule must change too. Defining both in the
|
|
47
|
+
* same file means a rename touches one place, not two.
|
|
48
|
+
*
|
|
49
|
+
* Best-effort: if the exclude file is missing (e.g. caller sandbox blocked
|
|
50
|
+
* `git clone` and the dir layout differs) we log and continue — failing the
|
|
51
|
+
* job over a missing git ignore wiring would be worse than the cosmetic
|
|
52
|
+
* issue we're solving.
|
|
53
|
+
*
|
|
54
|
+
* Idempotent: callers may invoke this multiple times (dual-clone path, retry
|
|
55
|
+
* after partial setup). We skip the append if the glob is already present.
|
|
56
|
+
*
|
|
57
|
+
* @param repoWorkDir - The git working tree root (the dir that contains
|
|
58
|
+
* `.git/`). For normal workflows this is the agent's job workDir; for
|
|
59
|
+
* global workflows it is the workflow repo dir (whose `.kici/` carries
|
|
60
|
+
* the scratch dirs).
|
|
61
|
+
*/
|
|
62
|
+
export declare function excludeScratchFromGit(repoWorkDir: string): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Rewrite localhost URLs to use the orchestrator host.
|
|
65
|
+
*
|
|
66
|
+
* The orchestrator rewrites file:// cache URLs to http://localhost:PORT/...
|
|
67
|
+
* but agent containers can't reach localhost. This utility replaces the
|
|
68
|
+
* host with the orchestrator's host derived from KICI_ORCHESTRATOR_URL.
|
|
69
|
+
*/
|
|
70
|
+
export declare function resolveOrchestratorUrl(url: string): string;
|
|
71
|
+
/**
|
|
72
|
+
* Restore dependencies from a cached tarball.
|
|
73
|
+
*
|
|
74
|
+
* For HTTP/HTTPS URLs: uses a streaming pipeline (response -> hash -> gunzip -> tar)
|
|
75
|
+
* with a 5-minute timeout and up to 2 retries. This avoids buffering entire tarballs
|
|
76
|
+
* in memory, eliminating memory spikes proportional to tarball size.
|
|
77
|
+
*
|
|
78
|
+
* For file:// URLs: uses a buffer-based approach (local, no streaming benefit).
|
|
79
|
+
*
|
|
80
|
+
* @param workDir - Root directory of the cloned repository
|
|
81
|
+
* @param depsUrl - URL to the dependency tarball (http://, https://, or file://)
|
|
82
|
+
* @param depsHash - Optional expected SHA-256 hash of the tarball
|
|
83
|
+
*/
|
|
84
|
+
export declare function restoreDeps(workDir: string, depsUrl: string, depsHash?: string): Promise<void>;
|
|
85
|
+
//# sourceMappingURL=dep-restore.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared HTTP/HTTPS download utility.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from workflow-loader.ts to avoid duplication across
|
|
5
|
+
* dep-restore.ts and workflow-loader.ts.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Download content from an HTTP/HTTPS URL.
|
|
9
|
+
*
|
|
10
|
+
* Includes a 5-minute timeout to prevent the agent from hanging indefinitely
|
|
11
|
+
* on slow or unresponsive endpoints.
|
|
12
|
+
*
|
|
13
|
+
* @param url - The URL to download from
|
|
14
|
+
* @returns The response body as a Buffer
|
|
15
|
+
*/
|
|
16
|
+
export declare function downloadUrl(url: string): Promise<Buffer>;
|
|
17
|
+
/**
|
|
18
|
+
* Upload a buffer to a pre-signed S3 URL via HTTP PUT.
|
|
19
|
+
*
|
|
20
|
+
* Used for direct-to-S3 uploads of bundles and dep tarballs. Localhost /
|
|
21
|
+
* 127.0.0.1 URLs are rewritten via `resolveOrchestratorUrl` so the
|
|
22
|
+
* filesystem cache backend's signed URLs work from container agents that
|
|
23
|
+
* can't reach the orchestrator's host loopback directly.
|
|
24
|
+
*
|
|
25
|
+
* @param url - The pre-signed URL to upload to
|
|
26
|
+
* @param data - The buffer to upload
|
|
27
|
+
*/
|
|
28
|
+
export declare function uploadToPresignedUrl(url: string, data: Buffer): Promise<void>;
|
|
29
|
+
//# sourceMappingURL=download.d.ts.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serializes SDK Job[] objects returned by a DynamicJobFn into LockJob[] format.
|
|
3
|
+
*
|
|
4
|
+
* This is the runtime equivalent of the compiler's transformJob() in lockfile/generator.ts.
|
|
5
|
+
* It converts rich SDK Job objects (with function references) into the minimal lock file
|
|
6
|
+
* representation that the orchestrator can process.
|
|
7
|
+
*
|
|
8
|
+
* Dynamic env/environment/concurrencyGroup/matrix functions on generated jobs are
|
|
9
|
+
* evaluated inline against the eval context (the same `event`, `$`, `log`, `env`
|
|
10
|
+
* already passed to the parent DynamicJobFn) and embedded as static lock fields.
|
|
11
|
+
* Each dynamic function call is wrapped in `withTimeout` (default 60s) mirroring
|
|
12
|
+
* `init-runner.ts`. Functions returning `undefined`/`null` leave the field unset.
|
|
13
|
+
*
|
|
14
|
+
* Constraints:
|
|
15
|
+
* - Generated jobs are limited to MAX_DYNAMIC_JOBS per DynamicJobFn invocation
|
|
16
|
+
* - Generated job names must be unique within the same DynamicJobFn output
|
|
17
|
+
*/
|
|
18
|
+
import type { $ as Shell } from 'zx';
|
|
19
|
+
import type { Job, Logger } from '@kici-dev/sdk';
|
|
20
|
+
import type { LockJob } from '@kici-dev/engine';
|
|
21
|
+
/** Maximum number of jobs a single DynamicJobFn can generate. */
|
|
22
|
+
export declare const MAX_DYNAMIC_JOBS = 100;
|
|
23
|
+
/**
|
|
24
|
+
* Context required to resolve dynamic env/environment/concurrencyGroup/matrix
|
|
25
|
+
* functions on generated jobs. The eval agent already has every field needed
|
|
26
|
+
* (it's the same context that was just passed to the parent DynamicJobFn), so
|
|
27
|
+
* we thread it through the serializer rather than re-creating it.
|
|
28
|
+
*/
|
|
29
|
+
export interface SerializerContext {
|
|
30
|
+
/** Webhook event payload — passed as the first argument to env/environment/concurrencyGroup fns. */
|
|
31
|
+
event: Record<string, unknown>;
|
|
32
|
+
/** zx shell — passed to dynamic matrix fns. */
|
|
33
|
+
$: typeof Shell;
|
|
34
|
+
/** Logger — passed to dynamic matrix fns. */
|
|
35
|
+
log: Logger;
|
|
36
|
+
/** Environment variables — passed to dynamic matrix fns. */
|
|
37
|
+
env: Record<string, string | undefined>;
|
|
38
|
+
/** Workflow name — surfaced through DynamicMatrixContext.ctx.workflow.name. */
|
|
39
|
+
workflowName: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Convert an array of SDK Job objects into LockJob format for the orchestrator.
|
|
43
|
+
*
|
|
44
|
+
* @param jobs - Jobs returned by a DynamicJobFn
|
|
45
|
+
* @param ctx - Eval-time context used to resolve dynamic fields on generated jobs
|
|
46
|
+
* @returns Serialized LockJob array ready for orchestrator dispatch
|
|
47
|
+
* @throws Error if validation fails (duplicates, limit exceeded) or if a user-supplied
|
|
48
|
+
* dynamic function throws / times out / returns an unsupported value
|
|
49
|
+
*/
|
|
50
|
+
export declare function serializeJobsToLock(jobs: Job[], ctx: SerializerContext, staticNames?: Set<string>, allowedGroups?: Set<string>): Promise<LockJob[]>;
|
|
51
|
+
//# sourceMappingURL=dynamic-job-serializer.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook executor module -- shared hook execution logic with timeout, error handling,
|
|
3
|
+
* and outcome metadata construction.
|
|
4
|
+
*
|
|
5
|
+
* Hooks run inline within the workflow-runner process (same sandbox), not as
|
|
6
|
+
* separate child processes. IPC messages are for status reporting to the
|
|
7
|
+
* fork-runner, which relays to the agent's job-runner.
|
|
8
|
+
*/
|
|
9
|
+
import type { HookConfig, OutcomeMetadata, HookInput } from '@kici-dev/sdk';
|
|
10
|
+
import type { StepContext } from '@kici-dev/sdk';
|
|
11
|
+
import type { RunnerToAgentMessage } from './sandbox/ipc-protocol.js';
|
|
12
|
+
/**
|
|
13
|
+
* Build outcome metadata from execution state.
|
|
14
|
+
*
|
|
15
|
+
* Duration is calculated as elapsed time since startTime.
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildOutcomeMetadata(opts: {
|
|
18
|
+
status: 'cancelled' | 'success' | 'failed';
|
|
19
|
+
reason?: string;
|
|
20
|
+
failedStep?: string;
|
|
21
|
+
stepOutputs: Record<string, unknown>;
|
|
22
|
+
startTime: number;
|
|
23
|
+
}): OutcomeMetadata;
|
|
24
|
+
interface ExecuteHookOptions {
|
|
25
|
+
hook: HookInput | HookConfig;
|
|
26
|
+
stepContext: StepContext;
|
|
27
|
+
outcome: OutcomeMetadata;
|
|
28
|
+
hookType: string;
|
|
29
|
+
stepIndex: number;
|
|
30
|
+
sendIpc: (msg: RunnerToAgentMessage) => void;
|
|
31
|
+
/** Default timeout in ms (overridden by hook-level timeout). Defaults to 5 minutes. */
|
|
32
|
+
timeout?: number;
|
|
33
|
+
}
|
|
34
|
+
interface ExecuteHookResult {
|
|
35
|
+
success: boolean;
|
|
36
|
+
error?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Execute a single hook with timeout enforcement and IPC reporting.
|
|
40
|
+
*
|
|
41
|
+
* Sends step.start and step.complete IPC messages with step_type = 'hook:{hookType}'.
|
|
42
|
+
* The hook runs in the same sandbox context as regular steps.
|
|
43
|
+
*/
|
|
44
|
+
export declare function executeHook(opts: ExecuteHookOptions): Promise<ExecuteHookResult>;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=hook-executor.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Workflow } from '@kici-dev/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Result of evaluating dynamic fields on a job.
|
|
4
|
+
* Only fields that were flagged as dynamic and successfully resolved are set.
|
|
5
|
+
*/
|
|
6
|
+
export interface InitResult {
|
|
7
|
+
environmentName?: string;
|
|
8
|
+
env?: Record<string, string>;
|
|
9
|
+
concurrencyGroup?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Evaluate dynamic fields (environment, env, concurrencyGroup) on a job.
|
|
13
|
+
*
|
|
14
|
+
* Only fields with their corresponding flag set to true AND whose property
|
|
15
|
+
* on the job is a function will be evaluated. All evaluations happen in a
|
|
16
|
+
* single call per.
|
|
17
|
+
*
|
|
18
|
+
* -: If a dynamic function throws, the error propagates (job fails).
|
|
19
|
+
* -: If a dynamic function returns undefined/null, the field is left undefined.
|
|
20
|
+
* -: Each dynamic function call is wrapped in a timeout (default 60s).
|
|
21
|
+
*
|
|
22
|
+
* @param workflow - The extracted Workflow object
|
|
23
|
+
* @param jobName - Name of the job whose dynamic fields to evaluate
|
|
24
|
+
* @param event - Normalized webhook event data, passed as argument to dynamic functions
|
|
25
|
+
* @param flags - Which fields are dynamic and need evaluation
|
|
26
|
+
* @param timeoutMs - Timeout per dynamic function call (default 60_000ms)
|
|
27
|
+
*/
|
|
28
|
+
export declare function evaluateDynamicFields(workflow: Workflow, jobName: string, event: Record<string, unknown>, flags: {
|
|
29
|
+
dynamicEnvironment: boolean;
|
|
30
|
+
dynamicEnv: boolean;
|
|
31
|
+
dynamicConcurrencyGroup: boolean;
|
|
32
|
+
}, timeoutMs?: number): Promise<InitResult>;
|
|
33
|
+
//# sourceMappingURL=init-runner.d.ts.map
|