@solosoficial/plugin-kubernetes 0.0.0-stage → 2026.1010.0-canary.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.
Files changed (92) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +162 -2
  3. package/dist/adapter-defaults.d.ts +29 -0
  4. package/dist/adapter-defaults.d.ts.map +1 -0
  5. package/dist/adapter-defaults.js +104 -0
  6. package/dist/adapter-defaults.js.map +1 -0
  7. package/dist/adapter-registry.d.ts +64 -0
  8. package/dist/adapter-registry.d.ts.map +1 -0
  9. package/dist/adapter-registry.js +25 -0
  10. package/dist/adapter-registry.js.map +1 -0
  11. package/dist/cilium-network-policy.d.ts +8 -0
  12. package/dist/cilium-network-policy.d.ts.map +1 -0
  13. package/dist/cilium-network-policy.js +57 -0
  14. package/dist/cilium-network-policy.js.map +1 -0
  15. package/dist/image-allowlist.d.ts +18 -0
  16. package/dist/image-allowlist.d.ts.map +1 -0
  17. package/dist/image-allowlist.js +39 -0
  18. package/dist/image-allowlist.js.map +1 -0
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +3 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/job-orchestrator.d.ts +24 -0
  24. package/dist/job-orchestrator.d.ts.map +1 -0
  25. package/dist/job-orchestrator.js +90 -0
  26. package/dist/job-orchestrator.js.map +1 -0
  27. package/dist/kube-client.d.ts +15 -0
  28. package/dist/kube-client.d.ts.map +1 -0
  29. package/dist/kube-client.js +23 -0
  30. package/dist/kube-client.js.map +1 -0
  31. package/dist/lease-lifecycle.d.ts +62 -0
  32. package/dist/lease-lifecycle.d.ts.map +1 -0
  33. package/dist/lease-lifecycle.js +155 -0
  34. package/dist/lease-lifecycle.js.map +1 -0
  35. package/dist/manifest.d.ts +4 -0
  36. package/dist/manifest.d.ts.map +1 -0
  37. package/dist/manifest.js +108 -0
  38. package/dist/manifest.js.map +1 -0
  39. package/dist/network-policy.d.ts +18 -0
  40. package/dist/network-policy.d.ts.map +1 -0
  41. package/dist/network-policy.js +113 -0
  42. package/dist/network-policy.js.map +1 -0
  43. package/dist/plugin.d.ts +3 -0
  44. package/dist/plugin.d.ts.map +1 -0
  45. package/dist/plugin.js +687 -0
  46. package/dist/plugin.js.map +1 -0
  47. package/dist/pod-exec.d.ts +28 -0
  48. package/dist/pod-exec.d.ts.map +1 -0
  49. package/dist/pod-exec.js +164 -0
  50. package/dist/pod-exec.js.map +1 -0
  51. package/dist/pod-spec-builder.d.ts +25 -0
  52. package/dist/pod-spec-builder.d.ts.map +1 -0
  53. package/dist/pod-spec-builder.js +82 -0
  54. package/dist/pod-spec-builder.js.map +1 -0
  55. package/dist/sandbox-cr-builder.d.ts +40 -0
  56. package/dist/sandbox-cr-builder.d.ts.map +1 -0
  57. package/dist/sandbox-cr-builder.js +123 -0
  58. package/dist/sandbox-cr-builder.js.map +1 -0
  59. package/dist/sandbox-cr-orchestrator.d.ts +62 -0
  60. package/dist/sandbox-cr-orchestrator.d.ts.map +1 -0
  61. package/dist/sandbox-cr-orchestrator.js +248 -0
  62. package/dist/sandbox-cr-orchestrator.js.map +1 -0
  63. package/dist/sandbox-orchestrator.d.ts +39 -0
  64. package/dist/sandbox-orchestrator.d.ts.map +1 -0
  65. package/dist/sandbox-orchestrator.js +2 -0
  66. package/dist/sandbox-orchestrator.js.map +1 -0
  67. package/dist/secret-manager.d.ts +14 -0
  68. package/dist/secret-manager.d.ts.map +1 -0
  69. package/dist/secret-manager.js +39 -0
  70. package/dist/secret-manager.js.map +1 -0
  71. package/dist/tenant-orchestrator.d.ts +35 -0
  72. package/dist/tenant-orchestrator.d.ts.map +1 -0
  73. package/dist/tenant-orchestrator.js +263 -0
  74. package/dist/tenant-orchestrator.js.map +1 -0
  75. package/dist/types.d.ts +264 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +65 -0
  78. package/dist/types.js.map +1 -0
  79. package/dist/upload-interceptor.d.ts +44 -0
  80. package/dist/upload-interceptor.d.ts.map +1 -0
  81. package/dist/upload-interceptor.js +114 -0
  82. package/dist/upload-interceptor.js.map +1 -0
  83. package/dist/utils.d.ts +11 -0
  84. package/dist/utils.d.ts.map +1 -0
  85. package/dist/utils.js +51 -0
  86. package/dist/utils.js.map +1 -0
  87. package/dist/worker.d.ts +3 -0
  88. package/dist/worker.d.ts.map +1 -0
  89. package/dist/worker.js +5 -0
  90. package/dist/worker.js.map +1 -0
  91. package/manifests/operator-prerequisites.yaml +22 -0
  92. package/package.json +44 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Paperclip AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,163 @@
