@tomflow/proflow-platform-cli 0.1.13 → 0.1.15

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 (142) hide show
  1. package/README.md +48 -43
  2. package/dist/deployment/adapter.d.ts +5 -5
  3. package/dist/deployment/adapter.js +2 -1
  4. package/dist/deployment/descriptor.d.ts +2 -3
  5. package/dist/deployment/descriptor.js +2 -3
  6. package/dist/src/binding/production-bindings.d.ts +17 -15
  7. package/dist/src/binding/production-bindings.js +18 -59
  8. package/dist/src/cli.d.ts +7 -9
  9. package/dist/src/cli.js +329 -1237
  10. package/dist/src/contracts.d.ts +4 -97
  11. package/dist/src/discovery/discover.js +0 -1
  12. package/dist/src/docs/aggregate.d.ts +18 -0
  13. package/dist/src/docs/aggregate.js +44 -0
  14. package/dist/src/docs/docs.d.ts +0 -31
  15. package/dist/src/docs/docs.js +0 -61
  16. package/dist/src/docs/index.d.ts +2 -1
  17. package/dist/src/docs/index.js +1 -1
  18. package/dist/src/errors.d.ts +1 -1
  19. package/dist/src/errors.js +0 -18
  20. package/dist/src/graph/graph.d.ts +1 -4
  21. package/dist/src/graph/graph.js +1 -13
  22. package/dist/src/graph/index.d.ts +2 -2
  23. package/dist/src/graph/index.js +1 -1
  24. package/dist/src/index.d.ts +4 -24
  25. package/dist/src/index.js +2 -16
  26. package/dist/src/install/package-manager.d.ts +21 -0
  27. package/dist/src/install/package-manager.js +153 -0
  28. package/dist/src/lifecycle/dispatch.d.ts +0 -30
  29. package/dist/src/lifecycle/dispatch.js +0 -120
  30. package/dist/src/lifecycle/index.d.ts +4 -3
  31. package/dist/src/lifecycle/index.js +2 -2
  32. package/dist/src/lifecycle/thin.d.ts +11 -0
  33. package/dist/src/lifecycle/thin.js +68 -0
  34. package/dist/src/paths.d.ts +0 -14
  35. package/dist/src/paths.js +0 -39
  36. package/dist/src/persistence/config.d.ts +0 -6
  37. package/dist/src/persistence/config.js +0 -14
  38. package/dist/src/persistence/guards.d.ts +0 -6
  39. package/dist/src/persistence/guards.js +0 -114
  40. package/dist/src/persistence/index.d.ts +4 -6
  41. package/dist/src/persistence/index.js +2 -5
  42. package/dist/src/persistence/workspace-metadata.d.ts +7 -0
  43. package/dist/src/persistence/workspace-metadata.js +39 -0
  44. package/dist/src/registry/index.d.ts +1 -1
  45. package/dist/src/registry/index.js +1 -1
  46. package/dist/src/registry/npm-registry.d.ts +0 -14
  47. package/dist/src/registry/npm-registry.js +1 -132
  48. package/package.json +2 -6
  49. package/proflow.module.json +2 -3
  50. package/CHANGELOG.md +0 -79
  51. package/dist/src/apply/apply.d.ts +0 -26
  52. package/dist/src/apply/apply.js +0 -314
  53. package/dist/src/apply/cleanup.d.ts +0 -12
  54. package/dist/src/apply/cleanup.js +0 -37
  55. package/dist/src/apply/current.d.ts +0 -5
  56. package/dist/src/apply/current.js +0 -95
  57. package/dist/src/apply/driver.d.ts +0 -28
  58. package/dist/src/apply/driver.js +0 -239
  59. package/dist/src/apply/execute.d.ts +0 -36
  60. package/dist/src/apply/execute.js +0 -152
  61. package/dist/src/apply/index.d.ts +0 -8
  62. package/dist/src/apply/index.js +0 -4
  63. package/dist/src/apply/reality.d.ts +0 -20
  64. package/dist/src/apply/reality.js +0 -105
  65. package/dist/src/binding/global-binding.d.ts +0 -69
  66. package/dist/src/binding/global-binding.js +0 -349
  67. package/dist/src/doctor/doctor.d.ts +0 -41
  68. package/dist/src/doctor/doctor.js +0 -80
  69. package/dist/src/doctor/index.d.ts +0 -2
  70. package/dist/src/doctor/index.js +0 -1
  71. package/dist/src/install/bootstrap.d.ts +0 -10
  72. package/dist/src/install/bootstrap.js +0 -79
  73. package/dist/src/install/environment.d.ts +0 -30
  74. package/dist/src/install/environment.js +0 -230
  75. package/dist/src/install/index.d.ts +0 -6
  76. package/dist/src/install/index.js +0 -3
  77. package/dist/src/install/install.d.ts +0 -19
  78. package/dist/src/install/install.js +0 -172
  79. package/dist/src/lifecycle/service-process.d.ts +0 -11
  80. package/dist/src/lifecycle/service-process.js +0 -356
  81. package/dist/src/manifest/index.d.ts +0 -2
  82. package/dist/src/manifest/index.js +0 -1
  83. package/dist/src/manifest/manifest.d.ts +0 -61
  84. package/dist/src/manifest/manifest.js +0 -167
  85. package/dist/src/observer/deployment-summary.d.ts +0 -31
  86. package/dist/src/observer/deployment-summary.js +0 -34
  87. package/dist/src/persistence/atomic.d.ts +0 -2
  88. package/dist/src/persistence/atomic.js +0 -16
  89. package/dist/src/persistence/effective-config.d.ts +0 -3
  90. package/dist/src/persistence/effective-config.js +0 -20
  91. package/dist/src/persistence/generated.d.ts +0 -2
  92. package/dist/src/persistence/generated.js +0 -4
  93. package/dist/src/persistence/plans.d.ts +0 -5
  94. package/dist/src/persistence/plans.js +0 -34
  95. package/dist/src/persistence/state.d.ts +0 -7
  96. package/dist/src/persistence/state.js +0 -34
  97. package/dist/src/persistence/verification.d.ts +0 -5
  98. package/dist/src/persistence/verification.js +0 -47
  99. package/dist/src/planner/assemble.d.ts +0 -16
  100. package/dist/src/planner/assemble.js +0 -107
  101. package/dist/src/planner/check.d.ts +0 -20
  102. package/dist/src/planner/check.js +0 -107
  103. package/dist/src/planner/fingerprint.d.ts +0 -12
  104. package/dist/src/planner/fingerprint.js +0 -164
  105. package/dist/src/planner/index.d.ts +0 -13
  106. package/dist/src/planner/index.js +0 -7
  107. package/dist/src/planner/plan.d.ts +0 -15
  108. package/dist/src/planner/plan.js +0 -144
  109. package/dist/src/planner/repair.d.ts +0 -28
  110. package/dist/src/planner/repair.js +0 -131
  111. package/dist/src/planner/stale.d.ts +0 -7
  112. package/dist/src/planner/stale.js +0 -23
  113. package/dist/src/planner/steps.d.ts +0 -37
  114. package/dist/src/planner/steps.js +0 -165
  115. package/dist/src/planner/target-catalog.d.ts +0 -13
  116. package/dist/src/planner/target-catalog.js +0 -48
  117. package/dist/src/planner/upgrade.d.ts +0 -18
  118. package/dist/src/planner/upgrade.js +0 -114
  119. package/dist/src/preflight/config.d.ts +0 -11
  120. package/dist/src/preflight/config.js +0 -88
  121. package/dist/src/preflight/findings.d.ts +0 -26
  122. package/dist/src/preflight/findings.js +0 -1
  123. package/dist/src/preflight/index.d.ts +0 -7
  124. package/dist/src/preflight/index.js +0 -3
  125. package/dist/src/preflight/preflight.d.ts +0 -10
  126. package/dist/src/preflight/preflight.js +0 -190
  127. package/dist/src/preflight/requirements.d.ts +0 -11
  128. package/dist/src/preflight/requirements.js +0 -231
  129. package/dist/src/ready/index.d.ts +0 -2
  130. package/dist/src/ready/index.js +0 -1
  131. package/dist/src/ready/ready.d.ts +0 -40
  132. package/dist/src/ready/ready.js +0 -201
  133. package/dist/src/security/index.d.ts +0 -3
  134. package/dist/src/security/index.js +0 -2
  135. package/dist/src/security/lock.d.ts +0 -9
  136. package/dist/src/security/lock.js +0 -127
  137. package/dist/src/security/redact.d.ts +0 -6
  138. package/dist/src/security/redact.js +0 -48
  139. package/dist/src/verification/index.d.ts +0 -2
  140. package/dist/src/verification/index.js +0 -1
  141. package/dist/src/verification/verify.d.ts +0 -33
  142. package/dist/src/verification/verify.js +0 -114
