@ankhorage/infra-minikube 0.0.0-stage → 0.4.128

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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +40 -2
  3. package/dist/constants/infra.d.ts +11 -0
  4. package/dist/constants/infra.d.ts.map +1 -0
  5. package/dist/constants/infra.js +4 -0
  6. package/dist/constants/infra.js.map +1 -0
  7. package/dist/features/cluster-runtime/adapters/createMinikubeCliControlPlane.d.ts +4 -0
  8. package/dist/features/cluster-runtime/adapters/createMinikubeCliControlPlane.d.ts.map +1 -0
  9. package/dist/features/cluster-runtime/adapters/createMinikubeCliControlPlane.js +156 -0
  10. package/dist/features/cluster-runtime/adapters/createMinikubeCliControlPlane.js.map +1 -0
  11. package/dist/features/cluster-runtime/adapters/createSubprocessMinikubeCommandRunner.d.ts +4 -0
  12. package/dist/features/cluster-runtime/adapters/createSubprocessMinikubeCommandRunner.d.ts.map +1 -0
  13. package/dist/features/cluster-runtime/adapters/createSubprocessMinikubeCommandRunner.js +26 -0
  14. package/dist/features/cluster-runtime/adapters/createSubprocessMinikubeCommandRunner.js.map +1 -0
  15. package/dist/features/cluster-runtime/adapters/inspectMinikubeAsync.d.ts +12 -0
  16. package/dist/features/cluster-runtime/adapters/inspectMinikubeAsync.d.ts.map +1 -0
  17. package/dist/features/cluster-runtime/adapters/inspectMinikubeAsync.js +141 -0
  18. package/dist/features/cluster-runtime/adapters/inspectMinikubeAsync.js.map +1 -0
  19. package/dist/features/cluster-runtime/adapters/minikubeCliProcess.d.ts +9 -0
  20. package/dist/features/cluster-runtime/adapters/minikubeCliProcess.d.ts.map +1 -0
  21. package/dist/features/cluster-runtime/adapters/minikubeCliProcess.js +56 -0
  22. package/dist/features/cluster-runtime/adapters/minikubeCliProcess.js.map +1 -0
  23. package/dist/features/cluster-runtime/adapters/readMinikubeEndpoints.d.ts +5 -0
  24. package/dist/features/cluster-runtime/adapters/readMinikubeEndpoints.d.ts.map +1 -0
  25. package/dist/features/cluster-runtime/adapters/readMinikubeEndpoints.js +52 -0
  26. package/dist/features/cluster-runtime/adapters/readMinikubeEndpoints.js.map +1 -0
  27. package/dist/features/cluster-runtime/application/use-cases/destroyMinikubeRuntimeAsync.d.ts +5 -0
  28. package/dist/features/cluster-runtime/application/use-cases/destroyMinikubeRuntimeAsync.d.ts.map +1 -0
  29. package/dist/features/cluster-runtime/application/use-cases/destroyMinikubeRuntimeAsync.js +73 -0
  30. package/dist/features/cluster-runtime/application/use-cases/destroyMinikubeRuntimeAsync.js.map +1 -0
  31. package/dist/features/cluster-runtime/application/use-cases/ensureMinikubeRuntimeAsync.d.ts +5 -0
  32. package/dist/features/cluster-runtime/application/use-cases/ensureMinikubeRuntimeAsync.d.ts.map +1 -0
  33. package/dist/features/cluster-runtime/application/use-cases/ensureMinikubeRuntimeAsync.js +67 -0
  34. package/dist/features/cluster-runtime/application/use-cases/ensureMinikubeRuntimeAsync.js.map +1 -0
  35. package/dist/features/cluster-runtime/application/use-cases/getMinikubeStatusAsync.d.ts +5 -0
  36. package/dist/features/cluster-runtime/application/use-cases/getMinikubeStatusAsync.d.ts.map +1 -0
  37. package/dist/features/cluster-runtime/application/use-cases/getMinikubeStatusAsync.js +27 -0
  38. package/dist/features/cluster-runtime/application/use-cases/getMinikubeStatusAsync.js.map +1 -0
  39. package/dist/features/cluster-runtime/application/use-cases/planMinikubeRuntimeAsync.d.ts +5 -0
  40. package/dist/features/cluster-runtime/application/use-cases/planMinikubeRuntimeAsync.d.ts.map +1 -0
  41. package/dist/features/cluster-runtime/application/use-cases/planMinikubeRuntimeAsync.js +83 -0
  42. package/dist/features/cluster-runtime/application/use-cases/planMinikubeRuntimeAsync.js.map +1 -0
  43. package/dist/features/cluster-runtime/application/use-cases/suspendMinikubeRuntimeAsync.d.ts +5 -0
  44. package/dist/features/cluster-runtime/application/use-cases/suspendMinikubeRuntimeAsync.d.ts.map +1 -0
  45. package/dist/features/cluster-runtime/application/use-cases/suspendMinikubeRuntimeAsync.js +17 -0
  46. package/dist/features/cluster-runtime/application/use-cases/suspendMinikubeRuntimeAsync.js.map +1 -0
  47. package/dist/features/cluster-runtime/application/use-cases/validateMinikubeRuntimeAsync.d.ts +5 -0
  48. package/dist/features/cluster-runtime/application/use-cases/validateMinikubeRuntimeAsync.d.ts.map +1 -0
  49. package/dist/features/cluster-runtime/application/use-cases/validateMinikubeRuntimeAsync.js +9 -0
  50. package/dist/features/cluster-runtime/application/use-cases/validateMinikubeRuntimeAsync.js.map +1 -0
  51. package/dist/features/cluster-runtime/composition/createInfraAdapter.d.ts +12 -0
  52. package/dist/features/cluster-runtime/composition/createInfraAdapter.d.ts.map +1 -0
  53. package/dist/features/cluster-runtime/composition/createInfraAdapter.js +29 -0
  54. package/dist/features/cluster-runtime/composition/createInfraAdapter.js.map +1 -0
  55. package/dist/features/cluster-runtime/utils/createKubernetesDriverRequest.d.ts +6 -0
  56. package/dist/features/cluster-runtime/utils/createKubernetesDriverRequest.d.ts.map +1 -0
  57. package/dist/features/cluster-runtime/utils/createKubernetesDriverRequest.js +10 -0
  58. package/dist/features/cluster-runtime/utils/createKubernetesDriverRequest.js.map +1 -0
  59. package/dist/features/cluster-runtime/utils/createMinikubeClusterOwner.d.ts +5 -0
  60. package/dist/features/cluster-runtime/utils/createMinikubeClusterOwner.d.ts.map +1 -0
  61. package/dist/features/cluster-runtime/utils/createMinikubeClusterOwner.js +16 -0
  62. package/dist/features/cluster-runtime/utils/createMinikubeClusterOwner.js.map +1 -0
  63. package/dist/features/cluster-runtime/utils/getMinikubeClusterIdentity.d.ts +5 -0
  64. package/dist/features/cluster-runtime/utils/getMinikubeClusterIdentity.d.ts.map +1 -0
  65. package/dist/features/cluster-runtime/utils/getMinikubeClusterIdentity.js +33 -0
  66. package/dist/features/cluster-runtime/utils/getMinikubeClusterIdentity.js.map +1 -0
  67. package/dist/features/cluster-runtime/utils/getMinikubeClusterSpec.d.ts +5 -0
  68. package/dist/features/cluster-runtime/utils/getMinikubeClusterSpec.d.ts.map +1 -0
  69. package/dist/features/cluster-runtime/utils/getMinikubeClusterSpec.js +40 -0
  70. package/dist/features/cluster-runtime/utils/getMinikubeClusterSpec.js.map +1 -0
  71. package/dist/index.d.ts +6 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +5 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/types/minikubeRuntime.d.ts +64 -0
  76. package/dist/types/minikubeRuntime.d.ts.map +1 -0
  77. package/dist/types/minikubeRuntime.js +2 -0
  78. package/dist/types/minikubeRuntime.js.map +1 -0
  79. package/package.json +67 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ankhorage
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,41 @@
1
- # Temporary Holding Version
1
+ <!-- markdownlint-disable MD013 MD033 -->
2
+ <!-- This file is generated by Paradox. Do not edit manually. -->
2
3
 
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.
4
+ # @ankhorage/infra-minikube
5
+
6
+ ![license: MIT](././paradox/badges/license.svg) ![npm: v0.4.128](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![paradox: warnings](././paradox/badges/docs.svg)
7
+
8
+ Minikube runtime adapter for provider-neutral Ankhorage infrastructure.
9
+
10
+ ## Generated documentation
11
+
12
+ - [Interactive documentation app](././paradox/index.html)
13
+ - [Public API reference](././paradox/exports.md)
14
+ - [Component registry](././paradox/components.md)
15
+ - [Architecture overview](././paradox/diagrams/architecture-overview.mmd)
16
+ - [Module relationships](././paradox/diagrams/module-relationships.mmd)
17
+ - [Export graph](././paradox/diagrams/export-graph.mmd)
18
+ - [createInfraAdapter sequence](././paradox/diagrams/sequences/create-infra-adapter.mmd)
19
+ - [createMinikubeCliControlPlane sequence](././paradox/diagrams/sequences/create-minikube-cli-control-plane.mmd)
20
+
21
+ ## Public API
22
+
23
+ ### Utilities
24
+
25
+ <details>
26
+ <summary>createInfraAdapter</summary>
27
+
28
+ ```ts
29
+ createInfraAdapter(options?: MinikubeAdapterOptions | undefined) => InfraRuntimeAdapter<"minikube">
30
+ ```
31
+
32
+ Create the canonical Minikube runtime adapter entrypoint.
33
+
34
+ The caller supplies a Minikube-specific command boundary. Standard workload projection and
35
+ reconciliation are delegated to the published Kubernetes driver.
36
+
37
+ Module: `src/features/cluster-runtime/composition/createInfraAdapter.ts`
38
+ Source: `src/features/cluster-runtime/composition/createInfraAdapter.ts:21:1`
39
+ Related symbols: `MinikubeAdapterOptions`
40
+
41
+ </details>
@@ -0,0 +1,11 @@
1
+ /** Canonical Contracts-backed identity used for adapter discovery and conformance. */
2
+ export declare const infraAdapterDescriptor: {
3
+ readonly id: "minikube";
4
+ readonly package: "@ankhorage/minikube";
5
+ readonly kind: "runtime";
6
+ readonly configVersion: 1;
7
+ readonly capabilities: readonly ["runtime", "workloads", "networking"];
8
+ readonly targets: readonly ["local-host"];
9
+ readonly dependencies: readonly ["compute"];
10
+ };
11
+ //# sourceMappingURL=infra.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infra.d.ts","sourceRoot":"","sources":["../../src/constants/infra.ts"],"names":[],"mappings":"AAGA,sFAAsF;AACtF,eAAO,MAAM,sBAAsB;;;;;;;;CAC0C,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { INFRA_ADAPTER_CATALOG } from '@ankhorage/contracts/infra';
2
+ /** Canonical Contracts-backed identity used for adapter discovery and conformance. */
3
+ export const infraAdapterDescriptor = INFRA_ADAPTER_CATALOG.minikube;
4
+ //# sourceMappingURL=infra.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infra.js","sourceRoot":"","sources":["../../src/constants/infra.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,sFAAsF;AACtF,MAAM,CAAC,MAAM,sBAAsB,GACjC,qBAAqB,CAAC,QAAqD,CAAC","sourcesContent":["import type { InfraAdapterDescriptor } from '@ankhorage/contracts/infra';\nimport { INFRA_ADAPTER_CATALOG } from '@ankhorage/contracts/infra';\n\n/** Canonical Contracts-backed identity used for adapter discovery and conformance. */\nexport const infraAdapterDescriptor =\n INFRA_ADAPTER_CATALOG.minikube satisfies InfraAdapterDescriptor<'minikube'>;\n"]}
@@ -0,0 +1,4 @@
1
+ import type { MinikubeCliControlPlaneOptions, MinikubeControlPlane } from '../../../types/minikubeRuntime';
2
+ /** Create the concrete stateless Minikube CLI control plane. */
3
+ export declare function createMinikubeCliControlPlane(options?: MinikubeCliControlPlaneOptions): MinikubeControlPlane;
4
+ //# sourceMappingURL=createMinikubeCliControlPlane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createMinikubeCliControlPlane.d.ts","sourceRoot":"","sources":["../../../../src/features/cluster-runtime/adapters/createMinikubeCliControlPlane.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,8BAA8B,EAI9B,oBAAoB,EACrB,MAAM,gCAAgC,CAAC;AAiBxC,gEAAgE;AAChE,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,8BAAmC,GAC3C,oBAAoB,CAYtB"}
@@ -0,0 +1,156 @@
1
+ import { createSubprocessMinikubeCommandRunner } from './createSubprocessMinikubeCommandRunner';
2
+ import { inspectMinikubeAsync } from './inspectMinikubeAsync';
3
+ import { delayMinikubePollAsync, runCheckedMinikubeCommandAsync } from './minikubeCliProcess';
4
+ import { readMinikubeEndpoints } from './readMinikubeEndpoints';
5
+ const IMAGE_LOAD_ATTEMPTS = 3;
6
+ /** Create the concrete stateless Minikube CLI control plane. */
7
+ export function createMinikubeCliControlPlane(options = {}) {
8
+ const context = {
9
+ runner: options.runner ?? createSubprocessMinikubeCommandRunner(),
10
+ executable: options.executable ?? 'minikube',
11
+ kubectlExecutable: options.kubectlExecutable ?? 'kubectl',
12
+ ...(options.kubectlRunner === undefined ? {} : { kubectlRunner: options.kubectlRunner }),
13
+ pollIntervalMs: options.pollIntervalMs ?? 500,
14
+ readinessTimeoutSeconds: options.readinessTimeoutSeconds ?? 120,
15
+ };
16
+ assertNonNegativeInteger('pollIntervalMs', context.pollIntervalMs);
17
+ assertPositiveInteger('readinessTimeoutSeconds', context.readinessTimeoutSeconds);
18
+ return createControlPlane(context);
19
+ }
20
+ function createControlPlane(context) {
21
+ return {
22
+ validateAsync: (spec, signal) => validateMinikubeCliAsync(context, spec, signal),
23
+ inspectAsync: (identity, signal) => inspectMinikubeAsync(context, identity, signal),
24
+ ensureAsync: (spec, signal) => ensureMinikubeCliAsync(context, spec, signal),
25
+ waitUntilReadyAsync: (identity, signal) => waitForMinikubeCliAsync(context, identity, signal),
26
+ loadImagesAsync: (identity, images, signal) => loadMinikubeImagesAsync(context, identity, images, signal),
27
+ repairEndpointsAsync: (identity, workloads, publicBaseUrl) => Promise.resolve(readMinikubeEndpoints(identity, workloads, publicBaseUrl)),
28
+ suspendAsync: (identity, signal) => suspendMinikubeCliAsync(context, identity, signal),
29
+ destroyAsync: (identity, signal) => destroyMinikubeCliAsync(context, identity, signal),
30
+ };
31
+ }
32
+ async function validateMinikubeCliAsync(context, spec, signal) {
33
+ const commands = [
34
+ [context.executable, ['version', '--output=json']],
35
+ [spec.driver, ['info']],
36
+ [context.kubectlExecutable, ['version', '--client=true', '--output=json']],
37
+ ];
38
+ for (const [executable, arguments_] of commands) {
39
+ const result = await runCheckedMinikubeCommandAsync(context.runner, executable, arguments_, signal);
40
+ if (!result.ok)
41
+ return result;
42
+ }
43
+ return { ok: true, value: null, diagnostics: [] };
44
+ }
45
+ async function ensureMinikubeCliAsync(context, spec, signal) {
46
+ const observed = await inspectMinikubeAsync(context, spec, signal);
47
+ if (!observed.ok)
48
+ return observed;
49
+ if (observed.value.state === 'ready' && observed.value.configurationMatches)
50
+ return observed;
51
+ const started = await runCheckedMinikubeCommandAsync(context.runner, context.executable, createStartArguments(spec), signal);
52
+ if (!started.ok)
53
+ return started;
54
+ const updated = await inspectMinikubeAsync(context, spec, signal);
55
+ return updated.ok && updated.value.configurationMatches ? updated : profileConfigurationDrift();
56
+ }
57
+ async function waitForMinikubeCliAsync(context, identity, signal) {
58
+ const deadline = Date.now() + context.readinessTimeoutSeconds * 1_000;
59
+ for (;;) {
60
+ const observed = await inspectMinikubeAsync(context, identity, signal);
61
+ if (!observed.ok)
62
+ return observed;
63
+ if (observed.value.state === 'ready')
64
+ return observed;
65
+ if (Date.now() >= deadline)
66
+ return readinessTimeout();
67
+ await delayMinikubePollAsync(Math.min(context.pollIntervalMs, Math.max(0, deadline - Date.now())), signal);
68
+ }
69
+ }
70
+ async function loadMinikubeImagesAsync(context, identity, images, signal) {
71
+ for (const image of images) {
72
+ const loaded = await loadMinikubeImageAsync(context, identity, image, 1, signal);
73
+ if (!loaded.ok)
74
+ return loaded;
75
+ }
76
+ return { ok: true, value: null, diagnostics: [] };
77
+ }
78
+ /*** Load one image with bounded retries because registry-backed image transfer is idempotent. */
79
+ async function loadMinikubeImageAsync(context, identity, image, attempt, signal) {
80
+ const loaded = await runCheckedMinikubeCommandAsync(context.runner, context.executable, ['image', 'load', image, '-p', identity.profile], signal);
81
+ if (loaded.ok)
82
+ return { ok: true, value: null, diagnostics: [] };
83
+ if (attempt >= IMAGE_LOAD_ATTEMPTS)
84
+ return loaded;
85
+ await delayMinikubePollAsync(context.pollIntervalMs, signal);
86
+ return loadMinikubeImageAsync(context, identity, image, attempt + 1, signal);
87
+ }
88
+ async function suspendMinikubeCliAsync(context, identity, signal) {
89
+ const observed = await inspectMinikubeAsync(context, identity, signal);
90
+ if (!observed.ok)
91
+ return observed;
92
+ if (observed.value.state === 'absent' || observed.value.state === 'stopped') {
93
+ return { ok: true, value: null, diagnostics: [] };
94
+ }
95
+ const stopped = await runCheckedMinikubeCommandAsync(context.runner, context.executable, ['stop', '-p', identity.profile, '--output=json'], signal);
96
+ return stopped.ok ? { ok: true, value: null, diagnostics: [] } : stopped;
97
+ }
98
+ async function destroyMinikubeCliAsync(context, identity, signal) {
99
+ const observed = await inspectMinikubeAsync(context, identity, signal);
100
+ if (!observed.ok)
101
+ return observed;
102
+ if (observed.value.state === 'absent') {
103
+ return { ok: true, value: null, diagnostics: [] };
104
+ }
105
+ const destroyed = await runCheckedMinikubeCommandAsync(context.runner, context.executable, ['delete', '-p', identity.profile, '--output=json'], signal);
106
+ return destroyed.ok ? { ok: true, value: null, diagnostics: [] } : destroyed;
107
+ }
108
+ function createStartArguments(spec) {
109
+ return [
110
+ 'start',
111
+ '-p',
112
+ spec.profile,
113
+ `--driver=${spec.driver}`,
114
+ '--interactive=false',
115
+ '--addons=ingress',
116
+ ...spec.publishedPorts.map((port) => `--ports=${port}:${port}`),
117
+ ...(spec.cpus === undefined ? [] : [`--cpus=${spec.cpus}`]),
118
+ ...(spec.memoryMiB === undefined ? [] : [`--memory=${spec.memoryMiB}mb`]),
119
+ ];
120
+ }
121
+ /*** Refuse to report convergence when an existing profile cannot adopt required port mappings. */
122
+ function profileConfigurationDrift() {
123
+ return {
124
+ ok: false,
125
+ diagnostics: [
126
+ {
127
+ severity: 'error',
128
+ code: 'minikube-profile-configuration-drift',
129
+ message: 'The existing Minikube profile does not expose the desired workload ports; destroy and recreate the owned profile explicitly.',
130
+ },
131
+ ],
132
+ };
133
+ }
134
+ function readinessTimeout() {
135
+ return {
136
+ ok: false,
137
+ diagnostics: [
138
+ {
139
+ severity: 'error',
140
+ code: 'minikube-readiness-timeout',
141
+ message: 'Timed out waiting for the Minikube cluster to become ready.',
142
+ },
143
+ ],
144
+ };
145
+ }
146
+ function assertNonNegativeInteger(name, value) {
147
+ if (!Number.isInteger(value) || value < 0) {
148
+ throw new TypeError(`Minikube ${name} must be a non-negative integer.`);
149
+ }
150
+ }
151
+ function assertPositiveInteger(name, value) {
152
+ if (!Number.isInteger(value) || value <= 0) {
153
+ throw new TypeError(`Minikube ${name} must be a positive integer.`);
154
+ }
155
+ }
156
+ //# sourceMappingURL=createMinikubeCliControlPlane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createMinikubeCliControlPlane.js","sourceRoot":"","sources":["../../../../src/features/cluster-runtime/adapters/createMinikubeCliControlPlane.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InfraResult } from '@ankhorage/contracts/infra';\n\nimport type {\n MinikubeCliControlPlaneOptions,\n MinikubeClusterIdentity,\n MinikubeClusterSpec,\n MinikubeCommandRunner,\n MinikubeControlPlane,\n} from '../../../types/minikubeRuntime';\nimport { createSubprocessMinikubeCommandRunner } from './createSubprocessMinikubeCommandRunner';\nimport { inspectMinikubeAsync } from './inspectMinikubeAsync';\nimport { delayMinikubePollAsync, runCheckedMinikubeCommandAsync } from './minikubeCliProcess';\nimport { readMinikubeEndpoints } from './readMinikubeEndpoints';\n\nconst IMAGE_LOAD_ATTEMPTS = 3;\n\ninterface MinikubeCliContext {\n readonly runner: MinikubeCommandRunner;\n readonly executable: string;\n readonly kubectlExecutable: string;\n readonly kubectlRunner?: MinikubeCliControlPlaneOptions['kubectlRunner'];\n readonly pollIntervalMs: number;\n readonly readinessTimeoutSeconds: number;\n}\n\n/** Create the concrete stateless Minikube CLI control plane. */\nexport function createMinikubeCliControlPlane(\n options: MinikubeCliControlPlaneOptions = {},\n): MinikubeControlPlane {\n const context: MinikubeCliContext = {\n runner: options.runner ?? createSubprocessMinikubeCommandRunner(),\n executable: options.executable ?? 'minikube',\n kubectlExecutable: options.kubectlExecutable ?? 'kubectl',\n ...(options.kubectlRunner === undefined ? {} : { kubectlRunner: options.kubectlRunner }),\n pollIntervalMs: options.pollIntervalMs ?? 500,\n readinessTimeoutSeconds: options.readinessTimeoutSeconds ?? 120,\n };\n assertNonNegativeInteger('pollIntervalMs', context.pollIntervalMs);\n assertPositiveInteger('readinessTimeoutSeconds', context.readinessTimeoutSeconds);\n return createControlPlane(context);\n}\n\nfunction createControlPlane(context: MinikubeCliContext): MinikubeControlPlane {\n return {\n validateAsync: (spec, signal) => validateMinikubeCliAsync(context, spec, signal),\n inspectAsync: (identity, signal) => inspectMinikubeAsync(context, identity, signal),\n ensureAsync: (spec, signal) => ensureMinikubeCliAsync(context, spec, signal),\n waitUntilReadyAsync: (identity, signal) => waitForMinikubeCliAsync(context, identity, signal),\n loadImagesAsync: (identity, images, signal) =>\n loadMinikubeImagesAsync(context, identity, images, signal),\n repairEndpointsAsync: (identity, workloads, publicBaseUrl) =>\n Promise.resolve(readMinikubeEndpoints(identity, workloads, publicBaseUrl)),\n suspendAsync: (identity, signal) => suspendMinikubeCliAsync(context, identity, signal),\n destroyAsync: (identity, signal) => destroyMinikubeCliAsync(context, identity, signal),\n };\n}\n\nasync function validateMinikubeCliAsync(\n context: MinikubeCliContext,\n spec: MinikubeClusterSpec,\n signal?: AbortSignal,\n): Promise<InfraResult<null>> {\n const commands: readonly [string, readonly string[]][] = [\n [context.executable, ['version', '--output=json']],\n [spec.driver, ['info']],\n [context.kubectlExecutable, ['version', '--client=true', '--output=json']],\n ];\n for (const [executable, arguments_] of commands) {\n const result = await runCheckedMinikubeCommandAsync(\n context.runner,\n executable,\n arguments_,\n signal,\n );\n if (!result.ok) return result;\n }\n return { ok: true, value: null, diagnostics: [] };\n}\n\nasync function ensureMinikubeCliAsync(\n context: MinikubeCliContext,\n spec: MinikubeClusterSpec,\n signal?: AbortSignal,\n) {\n const observed = await inspectMinikubeAsync(context, spec, signal);\n if (!observed.ok) return observed;\n if (observed.value.state === 'ready' && observed.value.configurationMatches) return observed;\n const started = await runCheckedMinikubeCommandAsync(\n context.runner,\n context.executable,\n createStartArguments(spec),\n signal,\n );\n if (!started.ok) return started;\n const updated = await inspectMinikubeAsync(context, spec, signal);\n return updated.ok && updated.value.configurationMatches ? updated : profileConfigurationDrift();\n}\n\nasync function waitForMinikubeCliAsync(\n context: MinikubeCliContext,\n identity: MinikubeClusterIdentity,\n signal?: AbortSignal,\n) {\n const deadline = Date.now() + context.readinessTimeoutSeconds * 1_000;\n for (;;) {\n const observed = await inspectMinikubeAsync(context, identity, signal);\n if (!observed.ok) return observed;\n if (observed.value.state === 'ready') return observed;\n if (Date.now() >= deadline) return readinessTimeout();\n await delayMinikubePollAsync(\n Math.min(context.pollIntervalMs, Math.max(0, deadline - Date.now())),\n signal,\n );\n }\n}\n\nasync function loadMinikubeImagesAsync(\n context: MinikubeCliContext,\n identity: MinikubeClusterIdentity,\n images: readonly string[],\n signal?: AbortSignal,\n): Promise<InfraResult<null>> {\n for (const image of images) {\n const loaded = await loadMinikubeImageAsync(context, identity, image, 1, signal);\n if (!loaded.ok) return loaded;\n }\n return { ok: true, value: null, diagnostics: [] };\n}\n\n/*** Load one image with bounded retries because registry-backed image transfer is idempotent. */\nasync function loadMinikubeImageAsync(\n context: MinikubeCliContext,\n identity: MinikubeClusterIdentity,\n image: string,\n attempt: number,\n signal?: AbortSignal,\n): Promise<InfraResult<null>> {\n const loaded = await runCheckedMinikubeCommandAsync(\n context.runner,\n context.executable,\n ['image', 'load', image, '-p', identity.profile],\n signal,\n );\n if (loaded.ok) return { ok: true, value: null, diagnostics: [] };\n if (attempt >= IMAGE_LOAD_ATTEMPTS) return loaded;\n await delayMinikubePollAsync(context.pollIntervalMs, signal);\n return loadMinikubeImageAsync(context, identity, image, attempt + 1, signal);\n}\n\nasync function suspendMinikubeCliAsync(\n context: MinikubeCliContext,\n identity: MinikubeClusterIdentity,\n signal?: AbortSignal,\n): Promise<InfraResult<null>> {\n const observed = await inspectMinikubeAsync(context, identity, signal);\n if (!observed.ok) return observed;\n if (observed.value.state === 'absent' || observed.value.state === 'stopped') {\n return { ok: true, value: null, diagnostics: [] };\n }\n const stopped = await runCheckedMinikubeCommandAsync(\n context.runner,\n context.executable,\n ['stop', '-p', identity.profile, '--output=json'],\n signal,\n );\n return stopped.ok ? { ok: true, value: null, diagnostics: [] } : stopped;\n}\n\nasync function destroyMinikubeCliAsync(\n context: MinikubeCliContext,\n identity: MinikubeClusterIdentity,\n signal?: AbortSignal,\n): Promise<InfraResult<null>> {\n const observed = await inspectMinikubeAsync(context, identity, signal);\n if (!observed.ok) return observed;\n if (observed.value.state === 'absent') {\n return { ok: true, value: null, diagnostics: [] };\n }\n const destroyed = await runCheckedMinikubeCommandAsync(\n context.runner,\n context.executable,\n ['delete', '-p', identity.profile, '--output=json'],\n signal,\n );\n return destroyed.ok ? { ok: true, value: null, diagnostics: [] } : destroyed;\n}\n\nfunction createStartArguments(spec: MinikubeClusterSpec): readonly string[] {\n return [\n 'start',\n '-p',\n spec.profile,\n `--driver=${spec.driver}`,\n '--interactive=false',\n '--addons=ingress',\n ...spec.publishedPorts.map((port) => `--ports=${port}:${port}`),\n ...(spec.cpus === undefined ? [] : [`--cpus=${spec.cpus}`]),\n ...(spec.memoryMiB === undefined ? [] : [`--memory=${spec.memoryMiB}mb`]),\n ];\n}\n\n/*** Refuse to report convergence when an existing profile cannot adopt required port mappings. */\nfunction profileConfigurationDrift(): InfraResult<never> {\n return {\n ok: false,\n diagnostics: [\n {\n severity: 'error',\n code: 'minikube-profile-configuration-drift',\n message:\n 'The existing Minikube profile does not expose the desired workload ports; destroy and recreate the owned profile explicitly.',\n },\n ],\n };\n}\n\nfunction readinessTimeout(): InfraResult<never> {\n return {\n ok: false,\n diagnostics: [\n {\n severity: 'error',\n code: 'minikube-readiness-timeout',\n message: 'Timed out waiting for the Minikube cluster to become ready.',\n },\n ],\n };\n}\n\nfunction assertNonNegativeInteger(name: string, value: number): void {\n if (!Number.isInteger(value) || value < 0) {\n throw new TypeError(`Minikube ${name} must be a non-negative integer.`);\n }\n}\n\nfunction assertPositiveInteger(name: string, value: number): void {\n if (!Number.isInteger(value) || value <= 0) {\n throw new TypeError(`Minikube ${name} must be a positive integer.`);\n }\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { MinikubeCommandRunner } from '../../../types/minikubeRuntime';
2
+ /** Create the concrete shell-free subprocess boundary used by Minikube operations. */
3
+ export declare function createSubprocessMinikubeCommandRunner(): MinikubeCommandRunner;
4
+ //# sourceMappingURL=createSubprocessMinikubeCommandRunner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createSubprocessMinikubeCommandRunner.d.ts","sourceRoot":"","sources":["../../../../src/features/cluster-runtime/adapters/createSubprocessMinikubeCommandRunner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,qBAAqB,EACtB,MAAM,gCAAgC,CAAC;AAExC,sFAAsF;AACtF,wBAAgB,qCAAqC,IAAI,qBAAqB,CAE7E"}
@@ -0,0 +1,26 @@
1
+ import { spawn } from 'node:child_process';
2
+ /** Create the concrete shell-free subprocess boundary used by Minikube operations. */
3
+ export function createSubprocessMinikubeCommandRunner() {
4
+ return { runAsync };
5
+ }
6
+ /** Execute one argv-safe command without exposing process output through thrown errors. */
7
+ function runAsync(request) {
8
+ return new Promise((resolve, reject) => {
9
+ const child = spawn(request.executable, [...request.arguments], {
10
+ shell: false,
11
+ stdio: ['ignore', 'pipe', 'pipe'],
12
+ ...(request.signal === undefined ? {} : { signal: request.signal }),
13
+ });
14
+ const stdout = [];
15
+ const stderr = [];
16
+ child.stdout.on('data', (chunk) => stdout.push(chunk));
17
+ child.stderr.on('data', (chunk) => stderr.push(chunk));
18
+ child.once('error', reject);
19
+ child.once('close', (exitCode) => resolve({
20
+ exitCode: exitCode ?? 1,
21
+ stdout: Buffer.concat(stdout).toString('utf8'),
22
+ stderr: Buffer.concat(stderr).toString('utf8'),
23
+ }));
24
+ });
25
+ }
26
+ //# sourceMappingURL=createSubprocessMinikubeCommandRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createSubprocessMinikubeCommandRunner.js","sourceRoot":"","sources":["../../../../src/features/cluster-runtime/adapters/createSubprocessMinikubeCommandRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAQ3C,sFAAsF;AACtF,MAAM,UAAU,qCAAqC;IACnD,OAAO,EAAE,QAAQ,EAAE,CAAC;AACtB,CAAC;AAED,2FAA2F;AAC3F,SAAS,QAAQ,CAAC,OAA+B;IAC/C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,EAAE;YAC9D,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACjC,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;SACpE,CAAC,CAAC;QACH,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/D,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC/B,OAAO,CAAC;YACN,QAAQ,EAAE,QAAQ,IAAI,CAAC;YACvB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;SAC/C,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { spawn } from 'node:child_process';\n\nimport type {\n MinikubeCommandRequest,\n MinikubeCommandResult,\n MinikubeCommandRunner,\n} from '../../../types/minikubeRuntime';\n\n/** Create the concrete shell-free subprocess boundary used by Minikube operations. */\nexport function createSubprocessMinikubeCommandRunner(): MinikubeCommandRunner {\n return { runAsync };\n}\n\n/** Execute one argv-safe command without exposing process output through thrown errors. */\nfunction runAsync(request: MinikubeCommandRequest): Promise<MinikubeCommandResult> {\n return new Promise((resolve, reject) => {\n const child = spawn(request.executable, [...request.arguments], {\n shell: false,\n stdio: ['ignore', 'pipe', 'pipe'],\n ...(request.signal === undefined ? {} : { signal: request.signal }),\n });\n const stdout: Buffer[] = [];\n const stderr: Buffer[] = [];\n child.stdout.on('data', (chunk: Buffer) => stdout.push(chunk));\n child.stderr.on('data', (chunk: Buffer) => stderr.push(chunk));\n child.once('error', reject);\n child.once('close', (exitCode) =>\n resolve({\n exitCode: exitCode ?? 1,\n stdout: Buffer.concat(stdout).toString('utf8'),\n stderr: Buffer.concat(stderr).toString('utf8'),\n }),\n );\n });\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import type { InfraResult } from '@ankhorage/contracts/infra';
2
+ import type { MinikubeCliControlPlaneOptions, MinikubeClusterIdentity, MinikubeClusterObservation, MinikubeClusterSpec, MinikubeCommandRunner } from '../../../types/minikubeRuntime';
3
+ interface InspectMinikubeOptions {
4
+ readonly runner: MinikubeCommandRunner;
5
+ readonly executable: string;
6
+ readonly kubectlExecutable: string;
7
+ readonly kubectlRunner?: MinikubeCliControlPlaneOptions['kubectlRunner'];
8
+ }
9
+ /** Inspect exact profile configuration and live status without mutating Minikube. */
10
+ export declare function inspectMinikubeAsync(options: InspectMinikubeOptions, identity: MinikubeClusterIdentity | MinikubeClusterSpec, signal?: AbortSignal): Promise<InfraResult<MinikubeClusterObservation>>;
11
+ export {};
12
+ //# sourceMappingURL=inspectMinikubeAsync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspectMinikubeAsync.d.ts","sourceRoot":"","sources":["../../../../src/features/cluster-runtime/adapters/inspectMinikubeAsync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAG9D,OAAO,KAAK,EACV,8BAA8B,EAC9B,uBAAuB,EACvB,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,gCAAgC,CAAC;AAaxC,UAAU,sBAAsB;IAC9B,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,8BAA8B,CAAC,eAAe,CAAC,CAAC;CAC1E;AAED,qFAAqF;AACrF,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,EAAE,uBAAuB,GAAG,mBAAmB,EACvD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC,CAYlD"}
@@ -0,0 +1,141 @@
1
+ import { createKubectlKubernetesApi } from '@ankhorage/kubernetes';
2
+ import { runCheckedMinikubeCommandAsync, runMinikubeCommandAsync } from './minikubeCliProcess';
3
+ const STATUS_FORMAT = '{{.Host}}|{{.Kubelet}}|{{.APIServer}}|{{.Kubeconfig}}';
4
+ /** Inspect exact profile configuration and live status without mutating Minikube. */
5
+ export async function inspectMinikubeAsync(options, identity, signal) {
6
+ const listed = await runCheckedMinikubeCommandAsync(options.runner, options.executable, ['profile', 'list', '--light', '--output=json'], signal);
7
+ if (!listed.ok)
8
+ return listed;
9
+ const profile = readProfile(listed.value.stdout, identity.profile);
10
+ if (!profile.ok)
11
+ return profile;
12
+ if (profile.value === undefined)
13
+ return absentObservation();
14
+ return inspectExistingMinikubeAsync(options, identity, profile.value, signal);
15
+ }
16
+ async function inspectExistingMinikubeAsync(options, identity, profile, signal) {
17
+ const status = await runMinikubeCommandAsync(options.runner, options.executable, ['status', '-p', identity.profile, '--format', STATUS_FORMAT], signal);
18
+ if (!status.ok)
19
+ return status;
20
+ const state = readStatus(status.value.stdout);
21
+ return {
22
+ ok: true,
23
+ value: {
24
+ state,
25
+ configurationMatches: profileMatches(profile, identity),
26
+ ...(state === 'ready' ? { api: createKubernetesApi(options, identity.profile) } : {}),
27
+ ...(status.value.exitCode === 0 ? {} : { detail: 'Minikube profile is not ready.' }),
28
+ },
29
+ diagnostics: [],
30
+ };
31
+ }
32
+ function createKubernetesApi(options, context) {
33
+ return createKubectlKubernetesApi({
34
+ context,
35
+ executable: options.kubectlExecutable,
36
+ ...(options.kubectlRunner === undefined ? {} : { runner: options.kubectlRunner }),
37
+ });
38
+ }
39
+ function absentObservation() {
40
+ return {
41
+ ok: true,
42
+ value: { state: 'absent', configurationMatches: true },
43
+ diagnostics: [],
44
+ };
45
+ }
46
+ /** Compare only user-controlled profile fields; omitted resources accept existing defaults. */
47
+ function profileMatches(profile, identity) {
48
+ if (!isClusterSpec(identity))
49
+ return true;
50
+ return (profile.driver === identity.driver &&
51
+ (identity.cpus === undefined || profile.cpus === identity.cpus) &&
52
+ (identity.memoryMiB === undefined || profile.memoryMiB === identity.memoryMiB) &&
53
+ arraysEqual(profile.publishedPorts, identity.publishedPorts));
54
+ }
55
+ function isClusterSpec(identity) {
56
+ return 'driver' in identity;
57
+ }
58
+ /** Parse one exact profile from Minikube's machine-readable profile catalog. */
59
+ function readProfile(input, name) {
60
+ const parsed = parseJson(input);
61
+ if (!parsed.ok)
62
+ return parsed;
63
+ if (!isRecord(parsed.value))
64
+ return invalidOutput();
65
+ const { valid, invalid } = parsed.value;
66
+ const entries = [...toUnknownArray(valid), ...toUnknownArray(invalid)];
67
+ const entry = entries.find((candidate) => isRecord(candidate) && candidate.Name === name);
68
+ if (!isRecord(entry))
69
+ return { ok: true, value: undefined, diagnostics: [] };
70
+ const config = isRecord(entry.Config) ? entry.Config : undefined;
71
+ return { ok: true, value: readProfileConfig(name, config), diagnostics: [] };
72
+ }
73
+ function toUnknownArray(value) {
74
+ return Array.isArray(value) ? value : [];
75
+ }
76
+ function readProfileConfig(name, config) {
77
+ return {
78
+ name,
79
+ ...(typeof config?.Driver === 'string' ? { driver: config.Driver } : {}),
80
+ ...(typeof config?.CPUs === 'number' ? { cpus: config.CPUs } : {}),
81
+ ...(typeof config?.Memory === 'number' ? { memoryMiB: config.Memory } : {}),
82
+ publishedPorts: readPublishedPorts(config?.ExposedPorts),
83
+ };
84
+ }
85
+ /*** Parse Minikube's host-to-profile port mappings into sorted exact host listeners. */
86
+ function readPublishedPorts(value) {
87
+ if (!Array.isArray(value))
88
+ return [];
89
+ return value
90
+ .flatMap((entry) => {
91
+ if (typeof entry !== 'string')
92
+ return [];
93
+ const [, hostPortText] = entry.split(':').reverse();
94
+ const hostPort = Number(hostPortText);
95
+ return Number.isInteger(hostPort) && hostPort > 0 && hostPort <= 65_535 ? [hostPort] : [];
96
+ })
97
+ .sort((left, right) => left - right);
98
+ }
99
+ /*** Compare two already sorted numeric port sets exactly. */
100
+ function arraysEqual(left, right) {
101
+ return left.length === right.length && left.join(',') === right.join(',');
102
+ }
103
+ /** Map Minikube component status into the provider-neutral lifecycle state. */
104
+ function readStatus(input) {
105
+ const [host, kubelet, apiServer, kubeconfig] = input.trim().split('|');
106
+ if (host === 'Running' &&
107
+ kubelet === 'Running' &&
108
+ apiServer === 'Running' &&
109
+ kubeconfig === 'Configured') {
110
+ return 'ready';
111
+ }
112
+ if (host === 'Stopped')
113
+ return 'stopped';
114
+ if (host === 'Running')
115
+ return 'pending';
116
+ return 'unknown';
117
+ }
118
+ function parseJson(input) {
119
+ try {
120
+ return { ok: true, value: JSON.parse(input), diagnostics: [] };
121
+ }
122
+ catch {
123
+ return invalidOutput();
124
+ }
125
+ }
126
+ function isRecord(value) {
127
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
128
+ }
129
+ function invalidOutput() {
130
+ return {
131
+ ok: false,
132
+ diagnostics: [
133
+ {
134
+ severity: 'error',
135
+ code: 'minikube-output-invalid',
136
+ message: 'Minikube returned an invalid machine-readable response.',
137
+ },
138
+ ],
139
+ };
140
+ }
141
+ //# sourceMappingURL=inspectMinikubeAsync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspectMinikubeAsync.js","sourceRoot":"","sources":["../../../../src/features/cluster-runtime/adapters/inspectMinikubeAsync.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InfraResult } from '@ankhorage/contracts/infra';\nimport { createKubectlKubernetesApi } from '@ankhorage/kubernetes';\n\nimport type {\n MinikubeCliControlPlaneOptions,\n MinikubeClusterIdentity,\n MinikubeClusterObservation,\n MinikubeClusterSpec,\n MinikubeCommandRunner,\n} from '../../../types/minikubeRuntime';\nimport { runCheckedMinikubeCommandAsync, runMinikubeCommandAsync } from './minikubeCliProcess';\n\nconst STATUS_FORMAT = '{{.Host}}|{{.Kubelet}}|{{.APIServer}}|{{.Kubeconfig}}';\n\ninterface MinikubeProfile {\n readonly name: string;\n readonly driver?: string;\n readonly cpus?: number;\n readonly memoryMiB?: number;\n readonly publishedPorts: readonly number[];\n}\n\ninterface InspectMinikubeOptions {\n readonly runner: MinikubeCommandRunner;\n readonly executable: string;\n readonly kubectlExecutable: string;\n readonly kubectlRunner?: MinikubeCliControlPlaneOptions['kubectlRunner'];\n}\n\n/** Inspect exact profile configuration and live status without mutating Minikube. */\nexport async function inspectMinikubeAsync(\n options: InspectMinikubeOptions,\n identity: MinikubeClusterIdentity | MinikubeClusterSpec,\n signal?: AbortSignal,\n): Promise<InfraResult<MinikubeClusterObservation>> {\n const listed = await runCheckedMinikubeCommandAsync(\n options.runner,\n options.executable,\n ['profile', 'list', '--light', '--output=json'],\n signal,\n );\n if (!listed.ok) return listed;\n const profile = readProfile(listed.value.stdout, identity.profile);\n if (!profile.ok) return profile;\n if (profile.value === undefined) return absentObservation();\n return inspectExistingMinikubeAsync(options, identity, profile.value, signal);\n}\n\nasync function inspectExistingMinikubeAsync(\n options: InspectMinikubeOptions,\n identity: MinikubeClusterIdentity | MinikubeClusterSpec,\n profile: MinikubeProfile,\n signal?: AbortSignal,\n): Promise<InfraResult<MinikubeClusterObservation>> {\n const status = await runMinikubeCommandAsync(\n options.runner,\n options.executable,\n ['status', '-p', identity.profile, '--format', STATUS_FORMAT],\n signal,\n );\n if (!status.ok) return status;\n const state = readStatus(status.value.stdout);\n return {\n ok: true,\n value: {\n state,\n configurationMatches: profileMatches(profile, identity),\n ...(state === 'ready' ? { api: createKubernetesApi(options, identity.profile) } : {}),\n ...(status.value.exitCode === 0 ? {} : { detail: 'Minikube profile is not ready.' }),\n },\n diagnostics: [],\n };\n}\n\nfunction createKubernetesApi(options: InspectMinikubeOptions, context: string) {\n return createKubectlKubernetesApi({\n context,\n executable: options.kubectlExecutable,\n ...(options.kubectlRunner === undefined ? {} : { runner: options.kubectlRunner }),\n });\n}\n\nfunction absentObservation(): InfraResult<MinikubeClusterObservation> {\n return {\n ok: true,\n value: { state: 'absent', configurationMatches: true },\n diagnostics: [],\n };\n}\n\n/** Compare only user-controlled profile fields; omitted resources accept existing defaults. */\nfunction profileMatches(\n profile: MinikubeProfile,\n identity: MinikubeClusterIdentity | MinikubeClusterSpec,\n): boolean {\n if (!isClusterSpec(identity)) return true;\n return (\n profile.driver === identity.driver &&\n (identity.cpus === undefined || profile.cpus === identity.cpus) &&\n (identity.memoryMiB === undefined || profile.memoryMiB === identity.memoryMiB) &&\n arraysEqual(profile.publishedPorts, identity.publishedPorts)\n );\n}\n\nfunction isClusterSpec(\n identity: MinikubeClusterIdentity | MinikubeClusterSpec,\n): identity is MinikubeClusterSpec {\n return 'driver' in identity;\n}\n\n/** Parse one exact profile from Minikube's machine-readable profile catalog. */\nfunction readProfile(input: string, name: string): InfraResult<MinikubeProfile | undefined> {\n const parsed = parseJson(input);\n if (!parsed.ok) return parsed;\n if (!isRecord(parsed.value)) return invalidOutput();\n const { valid, invalid } = parsed.value;\n const entries: readonly unknown[] = [...toUnknownArray(valid), ...toUnknownArray(invalid)];\n const entry = entries.find((candidate) => isRecord(candidate) && candidate.Name === name);\n if (!isRecord(entry)) return { ok: true, value: undefined, diagnostics: [] };\n const config = isRecord(entry.Config) ? entry.Config : undefined;\n return { ok: true, value: readProfileConfig(name, config), diagnostics: [] };\n}\n\nfunction toUnknownArray(value: unknown): readonly unknown[] {\n return Array.isArray(value) ? (value as readonly unknown[]) : [];\n}\n\nfunction readProfileConfig(\n name: string,\n config: Readonly<Record<string, unknown>> | undefined,\n): MinikubeProfile {\n return {\n name,\n ...(typeof config?.Driver === 'string' ? { driver: config.Driver } : {}),\n ...(typeof config?.CPUs === 'number' ? { cpus: config.CPUs } : {}),\n ...(typeof config?.Memory === 'number' ? { memoryMiB: config.Memory } : {}),\n publishedPorts: readPublishedPorts(config?.ExposedPorts),\n };\n}\n\n/*** Parse Minikube's host-to-profile port mappings into sorted exact host listeners. */\nfunction readPublishedPorts(value: unknown): readonly number[] {\n if (!Array.isArray(value)) return [];\n return value\n .flatMap((entry) => {\n if (typeof entry !== 'string') return [];\n const [, hostPortText] = entry.split(':').reverse();\n const hostPort = Number(hostPortText);\n return Number.isInteger(hostPort) && hostPort > 0 && hostPort <= 65_535 ? [hostPort] : [];\n })\n .sort((left, right) => left - right);\n}\n\n/*** Compare two already sorted numeric port sets exactly. */\nfunction arraysEqual(left: readonly number[], right: readonly number[]): boolean {\n return left.length === right.length && left.join(',') === right.join(',');\n}\n\n/** Map Minikube component status into the provider-neutral lifecycle state. */\nfunction readStatus(input: string): MinikubeClusterObservation['state'] {\n const [host, kubelet, apiServer, kubeconfig] = input.trim().split('|');\n if (\n host === 'Running' &&\n kubelet === 'Running' &&\n apiServer === 'Running' &&\n kubeconfig === 'Configured'\n ) {\n return 'ready';\n }\n if (host === 'Stopped') return 'stopped';\n if (host === 'Running') return 'pending';\n return 'unknown';\n}\n\nfunction parseJson(input: string): InfraResult<unknown> {\n try {\n return { ok: true, value: JSON.parse(input) as unknown, diagnostics: [] };\n } catch {\n return invalidOutput();\n }\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction invalidOutput(): InfraResult<never> {\n return {\n ok: false,\n diagnostics: [\n {\n severity: 'error',\n code: 'minikube-output-invalid',\n message: 'Minikube returned an invalid machine-readable response.',\n },\n ],\n };\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { InfraResult } from '@ankhorage/contracts/infra';
2
+ import type { MinikubeCommandResult, MinikubeCommandRunner } from '../../../types/minikubeRuntime';
3
+ /** Run one command, retaining exit status for state-oriented Minikube commands. */
4
+ export declare function runMinikubeCommandAsync(runner: MinikubeCommandRunner, executable: string, arguments_: readonly string[], signal?: AbortSignal): Promise<InfraResult<MinikubeCommandResult>>;
5
+ /** Run one command that must exit successfully. */
6
+ export declare function runCheckedMinikubeCommandAsync(runner: MinikubeCommandRunner, executable: string, arguments_: readonly string[], signal?: AbortSignal): Promise<InfraResult<MinikubeCommandResult>>;
7
+ /** Wait between status observations and abort promptly when requested. */
8
+ export declare function delayMinikubePollAsync(milliseconds: number, signal?: AbortSignal): Promise<void>;
9
+ //# sourceMappingURL=minikubeCliProcess.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minikubeCliProcess.d.ts","sourceRoot":"","sources":["../../../../src/features/cluster-runtime/adapters/minikubeCliProcess.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,KAAK,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAEnG,mFAAmF;AACnF,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,qBAAqB,EAC7B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC,CAW7C;AAED,mDAAmD;AACnD,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,qBAAqB,EAC7B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC,CAG7C;AAgBD,0EAA0E;AAC1E,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhG"}
@@ -0,0 +1,56 @@
1
+ /** Run one command, retaining exit status for state-oriented Minikube commands. */
2
+ export async function runMinikubeCommandAsync(runner, executable, arguments_, signal) {
3
+ try {
4
+ const value = await runner.runAsync({
5
+ executable,
6
+ arguments: arguments_,
7
+ ...(signal === undefined ? {} : { signal }),
8
+ });
9
+ return { ok: true, value, diagnostics: [] };
10
+ }
11
+ catch {
12
+ return minikubeCommandFailure();
13
+ }
14
+ }
15
+ /** Run one command that must exit successfully. */
16
+ export async function runCheckedMinikubeCommandAsync(runner, executable, arguments_, signal) {
17
+ const result = await runMinikubeCommandAsync(runner, executable, arguments_, signal);
18
+ return result.ok && result.value.exitCode === 0 ? result : minikubeCommandFailure();
19
+ }
20
+ /** Return a provider-safe command failure that excludes stdout and stderr. */
21
+ function minikubeCommandFailure() {
22
+ return {
23
+ ok: false,
24
+ diagnostics: [
25
+ {
26
+ severity: 'error',
27
+ code: 'minikube-command-failed',
28
+ message: 'A required Minikube control-plane command failed.',
29
+ },
30
+ ],
31
+ };
32
+ }
33
+ /** Wait between status observations and abort promptly when requested. */
34
+ export function delayMinikubePollAsync(milliseconds, signal) {
35
+ if (signal === undefined)
36
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
37
+ return new Promise((resolve, reject) => {
38
+ if (signal.aborted) {
39
+ reject(abortError(signal));
40
+ return;
41
+ }
42
+ const onAbort = () => {
43
+ clearTimeout(timeout);
44
+ reject(abortError(signal));
45
+ };
46
+ const timeout = setTimeout(() => {
47
+ signal.removeEventListener('abort', onAbort);
48
+ resolve();
49
+ }, milliseconds);
50
+ signal.addEventListener('abort', onAbort, { once: true });
51
+ });
52
+ }
53
+ function abortError(signal) {
54
+ return signal.reason instanceof Error ? signal.reason : new Error('Minikube operation aborted.');
55
+ }
56
+ //# sourceMappingURL=minikubeCliProcess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minikubeCliProcess.js","sourceRoot":"","sources":["../../../../src/features/cluster-runtime/adapters/minikubeCliProcess.ts"],"names":[],"mappings":"AAIA,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,MAA6B,EAC7B,UAAkB,EAClB,UAA6B,EAC7B,MAAoB;IAEpB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC;YAClC,UAAU;YACV,SAAS,EAAE,UAAU;YACrB,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;SAC5C,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,sBAAsB,EAAE,CAAC;IAClC,CAAC;AACH,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAClD,MAA6B,EAC7B,UAAkB,EAClB,UAA6B,EAC7B,MAAoB;IAEpB,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IACrF,OAAO,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,EAAE,CAAC;AACtF,CAAC;AAED,8EAA8E;AAC9E,SAAS,sBAAsB;IAC7B,OAAO;QACL,EAAE,EAAE,KAAK;QACT,WAAW,EAAE;YACX;gBACE,QAAQ,EAAE,OAAO;gBACjB,IAAI,EAAE,yBAAyB;gBAC/B,OAAO,EAAE,mDAAmD;aAC7D;SACF;KACF,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,sBAAsB,CAAC,YAAoB,EAAE,MAAoB;IAC/E,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;IAC7F,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;YAC3B,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7B,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,YAAY,CAAC,CAAC;QACjB,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,UAAU,CAAC,MAAmB;IACrC,OAAO,MAAM,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;AACnG,CAAC","sourcesContent":["import type { InfraResult } from '@ankhorage/contracts/infra';\n\nimport type { MinikubeCommandResult, MinikubeCommandRunner } from '../../../types/minikubeRuntime';\n\n/** Run one command, retaining exit status for state-oriented Minikube commands. */\nexport async function runMinikubeCommandAsync(\n runner: MinikubeCommandRunner,\n executable: string,\n arguments_: readonly string[],\n signal?: AbortSignal,\n): Promise<InfraResult<MinikubeCommandResult>> {\n try {\n const value = await runner.runAsync({\n executable,\n arguments: arguments_,\n ...(signal === undefined ? {} : { signal }),\n });\n return { ok: true, value, diagnostics: [] };\n } catch {\n return minikubeCommandFailure();\n }\n}\n\n/** Run one command that must exit successfully. */\nexport async function runCheckedMinikubeCommandAsync(\n runner: MinikubeCommandRunner,\n executable: string,\n arguments_: readonly string[],\n signal?: AbortSignal,\n): Promise<InfraResult<MinikubeCommandResult>> {\n const result = await runMinikubeCommandAsync(runner, executable, arguments_, signal);\n return result.ok && result.value.exitCode === 0 ? result : minikubeCommandFailure();\n}\n\n/** Return a provider-safe command failure that excludes stdout and stderr. */\nfunction minikubeCommandFailure(): InfraResult<never> {\n return {\n ok: false,\n diagnostics: [\n {\n severity: 'error',\n code: 'minikube-command-failed',\n message: 'A required Minikube control-plane command failed.',\n },\n ],\n };\n}\n\n/** Wait between status observations and abort promptly when requested. */\nexport function delayMinikubePollAsync(milliseconds: number, signal?: AbortSignal): Promise<void> {\n if (signal === undefined) return new Promise((resolve) => setTimeout(resolve, milliseconds));\n return new Promise((resolve, reject) => {\n if (signal.aborted) {\n reject(abortError(signal));\n return;\n }\n const onAbort = () => {\n clearTimeout(timeout);\n reject(abortError(signal));\n };\n const timeout = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, milliseconds);\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nfunction abortError(signal: AbortSignal): Error {\n return signal.reason instanceof Error ? signal.reason : new Error('Minikube operation aborted.');\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import type { InfraResult, InfraWorkloadSpec } from '@ankhorage/contracts/infra';
2
+ import type { MinikubeClusterIdentity, MinikubeEndpointOutput } from '../../../types/minikubeRuntime';
3
+ /*** Resolve deterministic reachable URLs for ports exposed by the owned Minikube profile. */
4
+ export declare function readMinikubeEndpoints(identity: MinikubeClusterIdentity, workloads: readonly InfraWorkloadSpec[], publicBaseUrl?: string): InfraResult<readonly MinikubeEndpointOutput[]>;
5
+ //# sourceMappingURL=readMinikubeEndpoints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readMinikubeEndpoints.d.ts","sourceRoot":"","sources":["../../../../src/features/cluster-runtime/adapters/readMinikubeEndpoints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEjF,OAAO,KAAK,EACV,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,gCAAgC,CAAC;AAExC,6FAA6F;AAC7F,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,uBAAuB,EACjC,SAAS,EAAE,SAAS,iBAAiB,EAAE,EACvC,aAAa,CAAC,EAAE,MAAM,GACrB,WAAW,CAAC,SAAS,sBAAsB,EAAE,CAAC,CAOhD"}