1
- # Temporary Holding Version
1
+ # @paperclipai/plugin-kubernetes (alpha)
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ First-party Paperclip sandbox-provider plugin for Kubernetes.
4
+
5
+ **Alpha:** the default backend (`sandbox-cr`) is built on `kubernetes-sigs/agent-sandbox` v1alpha1 — expect breaking changes as that CRD evolves toward Beta. A stable fallback backend (`job`, using `batch/v1` Job) is available for clusters without agent-sandbox installed, but it does NOT support multi-command exec (paperclip-server's adapter-install pattern requires sandbox-cr).
6
+
7
+ ## Prerequisites
8
+
9
+ ### For `sandbox-cr` backend (default, recommended)
10
+
11
+ 1. A Kubernetes cluster running k8s 1.27+
12
+ 2. [`kubernetes-sigs/agent-sandbox`](https://github.com/kubernetes-sigs/agent-sandbox) controller installed in the cluster (alpha — installs the `sandboxes.agents.x-k8s.io/v1alpha1` CRD and controller)
13
+ 3. Paperclip-server running with access to the cluster (in-cluster via `inCluster: true` or external via `kubeconfig`)
14
+
15
+ ### For `job` backend (stable fallback)
16
+
17
+ 1. A Kubernetes cluster running k8s 1.27+
18
+ 2. Paperclip-server with cluster access — no additional controllers or CRDs required
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ paperclipai plugin install @paperclipai/plugin-kubernetes
24
+ ```
25
+
26
+ Or, for local development:
27
+
28
+ ```bash
29
+ paperclipai plugin install --local /path/to/paperclip/packages/plugins/sandbox-providers/kubernetes
30
+ ```
31
+
32
+ ## Backends
33
+
34
+ The plugin supports two backend modes, selected via the `backend` config field:
35
+
36
+ | Backend | Default | Stability | Multi-command exec | Requires |
37
+ |---|---|---|---|---|
38
+ | `sandbox-cr` | Yes | Alpha | Yes | `kubernetes-sigs/agent-sandbox` controller |
39
+ | `job` | No | Stable | No | Nothing beyond k8s 1.27+ |
40
+
41
+ **`sandbox-cr` (default):** Creates a `Sandbox` CR (`agents.x-k8s.io/v1alpha1`) whose controller provisions a long-lived pod running `sleep infinity`. paperclip-server execs individual commands into the running pod — this is the multi-command adapter-install pattern. When you `releaseLease`, the Sandbox CR is deleted and the controller tears down the pod.
42
+
43
+ **`job` (stable fallback):** Creates a `batch/v1` Job. The container entrypoint runs once and exits — no multi-command exec possible. Use this when you cannot install agent-sandbox, or when you need strictly stable Kubernetes APIs. Note: paperclip-server's adapter-install pattern will not work in job mode.
44
+
45
+ ### Migrating from `job` to `sandbox-cr`
46
+
47
+ 1. Install the agent-sandbox controller: `kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/latest/download/install.yaml`
48
+ 2. Update your environment config to set `backend: "sandbox-cr"` (or remove `backend` since `sandbox-cr` is the default)
49
+ 3. New leases will use the Sandbox CR backend. Existing leases created with `job` mode continue to use job semantics until they are released.
50
+
51
+ ## Configuration
52
+
53
+ Create a `sandbox` environment with `driver: kubernetes`. One of these auth fields is required:
54
+
55
+ - `inCluster: true` — use the in-pod ServiceAccount credentials (when paperclip-server runs inside the same cluster).
56
+ - `kubeconfig: <YAML>` — inline kubeconfig (stored as a company secret).
57
+ - `kubeconfigSecretRef: <secret-uuid>` — reference to an existing Paperclip secret.
58
+
59
+ Common optional fields:
60
+
61
+ | Field | Default | Purpose |
62
+ |---|---|---|
63
+ | `backend` | `"sandbox-cr"` | `sandbox-cr` (alpha, requires agent-sandbox controller) or `job` (stable, one-shot entrypoint). |
64
+ | `adapterType` | `"claude_local"` | One of the supported adapter types (claude_local, codex_local, gemini_local, cursor_local, opencode_local, acpx_local, pi_local). Determines runtime image + env keys + egress allow-list. |
65
+ | `namespacePrefix` | `"paperclip-"` | Prefix for the per-company tenant namespace. |
66
+ | `companySlug` | derived from companyId | Override the auto-derived company slug. |
67
+ | `imageRegistry` | (none) | Override the default registry for agent runtime images. |
68
+ | `imageAllowList` | `[]` | Glob patterns of allowed `target.imageOverride` values. Empty = no override permitted. |
69
+ | `imagePullSecrets` | `[]` | Names of pre-created Docker image pull secrets in the tenant namespace. |
70
+ | `egressAllowFqdns` | `[]` | Additional FQDNs (beyond adapter defaults like `api.anthropic.com`). |
71
+ | `egressAllowCidrs` | `[]` | Additional CIDRs to allow egress to. |
72
+ | `egressMode` | `"standard"` | `standard` (NetworkPolicy + CIDRs) or `cilium` (CiliumNetworkPolicy + FQDN allow-list). |
73
+ | `runtimeClassName` | (none) | e.g. `kata-fc` for Firecracker-backed microVMs. Cluster must have the RuntimeClass installed. |
74
+ | `serviceAccountAnnotations` | `{}` | Annotations applied to per-tenant ServiceAccount (e.g. IRSA `eks.amazonaws.com/role-arn`). |
75
+ | `jobTtlSecondsAfterFinished` | `900` | Seconds after a Job completes before garbage-collection. |
76
+ | `podActivityDeadlineSec` | `3600` | Hard ceiling on a single run's wall-clock time. |
77
+
78
+ Full JSON Schema in `src/manifest.ts`.
79
+
80
+ ## What gets created in your cluster
81
+
82
+ For each company that runs agents (created lazily on first dispatch):
83
+
84
+ ```
85
+ Namespace paperclip-{companySlug} (PSS: restricted enforce + audit)
86
+ ServiceAccount paperclip-tenant-sa
87
+ Role paperclip-tenant-role (only get pods/log)
88
+ RoleBinding paperclip-tenant-rb
89
+ ResourceQuota paperclip-quota (pods, requests/limits cpu+memory)
90
+ LimitRange paperclip-limits (container max/min/default/defaultRequest)
91
+ NetworkPolicy paperclip-deny-all (deny ingress + egress baseline)
92
+ NetworkPolicy paperclip-egress-allow (DNS + paperclip-server callback + user CIDRs)
93
+ OR CiliumNetworkPolicy paperclip-egress-fqdn if egressMode=cilium
94
+ ```
95
+
96
+ For each agent run (sandbox-cr backend):
97
+
98
+ ```
99
+ Sandbox CR pc-{ulid} (agents.x-k8s.io/v1alpha1; explicit delete on release)
100
+ Pod pc-{ulid}-{podSuffix} (managed by Sandbox controller; torn down on CR delete)
101
+ Secret pc-{ulid}-env (owned by Sandbox CR; cascade-deleted)
102
+ ```
103
+
104
+ For each agent run (job backend):
105
+
106
+ ```
107
+ Job pc-{ulid} (backoffLimit: 0, ttlSecondsAfterFinished from config)
108
+ Pod pc-{ulid}-{podSuffix} (owned by Job; cascade-deleted)
109
+ Secret pc-{ulid}-env (owned by Job; cascade-deleted)
110
+ ```
111
+
112
+ ## Security baseline
113
+
114
+ Every agent pod is:
115
+
116
+ - non-root (`runAsUser: 1000`, `runAsGroup: 1000`, `runAsNonRoot: true`)
117
+ - drops ALL Linux capabilities, `allowPrivilegeEscalation: false`
118
+ - `readOnlyRootFilesystem: true` with explicit `emptyDir` mounts for `/workspace`, `/home/paperclip`, `/home/paperclip/.cache`, `/tmp`
119
+ - `seccompProfile: RuntimeDefault`
120
+ - Tini as PID 1 (reaps zombies, forwards signals)
121
+ - `fsGroupChangePolicy: OnRootMismatch` (fast PVC startup; openclaw-operator lesson)
122
+ - `automountServiceAccountToken: true` (for the agent shim's paperclip-server callback)
123
+
124
+ Plus per-namespace `pod-security.kubernetes.io/enforce: restricted` and a deny-all NetworkPolicy baseline with explicit egress allow-list (DNS, paperclip-server, configured FQDNs/CIDRs).
125
+
126
+ The per-run Secret carrying the bootstrap token and adapter API keys has `ownerReferences` pointing at the owning Job, so a single `kubectl delete job …` cascades cleanly to the Pod and Secret.
127
+
128
+ ## Optional Kata-FC microVM isolation
129
+
130
+ For stronger isolation, install [Kata Containers](https://github.com/kata-containers/kata-containers) with the Firecracker hypervisor, then set `runtimeClassName: kata-fc` in the plugin config. Each agent pod will run inside a Firecracker microVM. Requires nested-virt-capable nodes (bare-metal or specific cloud instance types).
131
+
132
+ ## Roadmap
133
+
134
+ - **Phase A (done):** `sandbox-cr` backend — multi-command exec via agent-sandbox Sandbox CRD.
135
+ - **Phase B:** Warm pool support — pre-provisioned Sandbox CRs for sub-second cold starts. The `SandboxOrchestrator` interface reserves optional `pause?`/`resume?` extension slots.
136
+ - **Phase C:** Kata-FC + snapshots — `runtimeClassName: kata-fc` with VM snapshot for fast restore.
137
+ - **Phase D:** Contribute back to agent-sandbox upstream if their Beta model diverges from our needs. The `SandboxOrchestrator` interface (`src/sandbox-orchestrator.ts`) is the clean swap point — a new implementation can be added without touching `plugin.ts` business logic.
138
+
139
+ ## Lessons learned (from openclaw-operator)
140
+
141
+ This plugin adopts patterns from `openclaw-rocks/openclaw-operator`:
142
+
143
+ - Tini PID 1 (issue #471 — zombie helper processes)
144
+ - Read-only rootFS with explicit writable mounts (issue #456 — ~/.config not writable)
145
+ - Strategic merge on reconcile (issue #446 — preserve third-party annotations)
146
+ - Multi-storage-class testing (issue #448 — `local-path-provisioner` differences)
147
+ - Image version compat matrix (issue #462 — runtime deps cannot resolve after upgrade)
148
+
149
+ ## Development
150
+
151
+ ```bash
152
+ cd packages/plugins/sandbox-providers/kubernetes
153
+ pnpm install --ignore-workspace
154
+ pnpm test # unit tests only (fast)
155
+ pnpm typecheck
156
+ pnpm build
157
+ ```
158
+
159
+ To run the kind-cluster integration test (requires `kubectl --context kind-paperclip` and a pre-loaded alpine image; see `test/integration/end-to-end-run.test.ts`):
160
+
161
+ ```bash
162
+ RUN_K8S_INTEGRATION_TESTS=1 pnpm test test/integration/end-to-end-run.test.ts
163
+ ```
@@ -0,0 +1,29 @@
1
+ import type { AdapterRegistryEntry } from "./adapter-registry.js";
2
+ export interface AdapterDefaults {
3
+ runtimeImage: string;
4
+ envKeys: string[];
5
+ allowFqdns: string[];
6
+ probeCommand: string[];
7
+ /** Non-secret env injected as the base layer for the Job (process-env wins on top). */
8
+ defaultEnv?: Record<string, string>;
9
+ }
10
+ export declare const KNOWN_ADAPTER_TYPES: ReadonlySet<string>;
11
+ /**
12
+ * Resolve the runtime defaults for an adapter. When a `registry` is supplied it
13
+ * is authoritative (replace semantics): the type MUST be present and complete,
14
+ * else this throws. With no registry, falls back to the built-in REGISTRY.
15
+ */
16
+ export declare function getAdapterDefaults(adapterType: string, registry?: readonly AdapterRegistryEntry[]): AdapterDefaults;
17
+ /**
18
+ * Resolve the adapter type for a single run: prefer the run's adapter (the agent's,
19
+ * from the lease params) so one environment can serve mixed harnesses; fall back to
20
+ * the environment's configured default adapter when the run does not specify one.
21
+ */
22
+ export declare function resolveRunAdapterType(runAdapterType: string | null | undefined, configAdapterType: string): string;
23
+ /**
24
+ * Build the per-run env for the Job: the non-secret `defaultEnv` is the base
25
+ * and the process-env values (the secret API keys named by `envKeys`) override
26
+ * it. Pure for testability.
27
+ */
28
+ export declare function buildAdapterEnv(defaults: AdapterDefaults, processEnv?: NodeJS.ProcessEnv): Record<string, string>;
29
+ //# sourceMappingURL=adapter-defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-defaults.d.ts","sourceRoot":"","sources":["../src/adapter-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AA+CD,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,MAAM,CAAkC,CAAC;AAqBvF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,SAAS,oBAAoB,EAAE,GACzC,eAAe,CAajB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,iBAAiB,EAAE,MAAM,GACxB,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,eAAe,EACzB,UAAU,GAAE,MAAM,CAAC,UAAwB,GAC1C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxB"}
@@ -0,0 +1,104 @@
1
+ const REGISTRY = {
2
+ claude_local: {
3
+ runtimeImage: "ghcr.io/paperclipai/agent-runtime-claude:v1",
4
+ envKeys: ["ANTHROPIC_API_KEY"],
5
+ allowFqdns: ["api.anthropic.com"],
6
+ probeCommand: ["claude", "--version"],
7
+ },
8
+ codex_local: {
9
+ runtimeImage: "ghcr.io/paperclipai/agent-runtime-codex:v1",
10
+ envKeys: ["OPENAI_API_KEY"],
11
+ allowFqdns: ["api.openai.com"],
12
+ probeCommand: ["codex", "--version"],
13
+ },
14
+ gemini_local: {
15
+ runtimeImage: "ghcr.io/paperclipai/agent-runtime-gemini:v1",
16
+ envKeys: ["GOOGLE_API_KEY", "GEMINI_API_KEY"],
17
+ allowFqdns: ["generativelanguage.googleapis.com"],
18
+ probeCommand: ["gemini", "--version"],
19
+ },
20
+ cursor_local: {
21
+ runtimeImage: "ghcr.io/paperclipai/agent-runtime-cursor:v1",
22
+ envKeys: ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"],
23
+ allowFqdns: ["api.anthropic.com", "api.openai.com"],
24
+ probeCommand: ["cursor-agent", "--version"],
25
+ },
26
+ opencode_local: {
27
+ runtimeImage: "ghcr.io/paperclipai/agent-runtime-opencode:v1",
28
+ envKeys: ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "OPENROUTER_API_KEY"],
29
+ allowFqdns: ["api.anthropic.com", "api.openai.com", "openrouter.ai"],
30
+ probeCommand: ["opencode", "--version"],
31
+ },
32
+ acpx_local: {
33
+ runtimeImage: "ghcr.io/paperclipai/agent-runtime-acpx:v1",
34
+ envKeys: ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"],
35
+ allowFqdns: ["api.anthropic.com", "api.openai.com"],
36
+ probeCommand: ["acpx", "--version"],
37
+ },
38
+ pi_local: {
39
+ runtimeImage: "ghcr.io/paperclipai/agent-runtime-pi:v1",
40
+ envKeys: ["ANTHROPIC_API_KEY"],
41
+ allowFqdns: ["api.anthropic.com"],
42
+ probeCommand: ["pi", "--version"],
43
+ },
44
+ };
45
+ export const KNOWN_ADAPTER_TYPES = new Set(Object.keys(REGISTRY));
46
+ function fromRegistryEntry(entry) {
47
+ // Only runtimeImage is strictly required. The array fields are optional and
48
+ // default to []: the operator emits them with `omitempty`, so a genuinely
49
+ // empty allowFqdns/envKeys/probeCommand arrives as undefined, which is valid
50
+ // (no extra egress / no forwarded secrets / no probe), NOT an error.
51
+ if (!entry.runtimeImage) {
52
+ throw new Error(`Adapter "${entry.adapterType}" is missing required runtime field: runtimeImage`);
53
+ }
54
+ return {
55
+ runtimeImage: entry.runtimeImage,
56
+ envKeys: entry.envKeys ?? [],
57
+ allowFqdns: entry.allowFqdns ?? [],
58
+ probeCommand: entry.probeCommand ?? [],
59
+ defaultEnv: entry.defaultEnv,
60
+ };
61
+ }
62
+ /**
63
+ * Resolve the runtime defaults for an adapter. When a `registry` is supplied it
64
+ * is authoritative (replace semantics): the type MUST be present and complete,
65
+ * else this throws. With no registry, falls back to the built-in REGISTRY.
66
+ */
67
+ export function getAdapterDefaults(adapterType, registry) {
68
+ if (registry && registry.length > 0) {
69
+ const entry = registry.find((e) => e.adapterType === adapterType);
70
+ if (!entry) {
71
+ throw new Error(`Adapter "${adapterType}" is not in the configured adapter registry`);
72
+ }
73
+ return fromRegistryEntry(entry);
74
+ }
75
+ const defaults = REGISTRY[adapterType];
76
+ if (!defaults) {
77
+ throw new Error(`Unknown adapter type: ${adapterType}`);
78
+ }
79
+ return defaults;
80
+ }
81
+ /**
82
+ * Resolve the adapter type for a single run: prefer the run's adapter (the agent's,
83
+ * from the lease params) so one environment can serve mixed harnesses; fall back to
84
+ * the environment's configured default adapter when the run does not specify one.
85
+ */
86
+ export function resolveRunAdapterType(runAdapterType, configAdapterType) {
87
+ const trimmed = typeof runAdapterType === "string" ? runAdapterType.trim() : "";
88
+ return trimmed.length > 0 ? trimmed : configAdapterType;
89
+ }
90
+ /**
91
+ * Build the per-run env for the Job: the non-secret `defaultEnv` is the base
92
+ * and the process-env values (the secret API keys named by `envKeys`) override
93
+ * it. Pure for testability.
94
+ */
95
+ export function buildAdapterEnv(defaults, processEnv = process.env) {
96
+ const out = { ...(defaults.defaultEnv ?? {}) };
97
+ for (const k of defaults.envKeys) {
98
+ const v = processEnv[k];
99
+ if (v)
100
+ out[k] = v;
101
+ }
102
+ return out;
103
+ }
104
+ //# sourceMappingURL=adapter-defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-defaults.js","sourceRoot":"","sources":["../src/adapter-defaults.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * One declarative agent-harness ("adapter") entry. Governs picker availability
4
+ * and, for sandboxed (Kubernetes) runs, the runtime wiring.
5
+ *
6
+ * NOTE: this shape is intentionally duplicated across the package boundary. It
7
+ * MUST stay structurally in sync with:
8
+ * - server `@paperclipai/shared` `adapterRegistryEntrySchema` (the parser side)
9
+ * - operator `AdapterRegistryEntry` Go struct (PAPERCLIP_ADAPTERS emitter)
10
+ * The duplication is deliberate: this plugin is standalone-installable and must
11
+ * not pull in heavy workspace packages at runtime.
12
+ */
13
+ export declare const adapterRegistryEntrySchema: z.ZodObject<{
14
+ adapterType: z.ZodString;
15
+ enabled: z.ZodDefault<z.ZodBoolean>;
16
+ runtimeImage: z.ZodOptional<z.ZodString>;
17
+ envKeys: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
18
+ allowFqdns: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
19
+ probeCommand: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
20
+ defaultEnv: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
21
+ }, "strict", z.ZodTypeAny, {
22
+ adapterType: string;
23
+ enabled: boolean;
24
+ runtimeImage?: string | undefined;
25
+ envKeys?: string[] | undefined;
26
+ allowFqdns?: string[] | undefined;
27
+ probeCommand?: string[] | undefined;
28
+ defaultEnv?: Record<string, string> | undefined;
29
+ }, {
30
+ adapterType: string;
31
+ enabled?: boolean | undefined;
32
+ runtimeImage?: string | undefined;
33
+ envKeys?: string[] | undefined;
34
+ allowFqdns?: string[] | undefined;
35
+ probeCommand?: string[] | undefined;
36
+ defaultEnv?: Record<string, string> | undefined;
37
+ }>;
38
+ export declare const adapterRegistrySchema: z.ZodArray<z.ZodObject<{
39
+ adapterType: z.ZodString;
40
+ enabled: z.ZodDefault<z.ZodBoolean>;
41
+ runtimeImage: z.ZodOptional<z.ZodString>;
42
+ envKeys: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
43
+ allowFqdns: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
44
+ probeCommand: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
45
+ defaultEnv: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
46
+ }, "strict", z.ZodTypeAny, {
47
+ adapterType: string;
48
+ enabled: boolean;
49
+ runtimeImage?: string | undefined;
50
+ envKeys?: string[] | undefined;
51
+ allowFqdns?: string[] | undefined;
52
+ probeCommand?: string[] | undefined;
53
+ defaultEnv?: Record<string, string> | undefined;
54
+ }, {
55
+ adapterType: string;
56
+ enabled?: boolean | undefined;
57
+ runtimeImage?: string | undefined;
58
+ envKeys?: string[] | undefined;
59
+ allowFqdns?: string[] | undefined;
60
+ probeCommand?: string[] | undefined;
61
+ defaultEnv?: Record<string, string> | undefined;
62
+ }>, "many">;
63
+ export type AdapterRegistryEntry = z.infer<typeof adapterRegistryEntrySchema>;
64
+ //# sourceMappingURL=adapter-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-registry.d.ts","sourceRoot":"","sources":["../src/adapter-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;EAU5B,CAAC;AAEZ,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;WAAsC,CAAC;AAEzE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * One declarative agent-harness ("adapter") entry. Governs picker availability
4
+ * and, for sandboxed (Kubernetes) runs, the runtime wiring.
5
+ *
6
+ * NOTE: this shape is intentionally duplicated across the package boundary. It
7
+ * MUST stay structurally in sync with:
8
+ * - server `@paperclipai/shared` `adapterRegistryEntrySchema` (the parser side)
9
+ * - operator `AdapterRegistryEntry` Go struct (PAPERCLIP_ADAPTERS emitter)
10
+ * The duplication is deliberate: this plugin is standalone-installable and must
11
+ * not pull in heavy workspace packages at runtime.
12
+ */
13
+ export const adapterRegistryEntrySchema = z
14
+ .object({
15
+ adapterType: z.string().min(1),
16
+ enabled: z.boolean().default(true),
17
+ runtimeImage: z.string().optional(),
18
+ envKeys: z.array(z.string()).optional(),
19
+ allowFqdns: z.array(z.string()).optional(),
20
+ probeCommand: z.array(z.string()).optional(),
21
+ defaultEnv: z.record(z.string()).optional(),
22
+ })
23
+ .strict();
24
+ export const adapterRegistrySchema = z.array(adapterRegistryEntrySchema);
25
+ //# sourceMappingURL=adapter-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-registry.js","sourceRoot":"","sources":["../src/adapter-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC;KACxC,MAAM,CAAC;IACN,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAClC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACvC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC1C,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC5C,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CAC5C,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface BuildCiliumNetworkPolicyInput {
2
+ namespace: string;
3
+ paperclipServerNamespace: string;
4
+ egressAllowFqdns: string[];
5
+ egressAllowCidrs: string[];
6
+ }
7
+ export declare function buildCiliumNetworkPolicyManifest(input: BuildCiliumNetworkPolicyInput): Record<string, unknown>;
8
+ //# sourceMappingURL=cilium-network-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cilium-network-policy.d.ts","sourceRoot":"","sources":["../src/cilium-network-policy.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,6BAA6B;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,wBAAwB,EAAE,MAAM,CAAC;IACjC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAMD,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,6BAA6B,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwD9G"}
@@ -0,0 +1,57 @@
1
+ // Design note: no ingress rules are defined here. Paperclip-server does NOT
2
+ // push to agent pods — agents make outbound (egress) callbacks to
3
+ // paperclip-server on port 3100. If server→agent push is ever needed, add a
4
+ // targeted ingress rule scoped to the paperclip-server endpoint selector.
5
+ export function buildCiliumNetworkPolicyManifest(input) {
6
+ const egress = [];
7
+ egress.push({
8
+ toEndpoints: [
9
+ { matchLabels: { "k8s:io.kubernetes.pod.namespace": "kube-system", "k8s-app": "kube-dns" } },
10
+ ],
11
+ toPorts: [
12
+ {
13
+ ports: [
14
+ { port: "53", protocol: "UDP" },
15
+ { port: "53", protocol: "TCP" },
16
+ ],
17
+ rules: { dns: [{ matchPattern: "*" }] },
18
+ },
19
+ ],
20
+ });
21
+ if (input.egressAllowFqdns.length > 0) {
22
+ egress.push({
23
+ toFQDNs: input.egressAllowFqdns.map((fqdn) => ({ matchName: fqdn })),
24
+ toPorts: [{ ports: [{ port: "443", protocol: "TCP" }] }],
25
+ });
26
+ }
27
+ egress.push({
28
+ toEndpoints: [
29
+ {
30
+ matchLabels: {
31
+ "k8s:io.kubernetes.pod.namespace": input.paperclipServerNamespace,
32
+ app: "paperclip-server",
33
+ },
34
+ },
35
+ ],
36
+ toPorts: [{ ports: [{ port: "3100", protocol: "TCP" }] }],
37
+ });
38
+ if (input.egressAllowCidrs.length > 0) {
39
+ egress.push({
40
+ toCIDRSet: input.egressAllowCidrs.map((cidr) => ({ cidr })),
41
+ });
42
+ }
43
+ return {
44
+ apiVersion: "cilium.io/v2",
45
+ kind: "CiliumNetworkPolicy",
46
+ metadata: {
47
+ name: "paperclip-egress-fqdn",
48
+ namespace: input.namespace,
49
+ labels: { "paperclip.io/managed-by": "paperclip-k8s-plugin" },
50
+ },
51
+ spec: {
52
+ endpointSelector: { matchLabels: { "paperclip.io/role": "agent" } },
53
+ egress,
54
+ },
55
+ };
56
+ }
57
+ //# sourceMappingURL=cilium-network-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cilium-network-policy.js","sourceRoot":"","sources":["../src/cilium-network-policy.ts"],"names":[],"mappings":"AAOA,4EAA4E;AAC5E,kEAAkE;AAClE,4EAA4E;AAC5E,0EAA0E;AAC1E,MAAM,UAAU,gCAAgC,CAAC,KAAoC;IACnF,MAAM,MAAM,GAA8B,EAAE,CAAC;IAE7C,MAAM,CAAC,IAAI,CAAC;QACV,WAAW,EAAE;YACX,EAAE,WAAW,EAAE,EAAE,iCAAiC,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE;SAC7F;QACD,OAAO,EAAE;YACP;gBACE,KAAK,EAAE;oBACL,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE;oBAC/B,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE;iBAChC;gBACD,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,EAAE;aACxC;SACF;KACF,CAAC,CAAC;IAEH,IAAI,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;SACzD,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,IAAI,CAAC;QACV,WAAW,EAAE;YACX;gBACE,WAAW,EAAE;oBACX,iCAAiC,EAAE,KAAK,CAAC,wBAAwB;oBACjE,GAAG,EAAE,kBAAkB;iBACxB;aACF;SACF;QACD,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;KAC1D,CAAC,CAAC;IAEH,IAAI,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC;YACV,SAAS,EAAE,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;SAC5D,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,UAAU,EAAE,cAAc;QAC1B,IAAI,EAAE,qBAAqB;QAC3B,QAAQ,EAAE;YACR,IAAI,EAAE,uBAAuB;YAC7B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,EAAE,yBAAyB,EAAE,sBAAsB,EAAE;SAC9D;QACD,IAAI,EAAE;YACJ,gBAAgB,EAAE,EAAE,WAAW,EAAE,EAAE,mBAAmB,EAAE,OAAO,EAAE,EAAE;YACnE,MAAM;SACP;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Glob matching for image references.
3
+ * - `*` matches any sequence of characters EXCEPT `/` (so a wildcard doesn't span path segments)
4
+ * - `?` matches exactly one character (excluding `/`)
5
+ */
6
+ export declare function globMatch(pattern: string, value: string): boolean;
7
+ export interface ResolveImageInput {
8
+ imageOverride?: string | null;
9
+ }
10
+ export interface ResolveImageDefaults {
11
+ runtimeImage: string;
12
+ }
13
+ export interface ResolveImageConfig {
14
+ imageAllowList: string[];
15
+ imageRegistry?: string;
16
+ }
17
+ export declare function resolveImage(target: ResolveImageInput, defaults: ResolveImageDefaults, config: ResolveImageConfig): string;
18
+ //# sourceMappingURL=image-allowlist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-allowlist.d.ts","sourceRoot":"","sources":["../src/image-allowlist.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAUjE;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,oBAAoB,EAC9B,MAAM,EAAE,kBAAkB,GACzB,MAAM,CAWR"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Glob matching for image references.
3
+ * - `*` matches any sequence of characters EXCEPT `/` (so a wildcard doesn't span path segments)
4
+ * - `?` matches exactly one character (excluding `/`)
5
+ */
6
+ export function globMatch(pattern, value) {
7
+ const re = new RegExp("^" +
8
+ pattern
9
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&")
10
+ .replace(/\*/g, "[^/]*")
11
+ .replace(/\?/g, "[^/]") +
12
+ "$");
13
+ return re.test(value);
14
+ }
15
+ export function resolveImage(target, defaults, config) {
16
+ if (target.imageOverride) {
17
+ if (!config.imageAllowList.some((p) => globMatch(p, target.imageOverride))) {
18
+ throw new Error(`Image override "${target.imageOverride}" is not in allowlist`);
19
+ }
20
+ return target.imageOverride;
21
+ }
22
+ if (config.imageRegistry) {
23
+ return rewriteRegistry(defaults.runtimeImage, config.imageRegistry);
24
+ }
25
+ return defaults.runtimeImage;
26
+ }
27
+ function rewriteRegistry(image, registry) {
28
+ // image is like "ghcr.io/paperclipai/agent-runtime-claude:v1"
29
+ // we want to replace the first two path segments (host + org) with `registry`
30
+ const cleanRegistry = registry.replace(/\/+$/, "");
31
+ const colonIdx = image.lastIndexOf(":");
32
+ const tag = colonIdx >= 0 ? image.slice(colonIdx) : "";
33
+ const path = colonIdx >= 0 ? image.slice(0, colonIdx) : image;
34
+ const segments = path.split("/");
35
+ // Strip the host+org (first two segments), keep the image name
36
+ const imageName = segments.slice(2).join("/") || segments[segments.length - 1];
37
+ return `${cleanRegistry}/${imageName}${tag}`;
38
+ }
39
+ //# sourceMappingURL=image-allowlist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-allowlist.js","sourceRoot":"","sources":["../src/image-allowlist.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,KAAa;IACtD,MAAM,EAAE,GAAG,IAAI,MAAM,CACnB,GAAG;QACD,OAAO;aACJ,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC;aACpC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;aACvB,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;QACzB,GAAG,CACN,CAAC;IACF,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACxB,CAAC;AAeD,MAAM,UAAU,YAAY,CAC1B,MAAyB,EACzB,QAA8B,EAC9B,MAA0B;IAE1B,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,aAAc,CAAC,CAAC,EAAE,CAAC;YAC5E,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,aAAa,uBAAuB,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,MAAM,CAAC,aAAa,CAAC;IAC9B,CAAC;IACD,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACzB,OAAO,eAAe,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,QAAQ,CAAC,YAAY,CAAC;AAC/B,CAAC;AAED,SAAS,eAAe,CAAC,KAAa,EAAE,QAAgB;IACtD,8DAA8D;IAC9D,8EAA8E;IAC9E,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,MAAM,IAAI,GAAG,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,+DAA+D;IAC/D,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/E,OAAO,GAAG,aAAa,IAAI,SAAS,GAAG,GAAG,EAAE,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { default as manifest } from "./manifest.js";
2
+ export { default as plugin } from "./plugin.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { default as manifest } from "./manifest.js";
2
+ export { default as plugin } from "./plugin.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { KubeClients } from "./kube-client.js";
2
+ import type { SandboxOrchestrator, SandboxStatus } from "./sandbox-orchestrator.js";
3
+ export declare class JobTimeoutError extends Error {
4
+ constructor(namespace: string, name: string, timeoutMs: number);
5
+ }
6
+ export declare function createJob(clients: KubeClients, namespace: string, manifest: Record<string, unknown>): Promise<{
7
+ uid: string;
8
+ }>;
9
+ export type JobStatus = SandboxStatus;
10
+ export declare function getJobStatus(clients: KubeClients, namespace: string, name: string): Promise<JobStatus>;
11
+ export declare function findPodForJob(clients: KubeClients, namespace: string, jobName: string): Promise<string | null>;
12
+ export declare function streamPodLogs(clients: KubeClients, namespace: string, podName: string, onChunk: (stream: "stdout" | "stderr", text: string) => Promise<void>): Promise<void>;
13
+ export declare function deleteJob(clients: KubeClients, namespace: string, name: string): Promise<void>;
14
+ export declare function waitForJobCompletion(clients: KubeClients, namespace: string, name: string, opts?: {
15
+ timeoutMs: number;
16
+ pollMs?: number;
17
+ }): Promise<JobStatus>;
18
+ /**
19
+ * Job-backed conformance to SandboxOrchestrator. Plugin.ts imports THIS value
20
+ * (the swap point) — to use a different backend, swap this import for another
21
+ * module exposing a SandboxOrchestrator-shaped default export.
22
+ */
23
+ export declare const jobOrchestrator: SandboxOrchestrator;
24
+ //# sourceMappingURL=job-orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-orchestrator.d.ts","sourceRoot":"","sources":["../src/job-orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAEpF,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAI/D;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAK1B;AAED,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC;AAEtC,wBAAsB,YAAY,CAChC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,SAAS,CAAC,CAoBpB;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQxB;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GACpE,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAyC,GAClF,OAAO,CAAC,SAAS,CAAC,CASpB;AAMD;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,mBAO7B,CAAC"}