@@ -1,95 +0,0 @@
1
- import { parseModuleDescriptor, } from "@tomflow/proflow-module-contract";
2
- import { discoverModules } from "../discovery/index.js";
3
- import { doctorModules } from "../doctor/index.js";
4
- import { mergeEffectiveConfig } from "../persistence/effective-config.js";
5
- import { diagnoseRepair } from "../planner/repair.js";
6
- function moduleSourceOf(module) {
7
- if (module.source.type === "registry") {
8
- throw new Error(`registry bootstrap target ${module.packageName} has no local descriptor`);
9
- }
10
- const source = {
11
- type: module.source.type,
12
- packageName: module.packageName,
13
- };
14
- if (module.source.path !== undefined)
15
- source.path = module.source.path;
16
- return source;
17
- }
18
- async function loadDescriptors(catalog, modules) {
19
- const descriptors = [];
20
- for (const module of modules) {
21
- const raw = await catalog.loadDescriptor(moduleSourceOf(module));
22
- descriptors.push(parseModuleDescriptor(raw));
23
- }
24
- return descriptors;
25
- }
26
- // Rebuilds a plan's stable current assumptions from the CURRENT module catalog
27
- // and current reality. The old plan's resolvedModules are never reused: modules
28
- // are re-discovered and re-parsed so descriptor drift reaches the staleness
29
- // gate. Upgrade additionally re-discovers current descriptors and reuses the
30
- // plan's frozen target descriptors; repair re-runs doctor for fresh facts.
31
- export async function rebuildCurrentAssumptions(catalog, plan, paths) {
32
- if ((plan.intent === "install" || plan.intent === "upgrade") &&
33
- plan.resolvedModules.every((module) => module.source.type === "registry")) {
34
- return {
35
- intent: plan.intent,
36
- modules: plan.resolvedModules,
37
- targets: plan.moduleTargets,
38
- };
39
- }
40
- const discovered = await discoverModules({ catalog });
41
- const byRef = new Map(discovered.map((module) => [module.moduleRef, module]));
42
- const modules = [];
43
- for (const target of plan.moduleTargets) {
44
- const module = byRef.get(target.moduleRef);
45
- if (module !== undefined)
46
- modules.push(module);
47
- }
48
- if (plan.intent === "upgrade") {
49
- const currentDescriptors = await loadDescriptors(catalog, modules);
50
- const config = await mergeEffectiveConfig(paths, modules, {});
51
- if (plan.targetDescriptors === undefined)
52
- return {
53
- intent: plan.intent,
54
- modules,
55
- targets: plan.moduleTargets,
56
- config,
57
- };
58
- return {
59
- intent: plan.intent,
60
- modules,
61
- targets: plan.moduleTargets,
62
- config,
63
- currentDescriptors,
64
- targetDescriptors: plan.targetDescriptors,
65
- };
66
- }
67
- if (plan.intent === "repair") {
68
- const diagnosis = diagnoseRepair(await doctorModules(catalog, modules));
69
- return {
70
- intent: plan.intent,
71
- modules,
72
- targets: plan.moduleTargets,
73
- facts: diagnosis.facts,
74
- };
75
- }
76
- if (plan.intent === "uninstall") {
77
- // A persisted uninstall plan does not store uninstallScope. Recover the only
78
- // legal scope from its module set for the staleness re-plan: any core module
79
- // can only have entered the plan through whole-instance uninstall.
80
- const uninstallScope = plan.resolvedModules.some((module) => module.installClass === "core")
81
- ? "platform-instance"
82
- : "module";
83
- return {
84
- intent: plan.intent,
85
- modules,
86
- targets: plan.moduleTargets,
87
- uninstallScope,
88
- };
89
- }
90
- return {
91
- intent: plan.intent,
92
- modules,
93
- targets: plan.moduleTargets,
94
- };
95
- }
@@ -1,28 +0,0 @@
1
- import type { ResolvedModule } from "../contracts.ts";
2
- import { type PackageCommandRunner } from "../install/package-manager.ts";
3
- /**
4
- * Package-level installation seam. Apply never invokes an arbitrary shell: a
5
- * package step is satisfied or mutated only through this injected driver. The
6
- * production driver executes a fixed package-manager binary with argv arrays.
7
- */
8
- export interface PackageManagerDriver {
9
- observeInstalledVersion(module: ResolvedModule): Promise<string | undefined>;
10
- install(module: ResolvedModule): Promise<void>;
11
- upgrade(module: ResolvedModule): Promise<void>;
12
- remove(module: ResolvedModule): Promise<void>;
13
- }
14
- /**
15
- * Monorepo/test seam retained for source-resident planning. Production CLI must
16
- * inject createWorkspacePackageManagerDriver(); it must never rely on this
17
- * no-op driver to claim a product Workspace package mutation succeeded.
18
- */
19
- export declare function workspaceResidentDriver(): PackageManagerDriver;
20
- export declare function cleanupWorkspacePackageManagerArtifacts(options: {
21
- workspaceRoot: string;
22
- removedModules: readonly ResolvedModule[];
23
- }): Promise<void>;
24
- export declare function createWorkspacePackageManagerDriver(options: {
25
- workspaceRoot: string;
26
- runner?: PackageCommandRunner;
27
- executableAvailable?: (command: string) => boolean;
28
- }): PackageManagerDriver;
@@ -1,239 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
- import { PlatformError } from "../errors.js";
4
- import { findExecutable, readWorkspacePackageManagerSelection, systemPackageCommandRunner, } from "../install/package-manager.js";
5
- import { atomicWrite } from "../paths.js";
6
- /**
7
- * Monorepo/test seam retained for source-resident planning. Production CLI must
8
- * inject createWorkspacePackageManagerDriver(); it must never rely on this
9
- * no-op driver to claim a product Workspace package mutation succeeded.
10
- */
11
- export function workspaceResidentDriver() {
12
- return {
13
- async observeInstalledVersion(module) {
14
- return module.moduleVersion;
15
- },
16
- async install() { },
17
- async upgrade() { },
18
- async remove() { },
19
- };
20
- }
21
- export async function cleanupWorkspacePackageManagerArtifacts(options) {
22
- const manager = await readWorkspacePackageManagerSelection(options.workspaceRoot);
23
- if (manager.name !== "pnpm")
24
- return;
25
- const removedPackageNames = new Set(options.removedModules.map((module) => module.packageName));
26
- await cleanupPnpmReleaseAgeExcludes(options.workspaceRoot, removedPackageNames);
27
- await normalizeEmptyPnpmRootImporter(options.workspaceRoot);
28
- }
29
- export function createWorkspacePackageManagerDriver(options) {
30
- const runner = options.runner ?? systemPackageCommandRunner();
31
- const executableAvailable = options.executableAvailable ?? findExecutable;
32
- return {
33
- observeInstalledVersion: (module) => observeInstalledVersion(options.workspaceRoot, module.packageName),
34
- install: async (module) => {
35
- await ensureWorkspacePackageJson(options.workspaceRoot);
36
- const manager = await requirePackageManager(options.workspaceRoot, executableAvailable);
37
- await mutatePackage(runner, manager, options.workspaceRoot, "install", `${module.packageName}@${module.moduleVersion}`);
38
- },
39
- upgrade: async (module) => {
40
- await ensureWorkspacePackageJson(options.workspaceRoot);
41
- const manager = await requirePackageManager(options.workspaceRoot, executableAvailable);
42
- await mutatePackage(runner, manager, options.workspaceRoot, "upgrade", `${module.packageName}@${module.moduleVersion}`);
43
- },
44
- remove: async (module) => {
45
- const manager = await requirePackageManager(options.workspaceRoot, executableAvailable);
46
- await mutatePackage(runner, manager, options.workspaceRoot, "remove", module.packageName);
47
- },
48
- };
49
- }
50
- async function mutatePackage(runner, manager, workspaceRoot, operation, packageSpec) {
51
- const args = await packageManagerArgs(runner, manager, workspaceRoot, operation, packageSpec);
52
- try {
53
- await runner.run(manager.name, args, workspaceRoot);
54
- }
55
- catch (error) {
56
- throw new PlatformError(operation === "upgrade" ? "UPGRADE_FAILED" : "APPLY_FAILED", `${manager.name} ${operation} failed for ${packageSpec}: ${errorMessage(error)}`);
57
- }
58
- }
59
- async function packageManagerArgs(runner, manager, workspaceRoot, operation, packageSpec) {
60
- if (manager.name === "pnpm") {
61
- return operation === "remove"
62
- ? ["--config.ignore-scripts=true", "remove", packageSpec]
63
- : ["add", "--save-exact", "--ignore-scripts", packageSpec];
64
- }
65
- if (manager.name === "npm") {
66
- return operation === "remove"
67
- ? ["uninstall", "--ignore-scripts", packageSpec]
68
- : ["install", "--save-exact", "--ignore-scripts", packageSpec];
69
- }
70
- const major = await yarnMajorVersion(runner, manager, workspaceRoot);
71
- if (major <= 1) {
72
- return operation === "remove"
73
- ? ["remove", "--ignore-scripts", packageSpec]
74
- : ["add", "--exact", "--ignore-scripts", packageSpec];
75
- }
76
- return operation === "remove"
77
- ? ["remove", "--mode=skip-build", packageSpec]
78
- : ["add", "--exact", "--mode=skip-build", packageSpec];
79
- }
80
- async function yarnMajorVersion(runner, manager, workspaceRoot) {
81
- const declaredVersion = declaredPackageManagerVersion(manager.declared);
82
- const value = declaredVersion ??
83
- (await runner.run("yarn", ["--version"], workspaceRoot)).trim();
84
- const major = Number.parseInt(value.split(".")[0] ?? "", 10);
85
- if (!Number.isInteger(major) || major < 1) {
86
- throw new PlatformError("PACKAGE_MANAGER_UNAVAILABLE", `cannot determine a supported Yarn major version from ${value || "<empty>"}`);
87
- }
88
- return major;
89
- }
90
- function declaredPackageManagerVersion(declared) {
91
- if (declared === undefined)
92
- return undefined;
93
- const separator = declared.lastIndexOf("@");
94
- return separator > 0 ? declared.slice(separator + 1) : undefined;
95
- }
96
- async function requirePackageManager(workspaceRoot, executableAvailable) {
97
- const manager = await readWorkspacePackageManagerSelection(workspaceRoot);
98
- if (!executableAvailable(manager.name)) {
99
- throw new PlatformError("PACKAGE_MANAGER_UNAVAILABLE", `workspace package manager ${manager.name} is not available on PATH`);
100
- }
101
- return manager;
102
- }
103
- async function ensureWorkspacePackageJson(workspaceRoot) {
104
- const path = join(workspaceRoot, "package.json");
105
- try {
106
- const raw = await readFile(path, "utf8");
107
- const parsed = JSON.parse(raw);
108
- if (typeof parsed !== "object" ||
109
- parsed === null ||
110
- Array.isArray(parsed)) {
111
- throw new Error("package.json root must be an object");
112
- }
113
- return;
114
- }
115
- catch (error) {
116
- if (!isMissingFile(error)) {
117
- throw new PlatformError("APPLY_FAILED", `workspace package.json is invalid: ${errorMessage(error)}`);
118
- }
119
- }
120
- await atomicWrite(path, `${JSON.stringify({ private: true }, null, 2)}\n`);
121
- }
122
- async function observeInstalledVersion(workspaceRoot, packageName) {
123
- const manifest = await readWorkspaceManifest(workspaceRoot);
124
- if (manifest === undefined ||
125
- (!hasOwn(manifest.dependencies, packageName) &&
126
- !hasOwn(manifest.devDependencies, packageName))) {
127
- return undefined;
128
- }
129
- try {
130
- const raw = await readFile(join(workspaceRoot, "node_modules", ...packageName.split("/"), "package.json"), "utf8");
131
- const parsed = JSON.parse(raw);
132
- if (typeof parsed === "object" &&
133
- parsed !== null &&
134
- !Array.isArray(parsed) &&
135
- Reflect.get(parsed, "name") === packageName &&
136
- typeof Reflect.get(parsed, "version") === "string") {
137
- return Reflect.get(parsed, "version");
138
- }
139
- return undefined;
140
- }
141
- catch {
142
- return undefined;
143
- }
144
- }
145
- async function readWorkspaceManifest(workspaceRoot) {
146
- try {
147
- const raw = await readFile(join(workspaceRoot, "package.json"), "utf8");
148
- const parsed = JSON.parse(raw);
149
- return typeof parsed === "object" &&
150
- parsed !== null &&
151
- !Array.isArray(parsed)
152
- ? parsed
153
- : undefined;
154
- }
155
- catch {
156
- return undefined;
157
- }
158
- }
159
- async function cleanupPnpmReleaseAgeExcludes(workspaceRoot, removedPackageNames) {
160
- const path = join(workspaceRoot, "pnpm-workspace.yaml");
161
- let raw;
162
- try {
163
- raw = await readFile(path, "utf8");
164
- }
165
- catch (error) {
166
- if (isMissingFile(error))
167
- return;
168
- throw error;
169
- }
170
- const lines = raw.split("\n");
171
- const keyIndex = lines.indexOf("minimumReleaseAgeExclude:");
172
- if (keyIndex < 0)
173
- return;
174
- let endIndex = keyIndex + 1;
175
- while (endIndex < lines.length &&
176
- (lines[endIndex]?.trim() === "" || /^\s/.test(lines[endIndex] ?? ""))) {
177
- endIndex += 1;
178
- }
179
- const retained = lines.slice(keyIndex + 1, endIndex).filter((line) => {
180
- const match = /^\s*-\s+(.+?)\s*$/.exec(line);
181
- if (match === null)
182
- return true;
183
- const value = stripYamlQuotes(match[1] ?? "");
184
- for (const packageName of removedPackageNames) {
185
- if (value === packageName || value.startsWith(`${packageName}@`))
186
- return false;
187
- }
188
- return true;
189
- });
190
- const hasListItem = retained.some((line) => /^\s*-\s+/.test(line));
191
- const replacement = hasListItem ? [lines[keyIndex] ?? "", ...retained] : [];
192
- let next = [
193
- ...lines.slice(0, keyIndex),
194
- ...replacement,
195
- ...lines.slice(endIndex),
196
- ].join("\n");
197
- if (raw.endsWith("\n") && !next.endsWith("\n"))
198
- next += "\n";
199
- if (next !== raw)
200
- await atomicWrite(path, next);
201
- }
202
- async function normalizeEmptyPnpmRootImporter(workspaceRoot) {
203
- const path = join(workspaceRoot, "pnpm-lock.yaml");
204
- let raw;
205
- try {
206
- raw = await readFile(path, "utf8");
207
- }
208
- catch (error) {
209
- if (isMissingFile(error))
210
- return;
211
- throw error;
212
- }
213
- const next = raw.replace("\nimporters:\n\n .: {}\n", "\nimporters:\n .: {}\n");
214
- if (next !== raw)
215
- await atomicWrite(path, next);
216
- }
217
- function stripYamlQuotes(value) {
218
- if ((value.startsWith("'") && value.endsWith("'")) ||
219
- (value.startsWith('"') && value.endsWith('"'))) {
220
- return value.slice(1, -1);
221
- }
222
- return value;
223
- }
224
- function hasOwn(record, key) {
225
- return record !== undefined && Object.hasOwn(record, key);
226
- }
227
- function isMissingFile(error) {
228
- return (typeof error === "object" &&
229
- error !== null &&
230
- Reflect.get(error, "code") === "ENOENT");
231
- }
232
- function errorMessage(error) {
233
- if (typeof error === "object" && error !== null) {
234
- const stderr = Reflect.get(error, "stderr");
235
- if (typeof stderr === "string" && stderr.trim() !== "")
236
- return stderr.trim();
237
- }
238
- return error instanceof Error ? error.message : String(error);
239
- }
@@ -1,36 +0,0 @@
1
- import type { HumanAction } from "@tomflow/proflow-module-contract";
2
- import type { DeploymentPlan, DeploymentStep } from "../contracts.ts";
3
- import type { ModuleCatalog } from "../modules.ts";
4
- import type { WorkspacePaths } from "../paths.ts";
5
- import type { PackageManagerDriver } from "./driver.ts";
6
- export interface ExecuteDeps {
7
- paths: WorkspacePaths;
8
- catalog: ModuleCatalog;
9
- driver: PackageManagerDriver;
10
- }
11
- /**
12
- * Structured result of executing one non-human step. A lifecycle adapter's
13
- * `ModuleOperationResult` is preserved verbatim: ACTION_REQUIRED / BLOCKED /
14
- * FAILED are returned as values, never collapsed into a thrown APPLY_FAILED.
15
- * Only genuine boundary violations (missing module, unsupported strategy,
16
- * malformed adapter result) still throw.
17
- */
18
- export type ExecuteStepOutcome = {
19
- kind: "SUCCEEDED";
20
- } | {
21
- kind: "ACTION_REQUIRED";
22
- actionRequired: HumanAction;
23
- } | {
24
- kind: "BLOCKED";
25
- reason: string;
26
- } | {
27
- kind: "FAILED";
28
- reason: string;
29
- };
30
- /**
31
- * Executes a single non-human step by kind + execute strategy, returning a
32
- * structured outcome instead of throwing for ACTION_REQUIRED / BLOCKED / FAILED
33
- * lifecycle results. Package/config mutations still throw on genuine driver or
34
- * boundary errors; those are not lifecycle outcomes and must not be swallowed.
35
- */
36
- export declare function executeStep(deps: ExecuteDeps, step: DeploymentStep, plan: DeploymentPlan): Promise<ExecuteStepOutcome>;
@@ -1,152 +0,0 @@
1
- import { PlatformError } from "../errors.js";
2
- import { dispatchLifecycle } from "../lifecycle/index.js";
3
- import { materializeConfig } from "../persistence/index.js";
4
- import { ExecuteStrategy } from "../planner/index.js";
5
- import { cleanupRemovableFilesystemEffects } from "./cleanup.js";
6
- function moduleOf(plan, step) {
7
- return plan.resolvedModules.find((module) => module.moduleRef === step.moduleRef);
8
- }
9
- function moduleSourceForMaterialization(module) {
10
- if (module.source.type === "registry") {
11
- throw new PlatformError("APPLY_FAILED", `registry bootstrap target ${module.packageName} has no local config materializer`);
12
- }
13
- return {
14
- type: module.source.type,
15
- packageName: module.packageName,
16
- ...(module.source.path === undefined ? {} : { path: module.source.path }),
17
- };
18
- }
19
- async function materializeModuleOwnedConfig(deps, module, config) {
20
- const namespace = await deps.catalog.loadAdapter(moduleSourceForMaterialization(module));
21
- if (typeof namespace !== "object" || namespace === null)
22
- return;
23
- const materializer = Reflect.get(namespace, "materializeProductionConfig");
24
- if (typeof materializer !== "function")
25
- return;
26
- await materializer({
27
- moduleRef: module.moduleRef,
28
- config: config.values,
29
- workspaceRoot: deps.paths.root,
30
- });
31
- }
32
- function configForStep(plan, step, module) {
33
- const target = plan.moduleTargets.find((entry) => entry.moduleRef === step.moduleRef);
34
- if (target?.config === undefined)
35
- return undefined;
36
- const secretRefs = module.configSlots
37
- .filter((slot) => slot.type === "secretRef")
38
- .map((slot) => slot.key);
39
- return {
40
- moduleRef: step.moduleRef,
41
- values: target.config,
42
- secretRefs,
43
- };
44
- }
45
- function lifecyclePrimitive(step) {
46
- switch (step.executeStrategy) {
47
- case ExecuteStrategy.lifecycleStart:
48
- return "start";
49
- case ExecuteStrategy.lifecycleStop:
50
- return "stop";
51
- case ExecuteStrategy.lifecycleRestart:
52
- return "restart";
53
- case ExecuteStrategy.lifecycleUninstall:
54
- return "uninstall";
55
- case ExecuteStrategy.lifecycleMigrate:
56
- return "migrate";
57
- default:
58
- throw new PlatformError("APPLY_FAILED", `unsupported lifecycle strategy ${step.executeStrategy ?? "<none>"}`);
59
- }
60
- }
61
- function externalResourcePrimitive(step) {
62
- if (step.executeStrategy === ExecuteStrategy.externalResourceConfigure) {
63
- return "start";
64
- }
65
- throw new PlatformError("APPLY_FAILED", `unsupported external-resource strategy ${step.executeStrategy ?? "<none>"}`);
66
- }
67
- function requiredActionRequired(result) {
68
- const actionRequired = result.actionRequired;
69
- if (actionRequired === undefined) {
70
- throw new PlatformError("APPLY_FAILED", `module ${result.moduleRef} reported ACTION_REQUIRED without a recoverable action`);
71
- }
72
- return actionRequired;
73
- }
74
- function operationOutcome(result) {
75
- switch (result.status) {
76
- case "SUCCEEDED":
77
- return { kind: "SUCCEEDED" };
78
- case "ACTION_REQUIRED":
79
- return {
80
- kind: "ACTION_REQUIRED",
81
- actionRequired: requiredActionRequired(result),
82
- };
83
- case "BLOCKED":
84
- return {
85
- kind: "BLOCKED",
86
- reason: `module ${result.moduleRef} is blocked`,
87
- };
88
- case "FAILED":
89
- return {
90
- kind: "FAILED",
91
- reason: result.error?.message ?? `module ${result.moduleRef} failed`,
92
- };
93
- }
94
- }
95
- /**
96
- * Executes a single non-human step by kind + execute strategy, returning a
97
- * structured outcome instead of throwing for ACTION_REQUIRED / BLOCKED / FAILED
98
- * lifecycle results. Package/config mutations still throw on genuine driver or
99
- * boundary errors; those are not lifecycle outcomes and must not be swallowed.
100
- */
101
- export async function executeStep(deps, step, plan) {
102
- const module = moduleOf(plan, step);
103
- if (module === undefined) {
104
- throw new PlatformError("APPLY_FAILED", `module ${step.moduleRef} is not in the plan`);
105
- }
106
- switch (step.kind) {
107
- case "package": {
108
- if (step.executeStrategy === ExecuteStrategy.packageRemove) {
109
- await deps.driver.remove(module);
110
- }
111
- else if (step.executeStrategy === ExecuteStrategy.packageUpgrade) {
112
- await deps.driver.upgrade(module);
113
- }
114
- else {
115
- await deps.driver.install(module);
116
- }
117
- return { kind: "SUCCEEDED" };
118
- }
119
- case "config": {
120
- const config = configForStep(plan, step, module);
121
- if (config === undefined) {
122
- throw new PlatformError("APPLY_FAILED", `module ${step.moduleRef} has no config target to materialize`);
123
- }
124
- // The Platform-owned public config is authoritative apply reality. Do not
125
- // commit it until the module-owned materializer has accepted the target;
126
- // otherwise a failed materializer can leave a false-satisfied config step
127
- // that a same-plan resume would incorrectly SKIP.
128
- await materializeModuleOwnedConfig(deps, module, config);
129
- await materializeConfig(deps.paths, config);
130
- return { kind: "SUCCEEDED" };
131
- }
132
- case "lifecycle": {
133
- const primitive = lifecyclePrimitive(step);
134
- const dispatched = await dispatchLifecycle(deps.catalog, module, primitive);
135
- const operation = operationOutcome(dispatched.result);
136
- if (primitive === "uninstall" && operation.kind === "SUCCEEDED") {
137
- await cleanupRemovableFilesystemEffects({
138
- workspaceRoot: deps.paths.root,
139
- effects: module.effects,
140
- });
141
- }
142
- return operation;
143
- }
144
- case "external-resource": {
145
- const primitive = externalResourcePrimitive(step);
146
- const dispatched = await dispatchLifecycle(deps.catalog, module, primitive);
147
- return operationOutcome(dispatched.result);
148
- }
149
- case "human":
150
- throw new PlatformError("APPLY_FAILED", `human step ${step.stepRef} must be routed to ACTION_REQUIRED, not executed`);
151
- }
152
- }
@@ -1,8 +0,0 @@
1
- export type { ApplyContext } from "./apply.ts";
2
- export { applyPlan } from "./apply.ts";
3
- export type { PackageManagerDriver } from "./driver.ts";
4
- export { createWorkspacePackageManagerDriver } from "./driver.ts";
5
- export type { ExecuteDeps, ExecuteStepOutcome } from "./execute.ts";
6
- export { executeStep } from "./execute.ts";
7
- export type { RealityObserver, RealityObserverDeps } from "./reality.ts";
8
- export { createRealityObserver } from "./reality.ts";
@@ -1,4 +0,0 @@
1
- export { applyPlan } from "./apply.js";
2
- export { createWorkspacePackageManagerDriver } from "./driver.js";
3
- export { executeStep } from "./execute.js";
4
- export { createRealityObserver } from "./reality.js";
@@ -1,20 +0,0 @@
1
- import type { DeploymentPlan, DeploymentStep } from "../contracts.ts";
2
- import type { ModuleCatalog } from "../modules.ts";
3
- import type { WorkspacePaths } from "../paths.ts";
4
- import type { StepReality } from "../planner/index.ts";
5
- import type { PackageManagerDriver } from "./driver.ts";
6
- /**
7
- * Observes the current reality of a single step. The apply loop consults this
8
- * before every decision so that persisted history can never impersonate current
9
- * reality; a step that is no longer satisfied is re-executed, never faked as
10
- * skipped.
11
- */
12
- export interface RealityObserver {
13
- observe(step: DeploymentStep, plan: DeploymentPlan): Promise<StepReality | undefined>;
14
- }
15
- export interface RealityObserverDeps {
16
- paths: WorkspacePaths;
17
- catalog: ModuleCatalog;
18
- driver: PackageManagerDriver;
19
- }
20
- export declare function createRealityObserver(deps: RealityObserverDeps): RealityObserver;