@tomflow/proflow-platform-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/README.md +37 -0
  2. package/conformance.json +1 -0
  3. package/dist/deployment/adapter.d.ts +57 -0
  4. package/dist/deployment/adapter.js +25 -0
  5. package/dist/deployment/descriptor.d.ts +39 -0
  6. package/dist/deployment/descriptor.js +41 -0
  7. package/dist/src/apply/apply.d.ts +24 -0
  8. package/dist/src/apply/apply.js +271 -0
  9. package/dist/src/apply/cleanup.d.ts +12 -0
  10. package/dist/src/apply/cleanup.js +37 -0
  11. package/dist/src/apply/current.d.ts +4 -0
  12. package/dist/src/apply/current.js +73 -0
  13. package/dist/src/apply/driver.d.ts +23 -0
  14. package/dist/src/apply/driver.js +154 -0
  15. package/dist/src/apply/execute.d.ts +36 -0
  16. package/dist/src/apply/execute.js +124 -0
  17. package/dist/src/apply/index.d.ts +8 -0
  18. package/dist/src/apply/index.js +4 -0
  19. package/dist/src/apply/reality.d.ts +20 -0
  20. package/dist/src/apply/reality.js +93 -0
  21. package/dist/src/binding/production-bindings.d.ts +45 -0
  22. package/dist/src/binding/production-bindings.js +102 -0
  23. package/dist/src/cli.d.ts +12 -0
  24. package/dist/src/cli.js +712 -0
  25. package/dist/src/contracts.d.ts +113 -0
  26. package/dist/src/contracts.js +1 -0
  27. package/dist/src/discovery/catalog.d.ts +10 -0
  28. package/dist/src/discovery/catalog.js +76 -0
  29. package/dist/src/discovery/discover.d.ts +19 -0
  30. package/dist/src/discovery/discover.js +124 -0
  31. package/dist/src/discovery/index.d.ts +5 -0
  32. package/dist/src/discovery/index.js +4 -0
  33. package/dist/src/discovery/installed.d.ts +21 -0
  34. package/dist/src/discovery/installed.js +130 -0
  35. package/dist/src/discovery/workspace.d.ts +10 -0
  36. package/dist/src/discovery/workspace.js +155 -0
  37. package/dist/src/docs/docs.d.ts +47 -0
  38. package/dist/src/docs/docs.js +129 -0
  39. package/dist/src/docs/index.d.ts +1 -0
  40. package/dist/src/docs/index.js +1 -0
  41. package/dist/src/doctor/doctor.d.ts +41 -0
  42. package/dist/src/doctor/doctor.js +80 -0
  43. package/dist/src/doctor/index.d.ts +2 -0
  44. package/dist/src/doctor/index.js +1 -0
  45. package/dist/src/errors.d.ts +6 -0
  46. package/dist/src/errors.js +35 -0
  47. package/dist/src/graph/graph.d.ts +23 -0
  48. package/dist/src/graph/graph.js +132 -0
  49. package/dist/src/graph/index.d.ts +2 -0
  50. package/dist/src/graph/index.js +1 -0
  51. package/dist/src/index.d.ts +28 -0
  52. package/dist/src/index.js +18 -0
  53. package/dist/src/install/bootstrap.d.ts +10 -0
  54. package/dist/src/install/bootstrap.js +79 -0
  55. package/dist/src/install/environment.d.ts +29 -0
  56. package/dist/src/install/environment.js +226 -0
  57. package/dist/src/install/index.d.ts +6 -0
  58. package/dist/src/install/index.js +3 -0
  59. package/dist/src/install/install.d.ts +19 -0
  60. package/dist/src/install/install.js +131 -0
  61. package/dist/src/install/package-manager.d.ts +11 -0
  62. package/dist/src/install/package-manager.js +58 -0
  63. package/dist/src/lifecycle/dispatch.d.ts +47 -0
  64. package/dist/src/lifecycle/dispatch.js +142 -0
  65. package/dist/src/lifecycle/index.d.ts +3 -0
  66. package/dist/src/lifecycle/index.js +2 -0
  67. package/dist/src/lifecycle/service-process.d.ts +11 -0
  68. package/dist/src/lifecycle/service-process.js +326 -0
  69. package/dist/src/manifest/index.d.ts +2 -0
  70. package/dist/src/manifest/index.js +1 -0
  71. package/dist/src/manifest/manifest.d.ts +61 -0
  72. package/dist/src/manifest/manifest.js +160 -0
  73. package/dist/src/modules.d.ts +11 -0
  74. package/dist/src/modules.js +55 -0
  75. package/dist/src/observer/deployment-summary.d.ts +31 -0
  76. package/dist/src/observer/deployment-summary.js +34 -0
  77. package/dist/src/paths.d.ts +21 -0
  78. package/dist/src/paths.js +56 -0
  79. package/dist/src/persistence/atomic.d.ts +2 -0
  80. package/dist/src/persistence/atomic.js +16 -0
  81. package/dist/src/persistence/config.d.ts +12 -0
  82. package/dist/src/persistence/config.js +43 -0
  83. package/dist/src/persistence/generated.d.ts +2 -0
  84. package/dist/src/persistence/generated.js +4 -0
  85. package/dist/src/persistence/guards.d.ts +7 -0
  86. package/dist/src/persistence/guards.js +120 -0
  87. package/dist/src/persistence/index.d.ts +6 -0
  88. package/dist/src/persistence/index.js +5 -0
  89. package/dist/src/persistence/plans.d.ts +5 -0
  90. package/dist/src/persistence/plans.js +34 -0
  91. package/dist/src/persistence/state.d.ts +7 -0
  92. package/dist/src/persistence/state.js +34 -0
  93. package/dist/src/persistence/verification.d.ts +5 -0
  94. package/dist/src/persistence/verification.js +47 -0
  95. package/dist/src/planner/assemble.d.ts +16 -0
  96. package/dist/src/planner/assemble.js +107 -0
  97. package/dist/src/planner/check.d.ts +20 -0
  98. package/dist/src/planner/check.js +96 -0
  99. package/dist/src/planner/fingerprint.d.ts +12 -0
  100. package/dist/src/planner/fingerprint.js +164 -0
  101. package/dist/src/planner/index.d.ts +13 -0
  102. package/dist/src/planner/index.js +7 -0
  103. package/dist/src/planner/plan.d.ts +14 -0
  104. package/dist/src/planner/plan.js +156 -0
  105. package/dist/src/planner/repair.d.ts +28 -0
  106. package/dist/src/planner/repair.js +131 -0
  107. package/dist/src/planner/stale.d.ts +7 -0
  108. package/dist/src/planner/stale.js +23 -0
  109. package/dist/src/planner/steps.d.ts +37 -0
  110. package/dist/src/planner/steps.js +165 -0
  111. package/dist/src/planner/target-catalog.d.ts +13 -0
  112. package/dist/src/planner/target-catalog.js +48 -0
  113. package/dist/src/planner/upgrade.d.ts +18 -0
  114. package/dist/src/planner/upgrade.js +105 -0
  115. package/dist/src/preflight/config.d.ts +10 -0
  116. package/dist/src/preflight/config.js +45 -0
  117. package/dist/src/preflight/findings.d.ts +26 -0
  118. package/dist/src/preflight/findings.js +1 -0
  119. package/dist/src/preflight/index.d.ts +7 -0
  120. package/dist/src/preflight/index.js +3 -0
  121. package/dist/src/preflight/preflight.d.ts +8 -0
  122. package/dist/src/preflight/preflight.js +174 -0
  123. package/dist/src/preflight/requirements.d.ts +11 -0
  124. package/dist/src/preflight/requirements.js +224 -0
  125. package/dist/src/ready/index.d.ts +2 -0
  126. package/dist/src/ready/index.js +1 -0
  127. package/dist/src/ready/ready.d.ts +40 -0
  128. package/dist/src/ready/ready.js +201 -0
  129. package/dist/src/registry/index.d.ts +2 -0
  130. package/dist/src/registry/index.js +1 -0
  131. package/dist/src/registry/npm-registry.d.ts +51 -0
  132. package/dist/src/registry/npm-registry.js +341 -0
  133. package/dist/src/security/index.d.ts +3 -0
  134. package/dist/src/security/index.js +2 -0
  135. package/dist/src/security/lock.d.ts +9 -0
  136. package/dist/src/security/lock.js +89 -0
  137. package/dist/src/security/redact.d.ts +6 -0
  138. package/dist/src/security/redact.js +48 -0
  139. package/dist/src/verification/index.d.ts +2 -0
  140. package/dist/src/verification/index.js +1 -0
  141. package/dist/src/verification/verify.d.ts +33 -0
  142. package/dist/src/verification/verify.js +114 -0
  143. package/package.json +49 -0
  144. package/proflow.module.json +45 -0
