@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.
Files changed (50) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +1 -6
  3. package/dist/checkout/git-clone.d.ts +59 -0
  4. package/dist/checkout/ssh-auth.d.ts +34 -0
  5. package/dist/config.d.ts +109 -0
  6. package/dist/execution/console-capture.d.ts +35 -0
  7. package/dist/execution/dep-installer.d.ts +44 -0
  8. package/dist/execution/dep-packer.d.ts +25 -0
  9. package/dist/execution/dep-restore.d.ts +85 -0
  10. package/dist/execution/download.d.ts +29 -0
  11. package/dist/execution/dynamic-job-serializer.d.ts +51 -0
  12. package/dist/execution/hook-executor.d.ts +46 -0
  13. package/dist/execution/init-runner.d.ts +33 -0
  14. package/dist/execution/job-runner.d.ts +266 -0
  15. package/dist/execution/log-streamer.d.ts +126 -0
  16. package/dist/execution/npm-registry-config.d.ts +63 -0
  17. package/dist/execution/npm-resolver.d.ts +40 -0
  18. package/dist/execution/overlay-applier.d.ts +51 -0
  19. package/dist/execution/rule-evaluator.d.ts +11 -0
  20. package/dist/execution/sandbox/bare-metal-sandbox.d.ts +69 -0
  21. package/dist/execution/sandbox/container-sandbox.d.ts +100 -0
  22. package/dist/execution/sandbox/env-sanitizer.d.ts +43 -0
  23. package/dist/execution/sandbox/firecracker-sandbox.d.ts +65 -0
  24. package/dist/execution/sandbox/fork-runner.d.ts +94 -0
  25. package/dist/execution/sandbox/index.d.ts +14 -0
  26. package/dist/execution/sandbox/ipc-protocol.d.ts +311 -0
  27. package/dist/execution/sandbox/log-masker.d.ts +45 -0
  28. package/dist/execution/sandbox/secret-encryption.d.ts +37 -0
  29. package/dist/execution/sandbox/secret-merge.d.ts +18 -0
  30. package/dist/execution/sandbox/step-loop.d.ts +77 -0
  31. package/dist/execution/sandbox/types.d.ts +142 -0
  32. package/dist/execution/sandbox/workflow-runner.d.ts +17 -0
  33. package/dist/execution/source-packer.d.ts +18 -0
  34. package/dist/execution/source-restore.d.ts +23 -0
  35. package/dist/execution/timeout-util.d.ts +11 -0
  36. package/dist/execution/workflow-loader.d.ts +70 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.js +128 -0
  39. package/dist/metrics/metrics-reporter.d.ts +32 -0
  40. package/dist/metrics/prometheus.d.ts +95 -0
  41. package/dist/routes/health.d.ts +27 -0
  42. package/dist/server.d.ts +20 -0
  43. package/dist/server.js +5347 -0
  44. package/dist/workflow-runner.js +2978 -0
  45. package/dist/ws/event-buffer.d.ts +16 -0
  46. package/dist/ws/log-buffer.d.ts +15 -0
  47. package/dist/ws/orchestrator-client.d.ts +269 -0
  48. package/package.json +59 -7
  49. package/sbom.spdx.json +10125 -0
  50. 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
@@ -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