log10x-mcp 1.12.5 → 1.12.7

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.
@@ -0,0 +1,177 @@
1
+ /**
2
+ * kubectl-writer — push a ConfigMap to the customer's k8s cluster via
3
+ * `kubectl apply`.
4
+ *
5
+ * Companion to the existing gitops/gh writer in configure-engine.ts. The
6
+ * gh path opens a PR against the customer's gitops repo (slow loop:
7
+ * review → merge → poll → engine hot-reload). This path is the
8
+ * direct-apply alternative for environments where:
9
+ *
10
+ * - the engine pulls action-intent from a ConfigMap (new pull source
11
+ * introduced alongside this writer), and
12
+ * - the operator wants in-session iteration speed (~seconds vs
13
+ * minutes), and
14
+ * - the MCP has direct kubectl access (the user's local kubeconfig
15
+ * pointed at the target cluster).
16
+ *
17
+ * Architecture: out-of-cluster. The MCP runs on the user's Mac and
18
+ * invokes `kubectl apply -f - --dry-run=server`. The ConfigMap YAML is
19
+ * built inline from caller-supplied content and piped via stdin.
20
+ *
21
+ * Safety model (layered):
22
+ * 1. Caller flag (auto_apply=false / read_only=true on the tool) short-
23
+ * circuits to dry-run; the rendered YAML is returned in-envelope.
24
+ * 2. Even when auto-applying, we ALWAYS do a `--dry-run=server` pass
25
+ * first to catch RBAC/quota/admission errors without writing.
26
+ * 3. All user-controlled strings reach `kubectl` via process args
27
+ * (spawnSync's argv array) — NEVER via shell interpolation. The YAML
28
+ * body itself is piped through stdin, not constructed in argv.
29
+ * 4. ConfigMap-size guard: k8s rejects objects > 1 MiB at the apiserver.
30
+ * We pre-flight on the SUM of value sizes and return a structured
31
+ * `request_entity_too_large` error before kubectl is invoked.
32
+ *
33
+ * Failure-classification: stderr from kubectl is regex-matched against
34
+ * the common error families so the agent can branch on `error_type`
35
+ * (forbidden, not_found, request_entity_too_large, conflict, timeout,
36
+ * unknown). All errors flow back as `{ ok: false, error: {...} }` —
37
+ * the function never throws.
38
+ *
39
+ * Why server-side dry-run by default: client-side dry-run only checks
40
+ * schema; server-side runs the admission chain (RBAC, ResourceQuota,
41
+ * webhooks). The latter is what the operator actually needs to know
42
+ * about. If the cluster doesn't support server-side dry-run we fall
43
+ * back to client-side and warn.
44
+ */
45
+ import type { PrimitiveError } from '../primitive-errors.js';
46
+ /**
47
+ * The k8s ConfigMap size limit is 1 MiB (apiserver enforcement). Allow
48
+ * a small headroom so the metadata block doesn't push us over.
49
+ */
50
+ export declare const CONFIGMAP_MAX_BYTES: number;
51
+ export interface KubectlWriterArgs {
52
+ /** Target k8s namespace. Must be DNS-1123-label valid. */
53
+ namespace: string;
54
+ /** Target ConfigMap name. Must be DNS-1123-subdomain valid. */
55
+ configmap: string;
56
+ /**
57
+ * ConfigMap `data` map. Each value is a string; binary values are not
58
+ * supported by this writer (the engine pulls action-intent.json which is
59
+ * UTF-8 text).
60
+ */
61
+ content: {
62
+ [key: string]: string;
63
+ };
64
+ /**
65
+ * When true, skip the real apply and only run `--dry-run=server`. The
66
+ * returned `dry_run_diff` carries kubectl's stdout describing what
67
+ * WOULD change. When false, we still run server-side dry-run first as
68
+ * a pre-flight, then do the real apply if the dry-run succeeded.
69
+ */
70
+ dryRun: boolean;
71
+ /**
72
+ * Optional labels to merge into the ConfigMap metadata. Useful for
73
+ * GitOps reconciliation markers (`app.kubernetes.io/managed-by=log10x`)
74
+ * and for the engine's pull-source label selector.
75
+ */
76
+ labels?: {
77
+ [key: string]: string;
78
+ };
79
+ /**
80
+ * Optional annotations. Stamped with `log10x.com/written-at` so the
81
+ * engine can log the freshness of the ConfigMap on each pull.
82
+ */
83
+ annotations?: {
84
+ [key: string]: string;
85
+ };
86
+ /** Override the default timeout (ms). Tests pass a short value. */
87
+ timeoutMs?: number;
88
+ /**
89
+ * Override the kubectl binary path. Default `kubectl` (resolved via
90
+ * PATH). Tests pass `/bin/false` etc.
91
+ */
92
+ kubectlPath?: string;
93
+ /**
94
+ * Injected spawn implementation. Defaults to node's spawnSync. Tests
95
+ * pass a mock that returns canned stdout/stderr/exit codes without
96
+ * starting a real process.
97
+ */
98
+ spawn?: SpawnSyncFn;
99
+ }
100
+ export interface KubectlWriterResult {
101
+ ok: boolean;
102
+ /** High-level state, branchable by the caller. */
103
+ status: 'applied' | 'dry_run_ok' | 'failed_validation' | 'failed_apply' | 'forbidden' | 'not_found' | 'request_entity_too_large' | 'conflict' | 'timeout' | 'kubectl_unavailable';
104
+ /** Server-side dry-run diff (kubectl stdout) — present on success. */
105
+ dry_run_diff?: string;
106
+ /** Rendered ConfigMap YAML (always present so the caller can persist). */
107
+ rendered_yaml: string;
108
+ /** Structured error envelope, present iff ok=false. */
109
+ error?: PrimitiveError;
110
+ /**
111
+ * Suggested kubectl one-liner the user can run to confirm the change
112
+ * landed (`kubectl get configmap -n <ns> <name> -o yaml`).
113
+ */
114
+ verification_hint: string;
115
+ }
116
+ /** Trimmed surface of node's `spawnSync` return value. */
117
+ export interface SpawnSyncResult {
118
+ status: number | null;
119
+ stdout: string | Buffer;
120
+ stderr: string | Buffer;
121
+ error?: Error & {
122
+ code?: string;
123
+ };
124
+ signal?: NodeJS.Signals | null;
125
+ }
126
+ /**
127
+ * Spawn function signature compatible with `child_process.spawnSync`.
128
+ * Tests pass a mock that returns canned results.
129
+ */
130
+ export type SpawnSyncFn = (command: string, args: string[], options: {
131
+ input: string;
132
+ timeout: number;
133
+ encoding?: BufferEncoding;
134
+ }) => SpawnSyncResult;
135
+ /**
136
+ * Apply a ConfigMap to the customer's cluster (or dry-run only) via
137
+ * kubectl. Never throws — all failures flow back as `{ ok: false, ... }`.
138
+ *
139
+ * The function does:
140
+ * 1. Validate the namespace + configmap names (DNS-1123).
141
+ * 2. Pre-flight the size against the apiserver's 1 MiB cap.
142
+ * 3. Render the ConfigMap YAML deterministically (sorted keys).
143
+ * 4. Run `kubectl apply -f - --dry-run=server`.
144
+ * 5. If dryRun=false and dry-run succeeded, run the real apply.
145
+ * 6. Classify kubectl exit code + stderr into a structured error.
146
+ */
147
+ export declare function applyViaKubectl(args: KubectlWriterArgs): KubectlWriterResult;
148
+ interface RenderInput {
149
+ namespace: string;
150
+ configmap: string;
151
+ content: {
152
+ [key: string]: string;
153
+ };
154
+ labels?: {
155
+ [key: string]: string;
156
+ };
157
+ annotations?: {
158
+ [key: string]: string;
159
+ };
160
+ }
161
+ /**
162
+ * Render the ConfigMap YAML. Public for testing — the format is stable
163
+ * across kubectl versions.
164
+ */
165
+ export declare function renderConfigMapYaml(input: RenderInput): string;
166
+ /**
167
+ * Map kubectl stderr text to a high-level status code. Exposed so the
168
+ * top-level result can carry both the structured error and a coarse
169
+ * branch the caller can switch on without parsing strings.
170
+ */
171
+ export declare function classifyKubectlStderr(stderr: string): KubectlWriterResult['status'];
172
+ /**
173
+ * Build the kubectl one-liner the caller surfaces in `verification_hint`
174
+ * so the user can confirm the apply landed.
175
+ */
176
+ export declare function buildVerificationHint(namespace: string, configmap: string): string;
177
+ export {};
@@ -0,0 +1,423 @@
1
+ /**
2
+ * kubectl-writer — push a ConfigMap to the customer's k8s cluster via
3
+ * `kubectl apply`.
4
+ *
5
+ * Companion to the existing gitops/gh writer in configure-engine.ts. The
6
+ * gh path opens a PR against the customer's gitops repo (slow loop:
7
+ * review → merge → poll → engine hot-reload). This path is the
8
+ * direct-apply alternative for environments where:
9
+ *
10
+ * - the engine pulls action-intent from a ConfigMap (new pull source
11
+ * introduced alongside this writer), and
12
+ * - the operator wants in-session iteration speed (~seconds vs
13
+ * minutes), and
14
+ * - the MCP has direct kubectl access (the user's local kubeconfig
15
+ * pointed at the target cluster).
16
+ *
17
+ * Architecture: out-of-cluster. The MCP runs on the user's Mac and
18
+ * invokes `kubectl apply -f - --dry-run=server`. The ConfigMap YAML is
19
+ * built inline from caller-supplied content and piped via stdin.
20
+ *
21
+ * Safety model (layered):
22
+ * 1. Caller flag (auto_apply=false / read_only=true on the tool) short-
23
+ * circuits to dry-run; the rendered YAML is returned in-envelope.
24
+ * 2. Even when auto-applying, we ALWAYS do a `--dry-run=server` pass
25
+ * first to catch RBAC/quota/admission errors without writing.
26
+ * 3. All user-controlled strings reach `kubectl` via process args
27
+ * (spawnSync's argv array) — NEVER via shell interpolation. The YAML
28
+ * body itself is piped through stdin, not constructed in argv.
29
+ * 4. ConfigMap-size guard: k8s rejects objects > 1 MiB at the apiserver.
30
+ * We pre-flight on the SUM of value sizes and return a structured
31
+ * `request_entity_too_large` error before kubectl is invoked.
32
+ *
33
+ * Failure-classification: stderr from kubectl is regex-matched against
34
+ * the common error families so the agent can branch on `error_type`
35
+ * (forbidden, not_found, request_entity_too_large, conflict, timeout,
36
+ * unknown). All errors flow back as `{ ok: false, error: {...} }` —
37
+ * the function never throws.
38
+ *
39
+ * Why server-side dry-run by default: client-side dry-run only checks
40
+ * schema; server-side runs the admission chain (RBAC, ResourceQuota,
41
+ * webhooks). The latter is what the operator actually needs to know
42
+ * about. If the cluster doesn't support server-side dry-run we fall
43
+ * back to client-side and warn.
44
+ */
45
+ import { spawnSync } from 'node:child_process';
46
+ // ─── public surface ──────────────────────────────────────────────────
47
+ /**
48
+ * The k8s ConfigMap size limit is 1 MiB (apiserver enforcement). Allow
49
+ * a small headroom so the metadata block doesn't push us over.
50
+ */
51
+ export const CONFIGMAP_MAX_BYTES = 1024 * 1024;
52
+ const CONFIGMAP_HEADROOM_BYTES = 4 * 1024;
53
+ const CONFIGMAP_SOFT_LIMIT = CONFIGMAP_MAX_BYTES - CONFIGMAP_HEADROOM_BYTES;
54
+ /** Default per-call timeout for kubectl invocations (ms). */
55
+ const KUBECTL_TIMEOUT_MS = 30_000;
56
+ // ─── entry ───────────────────────────────────────────────────────────
57
+ /**
58
+ * Apply a ConfigMap to the customer's cluster (or dry-run only) via
59
+ * kubectl. Never throws — all failures flow back as `{ ok: false, ... }`.
60
+ *
61
+ * The function does:
62
+ * 1. Validate the namespace + configmap names (DNS-1123).
63
+ * 2. Pre-flight the size against the apiserver's 1 MiB cap.
64
+ * 3. Render the ConfigMap YAML deterministically (sorted keys).
65
+ * 4. Run `kubectl apply -f - --dry-run=server`.
66
+ * 5. If dryRun=false and dry-run succeeded, run the real apply.
67
+ * 6. Classify kubectl exit code + stderr into a structured error.
68
+ */
69
+ export function applyViaKubectl(args) {
70
+ const spawn = args.spawn ?? spawnSync;
71
+ const kubectl = args.kubectlPath ?? 'kubectl';
72
+ const timeoutMs = args.timeoutMs ?? KUBECTL_TIMEOUT_MS;
73
+ const verification_hint = buildVerificationHint(args.namespace, args.configmap);
74
+ // ── 1. Validate identifiers ───────────────────────────────────────
75
+ const nsErr = validateDns1123Label(args.namespace, 'namespace');
76
+ if (nsErr) {
77
+ const yaml = ''; // not rendered when args are invalid
78
+ return {
79
+ ok: false,
80
+ status: 'failed_validation',
81
+ rendered_yaml: yaml,
82
+ error: nsErr,
83
+ verification_hint,
84
+ };
85
+ }
86
+ const cmErr = validateDns1123Subdomain(args.configmap, 'configmap');
87
+ if (cmErr) {
88
+ return {
89
+ ok: false,
90
+ status: 'failed_validation',
91
+ rendered_yaml: '',
92
+ error: cmErr,
93
+ verification_hint,
94
+ };
95
+ }
96
+ // ── 2. Pre-flight size ────────────────────────────────────────────
97
+ const sizeError = preflightSize(args.content);
98
+ if (sizeError) {
99
+ return {
100
+ ok: false,
101
+ status: 'request_entity_too_large',
102
+ rendered_yaml: '',
103
+ error: sizeError,
104
+ verification_hint,
105
+ };
106
+ }
107
+ // ── 3. Render YAML deterministically ──────────────────────────────
108
+ const yaml = renderConfigMapYaml({
109
+ namespace: args.namespace,
110
+ configmap: args.configmap,
111
+ content: args.content,
112
+ labels: args.labels,
113
+ annotations: args.annotations,
114
+ });
115
+ // ── 4. Server-side dry-run pre-flight ─────────────────────────────
116
+ const dryRunResult = runKubectl(spawn, kubectl, ['apply', '-n', args.namespace, '-f', '-', '--dry-run=server', '-o', 'yaml'], yaml, timeoutMs);
117
+ if (dryRunResult.kind === 'unavailable') {
118
+ return {
119
+ ok: false,
120
+ status: 'kubectl_unavailable',
121
+ rendered_yaml: yaml,
122
+ error: dryRunResult.error,
123
+ verification_hint,
124
+ };
125
+ }
126
+ if (dryRunResult.kind === 'timeout') {
127
+ return {
128
+ ok: false,
129
+ status: 'timeout',
130
+ rendered_yaml: yaml,
131
+ error: dryRunResult.error,
132
+ verification_hint,
133
+ };
134
+ }
135
+ if (dryRunResult.kind === 'error') {
136
+ return {
137
+ ok: false,
138
+ status: classifyKubectlStderr(dryRunResult.stderr),
139
+ rendered_yaml: yaml,
140
+ error: dryRunResult.error,
141
+ verification_hint,
142
+ };
143
+ }
144
+ // dry-run succeeded — caller wanted dry-run only, return now.
145
+ if (args.dryRun) {
146
+ return {
147
+ ok: true,
148
+ status: 'dry_run_ok',
149
+ rendered_yaml: yaml,
150
+ dry_run_diff: dryRunResult.stdout,
151
+ verification_hint,
152
+ };
153
+ }
154
+ // ── 5. Real apply ─────────────────────────────────────────────────
155
+ const applyResult = runKubectl(spawn, kubectl, ['apply', '-n', args.namespace, '-f', '-'], yaml, timeoutMs);
156
+ if (applyResult.kind === 'unavailable') {
157
+ return {
158
+ ok: false,
159
+ status: 'kubectl_unavailable',
160
+ rendered_yaml: yaml,
161
+ error: applyResult.error,
162
+ verification_hint,
163
+ };
164
+ }
165
+ if (applyResult.kind === 'timeout') {
166
+ return {
167
+ ok: false,
168
+ status: 'timeout',
169
+ rendered_yaml: yaml,
170
+ error: applyResult.error,
171
+ verification_hint,
172
+ };
173
+ }
174
+ if (applyResult.kind === 'error') {
175
+ return {
176
+ ok: false,
177
+ status: classifyKubectlStderr(applyResult.stderr),
178
+ rendered_yaml: yaml,
179
+ error: applyResult.error,
180
+ verification_hint,
181
+ };
182
+ }
183
+ return {
184
+ ok: true,
185
+ status: 'applied',
186
+ rendered_yaml: yaml,
187
+ dry_run_diff: dryRunResult.stdout,
188
+ verification_hint,
189
+ };
190
+ }
191
+ /**
192
+ * Render the ConfigMap YAML. Public for testing — the format is stable
193
+ * across kubectl versions.
194
+ */
195
+ export function renderConfigMapYaml(input) {
196
+ const lines = [];
197
+ lines.push('apiVersion: v1');
198
+ lines.push('kind: ConfigMap');
199
+ lines.push('metadata:');
200
+ lines.push(` name: ${yamlScalar(input.configmap)}`);
201
+ lines.push(` namespace: ${yamlScalar(input.namespace)}`);
202
+ // Always stamp managed-by so an operator scanning the cluster can find
203
+ // log10x-managed ConfigMaps. Caller labels merge on top.
204
+ const labels = {
205
+ 'app.kubernetes.io/managed-by': 'log10x-mcp',
206
+ 'log10x.com/source': 'configure_engine',
207
+ ...(input.labels ?? {}),
208
+ };
209
+ lines.push(' labels:');
210
+ for (const k of Object.keys(labels).sort()) {
211
+ lines.push(` ${yamlScalarKey(k)}: ${yamlScalar(labels[k])}`);
212
+ }
213
+ // Always stamp written-at; merge caller annotations on top.
214
+ const annotations = {
215
+ 'log10x.com/written-at': new Date().toISOString(),
216
+ ...(input.annotations ?? {}),
217
+ };
218
+ lines.push(' annotations:');
219
+ for (const k of Object.keys(annotations).sort()) {
220
+ lines.push(` ${yamlScalarKey(k)}: ${yamlScalar(annotations[k])}`);
221
+ }
222
+ lines.push('data:');
223
+ // Sort keys so the rendered YAML is byte-identical for identical input.
224
+ const sortedKeys = Object.keys(input.content).sort();
225
+ for (const k of sortedKeys) {
226
+ const v = input.content[k];
227
+ lines.push(` ${yamlScalarKey(k)}: ${yamlBlockOrScalar(v, 4)}`);
228
+ }
229
+ return lines.join('\n') + '\n';
230
+ }
231
+ /**
232
+ * Single-quoted YAML scalar. We escape `'` by doubling it. This is the
233
+ * safe encoding for arbitrary ASCII; multi-line / large values use the
234
+ * block-literal encoding below.
235
+ */
236
+ function yamlScalar(s) {
237
+ // Quote always so we don't trip YAML 1.1's surprise booleans
238
+ // (yes/no/on/off) or numeric coercions.
239
+ return `'${s.replace(/'/g, "''")}'`;
240
+ }
241
+ /**
242
+ * YAML key in scalar form. We quote keys that contain non-identifier
243
+ * characters (dots, slashes — common in k8s annotation keys).
244
+ */
245
+ function yamlScalarKey(k) {
246
+ if (/^[A-Za-z_][A-Za-z0-9_-]*$/.test(k))
247
+ return k;
248
+ return `'${k.replace(/'/g, "''")}'`;
249
+ }
250
+ /**
251
+ * Emit a value as a single-line quoted scalar when it fits, otherwise
252
+ * as a block literal. The block literal preserves newlines exactly.
253
+ */
254
+ function yamlBlockOrScalar(s, indent) {
255
+ if (!s.includes('\n'))
256
+ return yamlScalar(s);
257
+ const pad = ' '.repeat(indent);
258
+ const body = s.split('\n').map((l) => `${pad}${l}`).join('\n');
259
+ // `|-` strips the trailing newline; `|` keeps one. action-intent.json
260
+ // ends with a single trailing newline, so `|` matches it exactly.
261
+ return `|\n${body}`;
262
+ }
263
+ // ─── validation ──────────────────────────────────────────────────────
264
+ const DNS_1123_LABEL_RE = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/;
265
+ const DNS_1123_SUBDOMAIN_RE = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$/;
266
+ function validateDns1123Label(value, what) {
267
+ if (!value) {
268
+ return primitiveError('schema_invalid', `kubectl_configmap delivery: ${what} is empty. Pass a valid DNS-1123 label.`);
269
+ }
270
+ if (value.length > 63) {
271
+ return primitiveError('schema_invalid', `kubectl_configmap delivery: ${what} "${value.slice(0, 30)}…" exceeds the 63-char DNS-1123 label limit.`);
272
+ }
273
+ if (!DNS_1123_LABEL_RE.test(value)) {
274
+ return primitiveError('schema_invalid', `kubectl_configmap delivery: ${what} "${value}" is not a valid DNS-1123 label (lowercase letters, digits, hyphens; must start and end with alphanumeric).`);
275
+ }
276
+ return undefined;
277
+ }
278
+ function validateDns1123Subdomain(value, what) {
279
+ if (!value) {
280
+ return primitiveError('schema_invalid', `kubectl_configmap delivery: ${what} is empty.`);
281
+ }
282
+ if (value.length > 253) {
283
+ return primitiveError('schema_invalid', `kubectl_configmap delivery: ${what} exceeds the 253-char DNS-1123 subdomain limit.`);
284
+ }
285
+ if (!DNS_1123_SUBDOMAIN_RE.test(value)) {
286
+ return primitiveError('schema_invalid', `kubectl_configmap delivery: ${what} "${value}" is not a valid DNS-1123 subdomain.`);
287
+ }
288
+ return undefined;
289
+ }
290
+ /**
291
+ * Pre-flight the ConfigMap size against the apiserver's 1 MiB cap. We
292
+ * sum the byte length of all values plus a generous fudge factor for
293
+ * key names + YAML overhead.
294
+ */
295
+ function preflightSize(content) {
296
+ let total = 0;
297
+ for (const [k, v] of Object.entries(content)) {
298
+ total += Buffer.byteLength(k, 'utf8');
299
+ total += Buffer.byteLength(v, 'utf8');
300
+ }
301
+ if (total > CONFIGMAP_SOFT_LIMIT) {
302
+ const totalKb = (total / 1024).toFixed(1);
303
+ return {
304
+ error_type: 'schema_invalid',
305
+ retryable: false,
306
+ suggested_backoff_ms: null,
307
+ hint: `ConfigMap payload is ${totalKb} KiB which exceeds the 1 MiB k8s apiserver cap ` +
308
+ `(soft limit ${(CONFIGMAP_SOFT_LIMIT / 1024).toFixed(0)} KiB after headroom). ` +
309
+ `Split the action-intent across multiple ConfigMaps, or compact rare patterns.`,
310
+ };
311
+ }
312
+ return undefined;
313
+ }
314
+ function runKubectl(spawn, kubectl, args, yaml, timeoutMs) {
315
+ let res;
316
+ try {
317
+ res = spawn(kubectl, args, {
318
+ input: yaml,
319
+ timeout: timeoutMs,
320
+ encoding: 'utf8',
321
+ });
322
+ }
323
+ catch (e) {
324
+ // spawnSync only throws on invalid args; normalize to unavailable.
325
+ return {
326
+ kind: 'unavailable',
327
+ error: primitiveError('config_missing', `Failed to invoke kubectl: ${e.message}. Confirm kubectl is installed and on PATH.`),
328
+ };
329
+ }
330
+ const stdout = bufToString(res.stdout);
331
+ const stderr = bufToString(res.stderr);
332
+ // ENOENT / ENOTDIR: kubectl missing.
333
+ if (res.error && (res.error.code === 'ENOENT' || res.error.code === 'ENOTDIR')) {
334
+ return {
335
+ kind: 'unavailable',
336
+ error: primitiveError('config_missing', `kubectl binary not found (${res.error.code}). Install kubectl and ensure it is on PATH for the MCP process.`),
337
+ };
338
+ }
339
+ // Timeout via signal SIGTERM and null status (node's spawnSync sets
340
+ // status=null when killed by signal/timeout).
341
+ if (res.signal === 'SIGTERM' && res.status === null) {
342
+ return {
343
+ kind: 'timeout',
344
+ error: primitiveError('backend_timeout', `kubectl timed out after ${timeoutMs}ms. The cluster apiserver may be unreachable; check kubeconfig context and network.`, 2000, true),
345
+ };
346
+ }
347
+ if (res.status === 0) {
348
+ return { kind: 'ok', stdout, stderr };
349
+ }
350
+ const tail = stderr.trim().split('\n').slice(-5).join('\n').slice(0, 600);
351
+ return {
352
+ kind: 'error',
353
+ stdout,
354
+ stderr,
355
+ error: classifyKubectlError(stderr, res.status, tail),
356
+ };
357
+ }
358
+ function bufToString(b) {
359
+ if (b === undefined || b === null)
360
+ return '';
361
+ return typeof b === 'string' ? b : b.toString('utf8');
362
+ }
363
+ /**
364
+ * Map kubectl stderr text to a high-level status code. Exposed so the
365
+ * top-level result can carry both the structured error and a coarse
366
+ * branch the caller can switch on without parsing strings.
367
+ */
368
+ export function classifyKubectlStderr(stderr) {
369
+ const s = stderr.toLowerCase();
370
+ if (/forbidden|access denied|cannot.*resource|user.*cannot/i.test(s))
371
+ return 'forbidden';
372
+ if (/notfound|not found|no such|the server (?:could not find|doesn'?t have)/i.test(s)) {
373
+ return 'not_found';
374
+ }
375
+ if (/requestentitytoolarge|request entity too large|too large/i.test(s)) {
376
+ return 'request_entity_too_large';
377
+ }
378
+ if (/conflict|already exists/i.test(s))
379
+ return 'conflict';
380
+ if (/timeout|timed out|connection refused|unable to connect/i.test(s))
381
+ return 'timeout';
382
+ return 'failed_apply';
383
+ }
384
+ function classifyKubectlError(stderr, status, tail) {
385
+ const cls = classifyKubectlStderr(stderr);
386
+ switch (cls) {
387
+ case 'forbidden':
388
+ return primitiveError('config_missing', `kubectl Forbidden — the kubeconfig user lacks RBAC to write ConfigMaps in this namespace. ` +
389
+ `Bind a Role/RoleBinding granting configmaps create+patch, or switch contexts. kubectl said: ${tail}`);
390
+ case 'not_found':
391
+ return primitiveError('config_missing', `kubectl NotFound — the target namespace does not exist. Create it first ` +
392
+ `(kubectl create namespace …) or pass an existing one. kubectl said: ${tail}`);
393
+ case 'request_entity_too_large':
394
+ return primitiveError('schema_invalid', `kubectl RequestEntityTooLarge — the ConfigMap exceeds the 1 MiB apiserver cap. ` +
395
+ `Split the payload or compact rare patterns. kubectl said: ${tail}`);
396
+ case 'conflict':
397
+ return primitiveError('backend_error', `kubectl Conflict — the resource changed between read and write. Retry the apply. kubectl said: ${tail}`, 1000, true);
398
+ case 'timeout':
399
+ return primitiveError('backend_timeout', `kubectl timed out reaching the cluster. Check kubeconfig context and network. kubectl said: ${tail}`, 2000, true);
400
+ default:
401
+ return primitiveError('backend_error', `kubectl exited ${status ?? 'null'}: ${tail || 'no stderr output'}`);
402
+ }
403
+ }
404
+ // ─── helpers ─────────────────────────────────────────────────────────
405
+ function primitiveError(error_type, hint, backoff_ms = null, retryable = false) {
406
+ return {
407
+ error_type,
408
+ retryable,
409
+ suggested_backoff_ms: backoff_ms,
410
+ hint,
411
+ };
412
+ }
413
+ /**
414
+ * Build the kubectl one-liner the caller surfaces in `verification_hint`
415
+ * so the user can confirm the apply landed.
416
+ */
417
+ export function buildVerificationHint(namespace, configmap) {
418
+ // Two-line hint: confirm the ConfigMap, then tail the receiver pods so
419
+ // the user can see the engine pick up the new intent on its next pull.
420
+ return (`kubectl get configmap -n ${namespace} ${configmap} -o yaml | head -40\n` +
421
+ `kubectl logs -n ${namespace} -l app=tenx-fluentd --tail=200 | grep -i 'action-intent\\|configmap'`);
422
+ }
423
+ //# sourceMappingURL=kubectl-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kubectl-writer.js","sourceRoot":"","sources":["../../../src/lib/configure-engine/kubectl-writer.ts"],"names":[],"mappings":"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"}