@@ -0,0 +1,47 @@
1
+ import type { ModuleDescriptor } from "@tomflow/proflow-module-contract";
2
+ import type { ModuleSource } from "../modules.ts";
3
+ export interface PublishedCommand {
4
+ name: string;
5
+ target: string;
6
+ }
7
+ export interface PublicApiEntry {
8
+ subpath: string;
9
+ target?: string;
10
+ }
11
+ export interface ModuleDocsView {
12
+ moduleRef: string;
13
+ packageName: string;
14
+ moduleVersion: string;
15
+ kind: ModuleDescriptor["kind"];
16
+ installClass: ModuleDescriptor["installClass"];
17
+ identity: ModuleDescriptor["identity"];
18
+ commands: PublishedCommand[];
19
+ publicApiEntries: PublicApiEntry[];
20
+ provides: ModuleDescriptor["provides"];
21
+ requires: ModuleDescriptor["requires"];
22
+ requirements: ModuleDescriptor["requirements"];
23
+ configSlots: ModuleDescriptor["configSlots"];
24
+ lifecycle: ModuleDescriptor["lifecycle"]["supported"];
25
+ verification: ModuleDescriptor["verification"];
26
+ effects: ModuleDescriptor["effects"];
27
+ documentation: ModuleDescriptor["documentation"];
28
+ }
29
+ export interface ModuleDocumentContent {
30
+ moduleRef: string;
31
+ packageName: string;
32
+ documentId: string;
33
+ path: string;
34
+ description?: string;
35
+ content: string;
36
+ }
37
+ export declare function describeModule(input: {
38
+ workspaceRoot: string;
39
+ source: ModuleSource;
40
+ descriptor: ModuleDescriptor;
41
+ }): Promise<ModuleDocsView>;
42
+ export declare function readModuleDocument(input: {
43
+ workspaceRoot: string;
44
+ source: ModuleSource;
45
+ descriptor: ModuleDescriptor;
46
+ documentId: string;
47
+ }): Promise<ModuleDocumentContent>;
@@ -0,0 +1,129 @@
1
+ import { readFile, realpath, stat } from "node:fs/promises";
2
+ import { createRequire } from "node:module";
3
+ import { dirname, join, resolve, sep } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { PlatformError } from "../errors.js";
6
+ function executableName(packageName) {
7
+ return packageName.split("/").pop() ?? packageName;
8
+ }
9
+ function commandsFrom(manifest, packageName) {
10
+ if (typeof manifest.bin === "string") {
11
+ return [{ name: executableName(packageName), target: manifest.bin }];
12
+ }
13
+ if (typeof manifest.bin !== "object" || manifest.bin === null)
14
+ return [];
15
+ return Object.entries(manifest.bin)
16
+ .flatMap(([name, target]) => typeof target === "string" ? [{ name, target }] : [])
17
+ .sort((left, right) => left.name.localeCompare(right.name));
18
+ }
19
+ function publicApiEntriesFrom(manifest) {
20
+ if (typeof manifest.exports === "string") {
21
+ return [{ subpath: ".", target: manifest.exports }];
22
+ }
23
+ if (typeof manifest.exports !== "object" || manifest.exports === null)
24
+ return [];
25
+ return Object.entries(manifest.exports)
26
+ .filter(([subpath]) => subpath.startsWith("."))
27
+ .map(([subpath, target]) => ({
28
+ subpath,
29
+ ...(typeof target === "string" ? { target } : {}),
30
+ }))
31
+ .sort((left, right) => left.subpath.localeCompare(right.subpath));
32
+ }
33
+ async function packageRootFor(workspaceRoot, source) {
34
+ if (source.type === "workspace") {
35
+ if (source.path === undefined) {
36
+ throw new PlatformError("DESCRIPTOR_INVALID", `workspace source missing path for ${source.packageName}`);
37
+ }
38
+ return await realpath(source.path);
39
+ }
40
+ const require = createRequire(pathToFileURL(join(workspaceRoot, "package.json")));
41
+ let current;
42
+ try {
43
+ current = dirname(require.resolve(`${source.packageName}/deployment/descriptor`));
44
+ }
45
+ catch (error) {
46
+ throw new PlatformError("DESCRIPTOR_INVALID", `cannot resolve installed package ${source.packageName}: ${error instanceof Error ? error.message : String(error)}`);
47
+ }
48
+ for (;;) {
49
+ try {
50
+ const manifest = JSON.parse(await readFile(join(current, "package.json"), "utf8"));
51
+ if (manifest.name === source.packageName)
52
+ return await realpath(current);
53
+ }
54
+ catch {
55
+ // Export maps commonly hide package.json; keep walking from a resolved
56
+ // package-owned descriptor until the package root is found.
57
+ }
58
+ const parent = dirname(current);
59
+ if (parent === current)
60
+ break;
61
+ current = parent;
62
+ }
63
+ throw new PlatformError("DESCRIPTOR_INVALID", `package root not found for ${source.packageName}`);
64
+ }
65
+ async function readManifest(packageRoot, packageName) {
66
+ try {
67
+ const manifest = JSON.parse(await readFile(join(packageRoot, "package.json"), "utf8"));
68
+ if (manifest.name !== packageName) {
69
+ throw new Error(`expected package ${packageName}`);
70
+ }
71
+ return manifest;
72
+ }
73
+ catch (error) {
74
+ throw new PlatformError("DESCRIPTOR_INVALID", `invalid package metadata for ${packageName}: ${error instanceof Error ? error.message : String(error)}`);
75
+ }
76
+ }
77
+ export async function describeModule(input) {
78
+ const packageRoot = await packageRootFor(input.workspaceRoot, input.source);
79
+ const manifest = await readManifest(packageRoot, input.descriptor.packageName);
80
+ return {
81
+ moduleRef: input.descriptor.moduleRef,
82
+ packageName: input.descriptor.packageName,
83
+ moduleVersion: input.descriptor.moduleVersion,
84
+ kind: input.descriptor.kind,
85
+ installClass: input.descriptor.installClass,
86
+ identity: input.descriptor.identity,
87
+ commands: commandsFrom(manifest, input.descriptor.packageName),
88
+ publicApiEntries: publicApiEntriesFrom(manifest),
89
+ provides: input.descriptor.provides,
90
+ requires: input.descriptor.requires,
91
+ requirements: input.descriptor.requirements,
92
+ configSlots: input.descriptor.configSlots,
93
+ lifecycle: input.descriptor.lifecycle.supported,
94
+ verification: input.descriptor.verification,
95
+ effects: input.descriptor.effects,
96
+ documentation: input.descriptor.documentation,
97
+ };
98
+ }
99
+ export async function readModuleDocument(input) {
100
+ const entry = input.descriptor.documentation.find((candidate) => candidate.id === input.documentId);
101
+ if (entry === undefined) {
102
+ throw new PlatformError("INVALID_REQUEST", `document "${input.documentId}" is not declared by ${input.descriptor.moduleRef}`);
103
+ }
104
+ const packageRoot = await packageRootFor(input.workspaceRoot, input.source);
105
+ const root = resolve(packageRoot);
106
+ const target = resolve(root, entry.path);
107
+ if (target === root || !target.startsWith(`${root}${sep}`)) {
108
+ throw new PlatformError("DESCRIPTOR_INVALID", `documentation path escapes package root for ${input.descriptor.moduleRef}`);
109
+ }
110
+ try {
111
+ const info = await stat(target);
112
+ if (!info.isFile())
113
+ throw new Error("not a file");
114
+ const content = await readFile(target, "utf8");
115
+ return {
116
+ moduleRef: input.descriptor.moduleRef,
117
+ packageName: input.descriptor.packageName,
118
+ documentId: entry.id,
119
+ path: entry.path,
120
+ ...(entry.description === undefined
121
+ ? {}
122
+ : { description: entry.description }),
123
+ content,
124
+ };
125
+ }
126
+ catch (error) {
127
+ throw new PlatformError("DESCRIPTOR_INVALID", `cannot read document ${entry.id} for ${input.descriptor.moduleRef}: ${error instanceof Error ? error.message : String(error)}`);
128
+ }
129
+ }
@@ -0,0 +1 @@
1
+ export * from "./docs.ts";
@@ -0,0 +1 @@
1
+ export * from "./docs.js";
@@ -0,0 +1,41 @@
1
+ import type { DeploymentCheck, DeploymentError, ModuleOperationResult } from "@tomflow/proflow-module-contract";
2
+ import type { ResolvedModule } from "../contracts.ts";
3
+ import type { ModuleCatalog } from "../modules.ts";
4
+ export type DoctorNextAction = {
5
+ kind: "none";
6
+ } | {
7
+ kind: "human-action";
8
+ action: string;
9
+ description: string;
10
+ } | {
11
+ kind: "repair-plan";
12
+ summary: string;
13
+ };
14
+ export interface DoctorReport {
15
+ moduleRef: string;
16
+ moduleVersion: string;
17
+ status: ModuleOperationResult["status"];
18
+ checks: DeploymentCheck[];
19
+ errors: DeploymentError[];
20
+ evidenceRefs: string[];
21
+ nextAction: DoctorNextAction;
22
+ observedEffects: string[];
23
+ }
24
+ /**
25
+ * Maps a doctor result to the recommended next step. Doctor only recommends:
26
+ * it never performs a repair. A failing or blocked module yields a `repair-plan`
27
+ * recommendation (to be followed by `plan --intent repair` → confirm → apply);
28
+ * an ACTION_REQUIRED result yields the recoverable human action as-is.
29
+ */
30
+ export declare function nextActionOf(result: ModuleOperationResult): DoctorNextAction;
31
+ /**
32
+ * Diagnoses a single module by dispatching its public `doctor` primitive. The
33
+ * report carries live checks, typed errors, evidence refs, and a recommended
34
+ * next action — but performs no side effects and never auto-repairs.
35
+ */
36
+ export declare function doctorModule(catalog: ModuleCatalog, module: ResolvedModule): Promise<DoctorReport>;
37
+ /**
38
+ * Diagnoses every module that declares the `doctor` primitive; modules without
39
+ * it are skipped.
40
+ */
41
+ export declare function doctorModules(catalog: ModuleCatalog, modules: readonly ResolvedModule[]): Promise<DoctorReport[]>;
@@ -0,0 +1,80 @@
1
+ import { dispatchLifecycle } from "../lifecycle/index.js";
2
+ /**
3
+ * Maps a doctor result to the recommended next step. Doctor only recommends:
4
+ * it never performs a repair. A failing or blocked module yields a `repair-plan`
5
+ * recommendation (to be followed by `plan --intent repair` → confirm → apply);
6
+ * an ACTION_REQUIRED result yields the recoverable human action as-is.
7
+ */
8
+ export function nextActionOf(result) {
9
+ switch (result.status) {
10
+ case "SUCCEEDED":
11
+ return { kind: "none" };
12
+ case "ACTION_REQUIRED": {
13
+ const action = result.actionRequired;
14
+ if (action !== undefined) {
15
+ return {
16
+ kind: "human-action",
17
+ action: action.action,
18
+ description: action.description,
19
+ };
20
+ }
21
+ return {
22
+ kind: "repair-plan",
23
+ summary: "action required but unspecified",
24
+ };
25
+ }
26
+ case "BLOCKED":
27
+ case "FAILED": {
28
+ const summary = result.error !== undefined
29
+ ? `${result.error.code}: ${result.error.message}`
30
+ : `module ${result.moduleRef} is ${result.status.toLowerCase()}`;
31
+ return { kind: "repair-plan", summary };
32
+ }
33
+ }
34
+ }
35
+ /**
36
+ * Diagnoses a single module by dispatching its public `doctor` primitive. The
37
+ * report carries live checks, typed errors, evidence refs, and a recommended
38
+ * next action — but performs no side effects and never auto-repairs.
39
+ */
40
+ export async function doctorModule(catalog, module) {
41
+ const primitives = ["status", "verify", "doctor"].filter((primitive) => module.lifecycle.includes(primitive));
42
+ const dispatched = [];
43
+ for (const primitive of primitives) {
44
+ dispatched.push(await dispatchLifecycle(catalog, module, primitive));
45
+ }
46
+ const severity = {
47
+ SUCCEEDED: 0,
48
+ ACTION_REQUIRED: 1,
49
+ BLOCKED: 2,
50
+ FAILED: 3,
51
+ };
52
+ const effective = dispatched
53
+ .map((item) => item.result)
54
+ .reduce((worst, current) => severity[current.status] > severity[worst.status] ? current : worst);
55
+ const checks = dispatched.flatMap((item) => item.result.checks ?? []);
56
+ const errors = dispatched.flatMap((item) => item.result.error === undefined ? [] : [item.result.error]);
57
+ return {
58
+ moduleRef: module.moduleRef,
59
+ moduleVersion: module.moduleVersion,
60
+ status: effective.status,
61
+ checks,
62
+ errors,
63
+ evidenceRefs: checks.map((check) => `check:${check.id}:${check.status}`),
64
+ nextAction: nextActionOf(effective),
65
+ observedEffects: dispatched.flatMap((item) => item.observedEffects),
66
+ };
67
+ }
68
+ /**
69
+ * Diagnoses every module that declares the `doctor` primitive; modules without
70
+ * it are skipped.
71
+ */
72
+ export async function doctorModules(catalog, modules) {
73
+ const reports = [];
74
+ for (const module of modules) {
75
+ if (!module.lifecycle.includes("doctor"))
76
+ continue;
77
+ reports.push(await doctorModule(catalog, module));
78
+ }
79
+ return reports;
80
+ }
@@ -0,0 +1,2 @@
1
+ export type { DoctorNextAction, DoctorReport } from "./doctor.ts";
2
+ export { doctorModule, doctorModules, nextActionOf } from "./doctor.ts";
@@ -0,0 +1 @@
1
+ export { doctorModule, doctorModules, nextActionOf } from "./doctor.js";
@@ -0,0 +1,6 @@
1
+ export declare const platformErrorCodes: readonly ["INVALID_REQUEST", "DESCRIPTOR_INVALID", "DUPLICATE_IDENTITY", "DEPENDENCY_UNRESOLVED", "DEPENDENCY_INCOMPATIBLE", "DEPENDENCY_CYCLE", "CONFIG_MISSING", "SECRET_REF_INVALID", "PLAN_STALE", "PLAN_NOT_FOUND", "PLAN_INVALID", "WORKSPACE_LOCKED", "LIFECYCLE_UNSUPPORTED", "SECRET_LEAK", "APPLY_FAILED", "UPGRADE_FAILED", "CORE_PACKAGE_REQUIRED", "UNINSTALL_FAILED", "VERIFY_FAILED", "REGISTRY_UNAVAILABLE", "REGISTRY_AUTH_REQUIRED", "REGISTRY_RESPONSE_INVALID", "PACKAGE_NOT_FOUND", "PACKAGE_NOT_PROFLOW", "COMMAND_FAILED"];
2
+ export type PlatformErrorCode = (typeof platformErrorCodes)[number];
3
+ export declare class PlatformError extends Error {
4
+ readonly code: PlatformErrorCode;
5
+ constructor(code: PlatformErrorCode, message: string);
6
+ }
@@ -0,0 +1,35 @@
1
+ export const platformErrorCodes = [
2
+ "INVALID_REQUEST",
3
+ "DESCRIPTOR_INVALID",
4
+ "DUPLICATE_IDENTITY",
5
+ "DEPENDENCY_UNRESOLVED",
6
+ "DEPENDENCY_INCOMPATIBLE",
7
+ "DEPENDENCY_CYCLE",
8
+ "CONFIG_MISSING",
9
+ "SECRET_REF_INVALID",
10
+ "PLAN_STALE",
11
+ "PLAN_NOT_FOUND",
12
+ "PLAN_INVALID",
13
+ "WORKSPACE_LOCKED",
14
+ "LIFECYCLE_UNSUPPORTED",
15
+ "SECRET_LEAK",
16
+ "APPLY_FAILED",
17
+ "UPGRADE_FAILED",
18
+ "CORE_PACKAGE_REQUIRED",
19
+ "UNINSTALL_FAILED",
20
+ "VERIFY_FAILED",
21
+ "REGISTRY_UNAVAILABLE",
22
+ "REGISTRY_AUTH_REQUIRED",
23
+ "REGISTRY_RESPONSE_INVALID",
24
+ "PACKAGE_NOT_FOUND",
25
+ "PACKAGE_NOT_PROFLOW",
26
+ "COMMAND_FAILED",
27
+ ];
28
+ export class PlatformError extends Error {
29
+ code;
30
+ constructor(code, message) {
31
+ super(message);
32
+ this.code = code;
33
+ this.name = "PlatformError";
34
+ }
35
+ }
@@ -0,0 +1,23 @@
1
+ import type { ResolvedModule } from "../contracts.ts";
2
+ export type DependencyEdgeKind = "moduleRef" | "capability";
3
+ export interface DependencyEdge {
4
+ from: string;
5
+ to: string;
6
+ kind: DependencyEdgeKind;
7
+ contractRef?: string;
8
+ }
9
+ export interface DependencyGraph {
10
+ nodes: string[];
11
+ edges: DependencyEdge[];
12
+ order: string[];
13
+ }
14
+ export interface GraphOptions {
15
+ config?: Record<string, Record<string, string>>;
16
+ }
17
+ export declare class ModuleRefUnresolvedError extends Error {
18
+ readonly code: "MODULE_REF_UNRESOLVED";
19
+ readonly from: string;
20
+ readonly target: string;
21
+ constructor(from: string, target: string, message: string);
22
+ }
23
+ export declare function buildDependencyGraph(modules: readonly ResolvedModule[], options?: GraphOptions): DependencyGraph;
@@ -0,0 +1,132 @@
1
+ import { PlatformError } from "../errors.js";
2
+ import { versionSatisfies } from "../modules.js";
3
+ export class ModuleRefUnresolvedError extends Error {
4
+ code = "MODULE_REF_UNRESOLVED";
5
+ from;
6
+ target;
7
+ constructor(from, target, message) {
8
+ super(message);
9
+ this.from = from;
10
+ this.target = target;
11
+ this.name = "ModuleRefUnresolvedError";
12
+ }
13
+ }
14
+ function compareRef(a, b) {
15
+ return a < b ? -1 : a > b ? 1 : 0;
16
+ }
17
+ export function buildDependencyGraph(modules, options = {}) {
18
+ const nodes = [...new Set(modules.map((module) => module.moduleRef))].sort(compareRef);
19
+ const nodeSet = new Set(nodes);
20
+ const providersByContract = new Map();
21
+ for (const module of modules) {
22
+ for (const provide of module.provides) {
23
+ const list = providersByContract.get(provide.contractRef) ?? [];
24
+ list.push({ moduleRef: module.moduleRef, version: provide.version });
25
+ providersByContract.set(provide.contractRef, list);
26
+ }
27
+ }
28
+ const edges = [];
29
+ const edgeSet = new Set();
30
+ const addEdge = (from, to, kind, contractRef) => {
31
+ const key = `${kind}|${from}|${to}|${contractRef ?? ""}`;
32
+ if (edgeSet.has(key))
33
+ return;
34
+ edgeSet.add(key);
35
+ const edge = { from, to, kind };
36
+ if (contractRef !== undefined)
37
+ edge.contractRef = contractRef;
38
+ edges.push(edge);
39
+ };
40
+ const sorted = [...modules].sort((a, b) => compareRef(a.moduleRef, b.moduleRef));
41
+ for (const module of sorted) {
42
+ for (const slot of module.configSlots) {
43
+ if (slot.type !== "moduleRef")
44
+ continue;
45
+ const effective = options.config?.[module.moduleRef]?.[slot.key] ?? slot.default;
46
+ if (typeof effective !== "string")
47
+ continue;
48
+ if (!nodeSet.has(effective)) {
49
+ throw new ModuleRefUnresolvedError(module.moduleRef, effective, `moduleRef binding ${slot.key}=${effective} for ${module.moduleRef} does not resolve to a selected module`);
50
+ }
51
+ addEdge(module.moduleRef, effective, "moduleRef");
52
+ }
53
+ for (const requirement of module.requires) {
54
+ const candidates = providersByContract.get(requirement.contractRef) ?? [];
55
+ const matching = candidates
56
+ .filter((provider) => versionSatisfies(provider.version, requirement.versionRange))
57
+ .sort((a, b) => compareRef(a.moduleRef, b.moduleRef));
58
+ if (matching.length > 0) {
59
+ for (const provider of matching) {
60
+ addEdge(module.moduleRef, provider.moduleRef, "capability", requirement.contractRef);
61
+ }
62
+ continue;
63
+ }
64
+ if (candidates.length > 0) {
65
+ throw new PlatformError("DEPENDENCY_INCOMPATIBLE", `${module.moduleRef} requires ${requirement.contractRef} ${requirement.versionRange} but no provider satisfies it`);
66
+ }
67
+ if (requirement.optional !== true) {
68
+ throw new PlatformError("DEPENDENCY_UNRESOLVED", `${module.moduleRef} requires ${requirement.contractRef} ${requirement.versionRange} but no module provides it`);
69
+ }
70
+ }
71
+ }
72
+ edges.sort((a, b) => {
73
+ const byFrom = compareRef(a.from, b.from);
74
+ if (byFrom !== 0)
75
+ return byFrom;
76
+ const byTo = compareRef(a.to, b.to);
77
+ if (byTo !== 0)
78
+ return byTo;
79
+ return a.kind < b.kind ? -1 : a.kind > b.kind ? 1 : 0;
80
+ });
81
+ const order = computeOrder(nodes, edges);
82
+ return { nodes, edges, order };
83
+ }
84
+ function computeOrder(nodes, edges) {
85
+ const deps = new Map();
86
+ for (const node of nodes)
87
+ deps.set(node, new Set());
88
+ for (const edge of edges) {
89
+ const set = deps.get(edge.from);
90
+ if (set === undefined)
91
+ continue;
92
+ set.add(edge.to);
93
+ }
94
+ const depth = new Map();
95
+ const state = new Map();
96
+ const visit = (node) => {
97
+ const current = state.get(node);
98
+ if (current === "done")
99
+ return depth.get(node) ?? 0;
100
+ if (current === "visiting") {
101
+ throw new PlatformError("DEPENDENCY_CYCLE", `dependency cycle detected at ${node}`);
102
+ }
103
+ state.set(node, "visiting");
104
+ let maxDepth = 0;
105
+ const nodeDeps = [...(deps.get(node) ?? new Set())].sort(compareRef);
106
+ for (const dependency of nodeDeps) {
107
+ const dependencyDepth = visit(dependency);
108
+ if (dependencyDepth + 1 > maxDepth)
109
+ maxDepth = dependencyDepth + 1;
110
+ }
111
+ state.set(node, "done");
112
+ depth.set(node, maxDepth);
113
+ return maxDepth;
114
+ };
115
+ for (const node of nodes)
116
+ visit(node);
117
+ const layers = new Map();
118
+ for (const node of nodes) {
119
+ const nodeDepth = depth.get(node) ?? 0;
120
+ const layer = layers.get(nodeDepth) ?? [];
121
+ layer.push(node);
122
+ layers.set(nodeDepth, layer);
123
+ }
124
+ const depths = [...layers.keys()].sort((a, b) => a - b);
125
+ const order = [];
126
+ for (const nodeDepth of depths) {
127
+ const layer = layers.get(nodeDepth) ?? [];
128
+ layer.sort(compareRef);
129
+ order.push(...layer);
130
+ }
131
+ return order;
132
+ }
@@ -0,0 +1,2 @@
1
+ export type { DependencyEdge, DependencyEdgeKind, DependencyGraph, GraphOptions, } from "./graph.ts";
2
+ export { buildDependencyGraph, ModuleRefUnresolvedError } from "./graph.ts";
@@ -0,0 +1 @@
1
+ export { buildDependencyGraph, ModuleRefUnresolvedError } from "./graph.js";
@@ -0,0 +1,28 @@
1
+ export type { PackageManagerDriver } from "./apply/driver.ts";
2
+ export { applyPlan, createWorkspacePackageManagerDriver, } from "./apply/index.ts";
3
+ export type { CliOutcome, CliStatus } from "./cli.ts";
4
+ export { runCli } from "./cli.ts";
5
+ export type { DeploymentIntent, DeploymentPlan, DeploymentState, DeploymentStep, ModuleTarget, PlatformState, ResolvedModule, VerificationRecord, VerificationStep, } from "./contracts.ts";
6
+ export { AutoModuleCatalog, discoverModules } from "./discovery/discover.ts";
7
+ export type { ModuleDocsView, ModuleDocumentContent, PublicApiEntry, PublishedCommand, } from "./docs/index.ts";
8
+ export { describeModule, readModuleDocument } from "./docs/index.ts";
9
+ export { doctorModule, doctorModules } from "./doctor/index.ts";
10
+ export type { PlatformErrorCode } from "./errors.ts";
11
+ export { PlatformError } from "./errors.ts";
12
+ export { generateInstallDoc, preflightInstallerEnvironment, renderInstallDoc, } from "./install/index.ts";
13
+ export { dispatchLifecycle, restartModules, startModules, statusModules, stopModules, } from "./lifecycle/index.ts";
14
+ export { buildManifest, MANIFEST_CONTRACT } from "./manifest/index.ts";
15
+ export type { ModuleCatalog, ModuleSource } from "./modules.ts";
16
+ export { versionSatisfies } from "./modules.ts";
17
+ export type { WorkspacePaths } from "./paths.ts";
18
+ export { atomicWrite, workspacePaths } from "./paths.ts";
19
+ export { appendVerification, emptyDeploymentState, listPlans, loadConfig, loadDeploymentState, loadLatestVerification, loadPlan, loadVerificationHistory, materializeConfig, saveDeploymentState, savePlan, writeInstallDoc, } from "./persistence/index.ts";
20
+ export { assessUpgrade, CheckStrategy, checkPlanStale, computeFingerprint, ExecuteStrategy, evaluateStepCheck, planDeployment, planRepair, planUpgrade, repairFactCodes, } from "./planner/index.ts";
21
+ export type { PlanInput } from "./planner/plan.ts";
22
+ export type { PreflightResult } from "./preflight/findings.ts";
23
+ export { runPreflight } from "./preflight/preflight.ts";
24
+ export { assessPlatformReady } from "./ready/index.ts";
25
+ export type { RegistryDiscoveryResult, RegistryModuleCandidate, RegistryRejectedPackage, } from "./registry/index.ts";
26
+ export { discoverRegistryModules } from "./registry/index.ts";
27
+ export { acquireWorkspaceLock, readWorkspaceLock, redactDeep, redactPlanSecrets, redactSecretValues, SECRET_REDACTED, workspaceLockPath, } from "./security/index.ts";
28
+ export { verifyModule, verifyModules } from "./verification/index.ts";
@@ -0,0 +1,18 @@
1
+ export { applyPlan, createWorkspacePackageManagerDriver, } from "./apply/index.js";
2
+ export { runCli } from "./cli.js";
3
+ export { AutoModuleCatalog, discoverModules } from "./discovery/discover.js";
4
+ export { describeModule, readModuleDocument } from "./docs/index.js";
5
+ export { doctorModule, doctorModules } from "./doctor/index.js";
6
+ export { PlatformError } from "./errors.js";
7
+ export { generateInstallDoc, preflightInstallerEnvironment, renderInstallDoc, } from "./install/index.js";
8
+ export { dispatchLifecycle, restartModules, startModules, statusModules, stopModules, } from "./lifecycle/index.js";
9
+ export { buildManifest, MANIFEST_CONTRACT } from "./manifest/index.js";
10
+ export { versionSatisfies } from "./modules.js";
11
+ export { atomicWrite, workspacePaths } from "./paths.js";
12
+ export { appendVerification, emptyDeploymentState, listPlans, loadConfig, loadDeploymentState, loadLatestVerification, loadPlan, loadVerificationHistory, materializeConfig, saveDeploymentState, savePlan, writeInstallDoc, } from "./persistence/index.js";
13
+ export { assessUpgrade, CheckStrategy, checkPlanStale, computeFingerprint, ExecuteStrategy, evaluateStepCheck, planDeployment, planRepair, planUpgrade, repairFactCodes, } from "./planner/index.js";
14
+ export { runPreflight } from "./preflight/preflight.js";
15
+ export { assessPlatformReady } from "./ready/index.js";
16
+ export { discoverRegistryModules } from "./registry/index.js";
17
+ export { acquireWorkspaceLock, readWorkspaceLock, redactDeep, redactPlanSecrets, redactSecretValues, SECRET_REDACTED, workspaceLockPath, } from "./security/index.js";
18
+ export { verifyModule, verifyModules } from "./verification/index.js";
@@ -0,0 +1,10 @@
1
+ import type { ResolvedModule } from "../contracts.ts";
2
+ import { type RegistryModuleCandidate } from "../registry/index.ts";
3
+ /**
4
+ * Registry bootstrap targets intentionally carry only facts available before
5
+ * installation. They are package-plan placeholders, never substitutes for the
6
+ * package-owned Module Descriptor that is loaded after installation.
7
+ */
8
+ export declare function registryCandidateToBootstrapModule(candidate: RegistryModuleCandidate): ResolvedModule;
9
+ export declare function selectBootstrapModules(candidates: readonly RegistryModuleCandidate[], explicitPackageName?: string): ResolvedModule[];
10
+ export declare function selectUpgradeBootstrapModules(currentModules: readonly ResolvedModule[], candidates: readonly RegistryModuleCandidate[]): ResolvedModule[];
@@ -0,0 +1,79 @@
1
+ import { PlatformError } from "../errors.js";
2
+ import { PRO_FLOW_PACKAGE_PREFIX, } from "../registry/index.js";
3
+ /**
4
+ * Registry bootstrap targets intentionally carry only facts available before
5
+ * installation. They are package-plan placeholders, never substitutes for the
6
+ * package-owned Module Descriptor that is loaded after installation.
7
+ */
8
+ export function registryCandidateToBootstrapModule(candidate) {
9
+ if (!candidate.packageName.startsWith(PRO_FLOW_PACKAGE_PREFIX)) {
10
+ throw new PlatformError("PACKAGE_NOT_PROFLOW", `package ${candidate.packageName} is outside ${PRO_FLOW_PACKAGE_PREFIX}*`);
11
+ }
12
+ const moduleRef = candidate.packageName.slice(PRO_FLOW_PACKAGE_PREFIX.length);
13
+ if (moduleRef === "") {
14
+ throw new PlatformError("REGISTRY_RESPONSE_INVALID", `cannot derive moduleRef from ${candidate.packageName}`);
15
+ }
16
+ return {
17
+ moduleRef,
18
+ packageName: candidate.packageName,
19
+ moduleVersion: candidate.moduleVersion,
20
+ kind: "registry-package",
21
+ installClass: candidate.installClass,
22
+ provides: [],
23
+ requires: [],
24
+ requirements: [],
25
+ configSlots: [],
26
+ lifecycle: [],
27
+ verification: { checks: [] },
28
+ effects: [],
29
+ documentation: [],
30
+ source: { type: "registry" },
31
+ };
32
+ }
33
+ export function selectBootstrapModules(candidates, explicitPackageName) {
34
+ const byPackage = new Map(candidates.map((candidate) => [candidate.packageName, candidate]));
35
+ const roots = explicitPackageName === undefined
36
+ ? candidates.filter((candidate) => candidate.installClass === "core")
37
+ : candidates.filter((candidate) => candidate.packageName === explicitPackageName);
38
+ if (roots.length === 0) {
39
+ throw new PlatformError(explicitPackageName === undefined
40
+ ? "REGISTRY_RESPONSE_INVALID"
41
+ : "PACKAGE_NOT_FOUND", explicitPackageName === undefined
42
+ ? "Registry discovery returned no installable core ProFlow packages"
43
+ : `no installable ProFlow package found for ${explicitPackageName}`);
44
+ }
45
+ const selected = new Map();
46
+ const queue = [...roots];
47
+ while (queue.length > 0) {
48
+ const candidate = queue.shift();
49
+ if (!candidate)
50
+ continue;
51
+ if (selected.has(candidate.packageName))
52
+ continue;
53
+ selected.set(candidate.packageName, candidate);
54
+ for (const dependencyName of candidate.installRequires) {
55
+ const dependency = byPackage.get(dependencyName);
56
+ if (dependency === undefined) {
57
+ throw new PlatformError("DEPENDENCY_UNRESOLVED", `Registry bootstrap dependency ${dependencyName} required by ${candidate.packageName} was not discovered`);
58
+ }
59
+ queue.push(dependency);
60
+ }
61
+ }
62
+ return [...selected.values()]
63
+ .sort((a, b) => a.packageName.localeCompare(b.packageName))
64
+ .map(registryCandidateToBootstrapModule);
65
+ }
66
+ export function selectUpgradeBootstrapModules(currentModules, candidates) {
67
+ const byPackage = new Map(candidates.map((candidate) => [candidate.packageName, candidate]));
68
+ const targets = [];
69
+ for (const current of currentModules) {
70
+ const candidate = byPackage.get(current.packageName);
71
+ if (candidate === undefined) {
72
+ throw new PlatformError("PACKAGE_NOT_FOUND", `no installable Registry target found for managed package ${current.packageName}`);
73
+ }
74
+ if (candidate.moduleVersion === current.moduleVersion)
75
+ continue;
76
+ targets.push(registryCandidateToBootstrapModule(candidate));
77
+ }
78
+ return targets;
79
+ }