@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.
- package/README.md +48 -43
- package/dist/deployment/adapter.d.ts +5 -5
- package/dist/deployment/adapter.js +2 -1
- package/dist/deployment/descriptor.d.ts +2 -3
- package/dist/deployment/descriptor.js +2 -3
- package/dist/src/binding/production-bindings.d.ts +17 -15
- package/dist/src/binding/production-bindings.js +18 -59
- package/dist/src/cli.d.ts +7 -9
- package/dist/src/cli.js +329 -1237
- package/dist/src/contracts.d.ts +4 -97
- package/dist/src/discovery/discover.js +0 -1
- package/dist/src/docs/aggregate.d.ts +18 -0
- package/dist/src/docs/aggregate.js +44 -0
- package/dist/src/docs/docs.d.ts +0 -31
- package/dist/src/docs/docs.js +0 -61
- package/dist/src/docs/index.d.ts +2 -1
- package/dist/src/docs/index.js +1 -1
- package/dist/src/errors.d.ts +1 -1
- package/dist/src/errors.js +0 -18
- package/dist/src/graph/graph.d.ts +1 -4
- package/dist/src/graph/graph.js +1 -13
- package/dist/src/graph/index.d.ts +2 -2
- package/dist/src/graph/index.js +1 -1
- package/dist/src/index.d.ts +4 -24
- package/dist/src/index.js +2 -16
- package/dist/src/install/package-manager.d.ts +21 -0
- package/dist/src/install/package-manager.js +153 -0
- package/dist/src/lifecycle/dispatch.d.ts +0 -30
- package/dist/src/lifecycle/dispatch.js +0 -120
- package/dist/src/lifecycle/index.d.ts +4 -3
- package/dist/src/lifecycle/index.js +2 -2
- package/dist/src/lifecycle/thin.d.ts +11 -0
- package/dist/src/lifecycle/thin.js +68 -0
- package/dist/src/paths.d.ts +0 -14
- package/dist/src/paths.js +0 -39
- package/dist/src/persistence/config.d.ts +0 -6
- package/dist/src/persistence/config.js +0 -14
- package/dist/src/persistence/guards.d.ts +0 -6
- package/dist/src/persistence/guards.js +0 -114
- package/dist/src/persistence/index.d.ts +4 -6
- package/dist/src/persistence/index.js +2 -5
- package/dist/src/persistence/workspace-metadata.d.ts +7 -0
- package/dist/src/persistence/workspace-metadata.js +39 -0
- package/dist/src/registry/index.d.ts +1 -1
- package/dist/src/registry/index.js +1 -1
- package/dist/src/registry/npm-registry.d.ts +0 -14
- package/dist/src/registry/npm-registry.js +1 -132
- package/package.json +2 -6
- package/proflow.module.json +2 -3
- package/CHANGELOG.md +0 -79
- package/dist/src/apply/apply.d.ts +0 -26
- package/dist/src/apply/apply.js +0 -314
- package/dist/src/apply/cleanup.d.ts +0 -12
- package/dist/src/apply/cleanup.js +0 -37
- package/dist/src/apply/current.d.ts +0 -5
- package/dist/src/apply/current.js +0 -95
- package/dist/src/apply/driver.d.ts +0 -28
- package/dist/src/apply/driver.js +0 -239
- package/dist/src/apply/execute.d.ts +0 -36
- package/dist/src/apply/execute.js +0 -152
- package/dist/src/apply/index.d.ts +0 -8
- package/dist/src/apply/index.js +0 -4
- package/dist/src/apply/reality.d.ts +0 -20
- package/dist/src/apply/reality.js +0 -105
- package/dist/src/binding/global-binding.d.ts +0 -69
- package/dist/src/binding/global-binding.js +0 -349
- package/dist/src/doctor/doctor.d.ts +0 -41
- package/dist/src/doctor/doctor.js +0 -80
- package/dist/src/doctor/index.d.ts +0 -2
- package/dist/src/doctor/index.js +0 -1
- package/dist/src/install/bootstrap.d.ts +0 -10
- package/dist/src/install/bootstrap.js +0 -79
- package/dist/src/install/environment.d.ts +0 -30
- package/dist/src/install/environment.js +0 -230
- package/dist/src/install/index.d.ts +0 -6
- package/dist/src/install/index.js +0 -3
- package/dist/src/install/install.d.ts +0 -19
- package/dist/src/install/install.js +0 -172
- package/dist/src/lifecycle/service-process.d.ts +0 -11
- package/dist/src/lifecycle/service-process.js +0 -356
- package/dist/src/manifest/index.d.ts +0 -2
- package/dist/src/manifest/index.js +0 -1
- package/dist/src/manifest/manifest.d.ts +0 -61
- package/dist/src/manifest/manifest.js +0 -167
- package/dist/src/observer/deployment-summary.d.ts +0 -31
- package/dist/src/observer/deployment-summary.js +0 -34
- package/dist/src/persistence/atomic.d.ts +0 -2
- package/dist/src/persistence/atomic.js +0 -16
- package/dist/src/persistence/effective-config.d.ts +0 -3
- package/dist/src/persistence/effective-config.js +0 -20
- package/dist/src/persistence/generated.d.ts +0 -2
- package/dist/src/persistence/generated.js +0 -4
- package/dist/src/persistence/plans.d.ts +0 -5
- package/dist/src/persistence/plans.js +0 -34
- package/dist/src/persistence/state.d.ts +0 -7
- package/dist/src/persistence/state.js +0 -34
- package/dist/src/persistence/verification.d.ts +0 -5
- package/dist/src/persistence/verification.js +0 -47
- package/dist/src/planner/assemble.d.ts +0 -16
- package/dist/src/planner/assemble.js +0 -107
- package/dist/src/planner/check.d.ts +0 -20
- package/dist/src/planner/check.js +0 -107
- package/dist/src/planner/fingerprint.d.ts +0 -12
- package/dist/src/planner/fingerprint.js +0 -164
- package/dist/src/planner/index.d.ts +0 -13
- package/dist/src/planner/index.js +0 -7
- package/dist/src/planner/plan.d.ts +0 -15
- package/dist/src/planner/plan.js +0 -144
- package/dist/src/planner/repair.d.ts +0 -28
- package/dist/src/planner/repair.js +0 -131
- package/dist/src/planner/stale.d.ts +0 -7
- package/dist/src/planner/stale.js +0 -23
- package/dist/src/planner/steps.d.ts +0 -37
- package/dist/src/planner/steps.js +0 -165
- package/dist/src/planner/target-catalog.d.ts +0 -13
- package/dist/src/planner/target-catalog.js +0 -48
- package/dist/src/planner/upgrade.d.ts +0 -18
- package/dist/src/planner/upgrade.js +0 -114
- package/dist/src/preflight/config.d.ts +0 -11
- package/dist/src/preflight/config.js +0 -88
- package/dist/src/preflight/findings.d.ts +0 -26
- package/dist/src/preflight/findings.js +0 -1
- package/dist/src/preflight/index.d.ts +0 -7
- package/dist/src/preflight/index.js +0 -3
- package/dist/src/preflight/preflight.d.ts +0 -10
- package/dist/src/preflight/preflight.js +0 -190
- package/dist/src/preflight/requirements.d.ts +0 -11
- package/dist/src/preflight/requirements.js +0 -231
- package/dist/src/ready/index.d.ts +0 -2
- package/dist/src/ready/index.js +0 -1
- package/dist/src/ready/ready.d.ts +0 -40
- package/dist/src/ready/ready.js +0 -201
- package/dist/src/security/index.d.ts +0 -3
- package/dist/src/security/index.js +0 -2
- package/dist/src/security/lock.d.ts +0 -9
- package/dist/src/security/lock.js +0 -127
- package/dist/src/security/redact.d.ts +0 -6
- package/dist/src/security/redact.js +0 -48
- package/dist/src/verification/index.d.ts +0 -2
- package/dist/src/verification/index.js +0 -1
- package/dist/src/verification/verify.d.ts +0 -33
- 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;
|
package/dist/src/apply/driver.js
DELETED
|
@@ -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";
|
package/dist/src/apply/index.js
DELETED
|
@@ -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;
|