@tomflow/proflow-platform-cli 0.1.16 → 0.1.17

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 (36) hide show
  1. package/DOCS.md +27 -0
  2. package/SETUP.md +7 -0
  3. package/dist/deployment/adapter.d.ts +58 -34
  4. package/dist/deployment/adapter.js +28 -12
  5. package/dist/deployment/descriptor.d.ts +5 -16
  6. package/dist/deployment/descriptor.js +10 -21
  7. package/dist/src/cli.js +131 -137
  8. package/dist/src/contracts.d.ts +0 -2
  9. package/dist/src/discovery/discover.d.ts +1 -3
  10. package/dist/src/discovery/discover.js +1 -10
  11. package/dist/src/errors.d.ts +1 -1
  12. package/dist/src/errors.js +0 -2
  13. package/dist/src/index.d.ts +0 -2
  14. package/dist/src/index.js +0 -1
  15. package/dist/src/lifecycle/dispatch.d.ts +4 -11
  16. package/dist/src/lifecycle/dispatch.js +28 -56
  17. package/dist/src/lifecycle/index.d.ts +4 -4
  18. package/dist/src/lifecycle/index.js +2 -2
  19. package/dist/src/lifecycle/thin.d.ts +19 -7
  20. package/dist/src/lifecycle/thin.js +80 -55
  21. package/dist/src/persistence/index.d.ts +0 -2
  22. package/dist/src/persistence/index.js +0 -1
  23. package/package.json +7 -5
  24. package/proflow.module.json +5 -20
  25. package/dist/src/binding/production-bindings.d.ts +0 -37
  26. package/dist/src/binding/production-bindings.js +0 -75
  27. package/dist/src/docs/aggregate.d.ts +0 -18
  28. package/dist/src/docs/aggregate.js +0 -44
  29. package/dist/src/docs/docs.d.ts +0 -16
  30. package/dist/src/docs/docs.js +0 -68
  31. package/dist/src/docs/index.d.ts +0 -2
  32. package/dist/src/docs/index.js +0 -1
  33. package/dist/src/persistence/config.d.ts +0 -6
  34. package/dist/src/persistence/config.js +0 -54
  35. package/dist/src/persistence/guards.d.ts +0 -1
  36. package/dist/src/persistence/guards.js +0 -7
package/dist/src/cli.js CHANGED
@@ -3,28 +3,24 @@ import { readFile, realpath, stat } from "node:fs/promises";
3
3
  import { resolve } from "node:path";
4
4
  import { moduleStatusObservationSchema } from "@tomflow/proflow-module-contract";
5
5
  import { descriptor as platformCliDescriptor } from "../deployment/descriptor.js";
6
- import { buildProductionBindings, importRawAdapter, } from "./binding/production-bindings.js";
7
6
  import { AutoModuleCatalog, discoverModules } from "./discovery/discover.js";
8
7
  import { InstalledModuleCatalog } from "./discovery/installed.js";
9
- import { aggregateModuleDocs } from "./docs/aggregate.js";
10
8
  import { PlatformError } from "./errors.js";
11
9
  import { observeWorkspaceInstalledVersion, removeWorkspacePackages, syncWorkspacePackages, } from "./install/package-manager.js";
12
- import { observeStatuses, preflightAndStartModules, stopModulesThin, } from "./lifecycle/thin.js";
13
- import { workspacePaths } from "./paths.js";
14
- import { loadConfig } from "./persistence/config.js";
10
+ import { installModulesThin, observeDocs, observeStatuses, setupModulesThin, startModulesThin, stopModulesThin, uninstallModulesThin, } from "./lifecycle/index.js";
15
11
  import { ensureWorkspaceMetadata } from "./persistence/workspace-metadata.js";
16
12
  import { discoverRegistryModules, PRO_FLOW_PACKAGE_PREFIX, } from "./registry/index.js";
17
13
  const COMMANDS = [
18
- "modules",
19
- "docs",
20
14
  "install",
21
15
  "uninstall",
16
+ "status",
17
+ "setup",
18
+ "docs",
22
19
  "start",
23
20
  "stop",
24
21
  ];
25
22
  function parseArgs(argv) {
26
- let json = false;
27
- let workspace;
23
+ let json = false, workspace, moduleRef, input, inputSeen = false;
28
24
  let special;
29
25
  const positional = [];
30
26
  for (let index = 0; index < argv.length; index += 1) {
@@ -35,24 +31,33 @@ function parseArgs(argv) {
35
31
  json = true;
36
32
  continue;
37
33
  }
38
- if (value === "--workspace") {
34
+ if (value === "--workspace" ||
35
+ value === "--module" ||
36
+ value === "--input") {
39
37
  const next = argv[index + 1];
40
- if (!next || next.startsWith("-")) {
41
- throw new PlatformError("INVALID_REQUEST", "--workspace requires a path");
38
+ if (!next || (value !== "--input" && next.startsWith("-")))
39
+ throw new PlatformError("INVALID_REQUEST", `${value} requires a value`);
40
+ if (value === "--workspace")
41
+ workspace = next;
42
+ else if (value === "--module")
43
+ moduleRef = next;
44
+ else {
45
+ try {
46
+ input = JSON.parse(next);
47
+ inputSeen = true;
48
+ }
49
+ catch (error) {
50
+ throw new PlatformError("INVALID_REQUEST", `--input must be valid JSON: ${error instanceof Error ? error.message : String(error)}`);
51
+ }
42
52
  }
43
- workspace = next;
44
53
  index += 1;
45
54
  continue;
46
55
  }
47
56
  if (value === "--help" || value === "-h") {
48
- if (special !== undefined && special !== "help")
49
- throw new PlatformError("INVALID_REQUEST", "help and version flags cannot be combined");
50
57
  special = "help";
51
58
  continue;
52
59
  }
53
60
  if (value === "--version" || value === "-v") {
54
- if (special !== undefined && special !== "version")
55
- throw new PlatformError("INVALID_REQUEST", "help and version flags cannot be combined");
56
61
  special = "version";
57
62
  continue;
58
63
  }
@@ -61,15 +66,15 @@ function parseArgs(argv) {
61
66
  positional.push(value);
62
67
  }
63
68
  if (special !== undefined) {
64
- if (workspace !== undefined || positional.length > 0)
65
- throw new PlatformError("INVALID_REQUEST", `${special} flag cannot be combined with a command or --workspace`);
69
+ if (workspace !== undefined ||
70
+ moduleRef !== undefined ||
71
+ inputSeen ||
72
+ positional.length > 0)
73
+ throw new PlatformError("INVALID_REQUEST", `${special} flag cannot be combined with command options`);
66
74
  return { command: special, json };
67
75
  }
68
- if (positional.length === 0) {
69
- if (workspace !== undefined)
70
- throw new PlatformError("INVALID_REQUEST", "--workspace is only valid with install");
76
+ if (positional.length === 0)
71
77
  return { command: "help", json };
72
- }
73
78
  if (positional.length !== 1)
74
79
  throw new PlatformError("INVALID_REQUEST", "commands accept no positional arguments");
75
80
  const raw = positional[0] ?? "";
@@ -78,9 +83,17 @@ function parseArgs(argv) {
78
83
  const command = raw;
79
84
  if (workspace !== undefined && command !== "install")
80
85
  throw new PlatformError("INVALID_REQUEST", "--workspace is only valid with install");
81
- return workspace === undefined
82
- ? { command, json }
83
- : { command, workspace, json };
86
+ if ((moduleRef !== undefined || inputSeen) && command !== "setup")
87
+ throw new PlatformError("INVALID_REQUEST", "--module/--input are only valid with setup");
88
+ if (inputSeen && moduleRef === undefined)
89
+ throw new PlatformError("INVALID_REQUEST", "--input requires --module");
90
+ return {
91
+ command,
92
+ json,
93
+ ...(workspace === undefined ? {} : { workspace }),
94
+ ...(moduleRef === undefined ? {} : { moduleRef }),
95
+ ...(inputSeen ? { input } : {}),
96
+ };
84
97
  }
85
98
  function outcome(command, status, workspaceRoot, data) {
86
99
  return {
@@ -99,32 +112,12 @@ async function canonicalWorkspace(cwd, explicit) {
99
112
  catch (error) {
100
113
  throw new PlatformError("WORKSPACE_NOT_FOUND", `Workspace does not exist: ${candidate} (${error instanceof Error ? error.message : String(error)})`);
101
114
  }
102
- if (!info.isDirectory()) {
115
+ if (!info.isDirectory())
103
116
  throw new PlatformError("WORKSPACE_NOT_FOUND", `Workspace is not a directory: ${candidate}`);
104
- }
105
117
  return realpath(candidate);
106
118
  }
107
- async function loadConfigMap(root, modules) {
108
- const paths = workspacePaths(root);
109
- const configByModuleRef = new Map();
110
- for (const module of modules) {
111
- const config = await loadConfig(paths, module.moduleRef);
112
- if (config === undefined)
113
- continue;
114
- configByModuleRef.set(module.moduleRef, config);
115
- }
116
- return configByModuleRef;
117
- }
118
119
  async function buildContext(root) {
119
- const discovered = await discoverModules({ workspaceRoot: root });
120
- const configByModuleRef = await loadConfigMap(root, discovered);
121
- const bindings = await buildProductionBindings({
122
- workspaceRoot: root,
123
- modules: discovered,
124
- configByModuleRef,
125
- importAdapter: (packageName, source) => importRawAdapter(packageName, source, root),
126
- });
127
- const catalog = new AutoModuleCatalog(root, bindings);
120
+ const catalog = new AutoModuleCatalog(root);
128
121
  const modules = await discoverModules({ workspaceRoot: root, catalog });
129
122
  return { catalog, modules };
130
123
  }
@@ -137,62 +130,62 @@ function statusFromModule(value) {
137
130
  ? "BLOCKED"
138
131
  : "FAILED";
139
132
  }
140
- function failedLifecycleStatus(results) {
141
- const last = results.at(-1);
142
- return last === undefined
143
- ? "SUCCEEDED"
144
- : statusFromModule(last.result.status);
133
+ function batchStatus(result) {
134
+ if (result.completed)
135
+ return "SUCCEEDED";
136
+ if (result.blockedBy)
137
+ return result.blockedBy.setupStatus === "ACTION_REQUIRED"
138
+ ? "ACTION_REQUIRED"
139
+ : "FAILED";
140
+ return statusFromModule(result.results.at(-1)?.result.status ?? "FAILED");
145
141
  }
146
- async function handleModules(root) {
142
+ async function handleStatus(root) {
147
143
  const { catalog, modules } = await buildContext(root);
148
- const observed = await observeStatuses(catalog, modules);
144
+ const observed = await observeStatuses(catalog, modules, root);
149
145
  const byRef = new Map(modules.map((module) => [module.moduleRef, module]));
150
146
  const output = observed.map((item) => {
151
- if (item.result.status !== "SUCCEEDED") {
147
+ if (item.result.status !== "SUCCEEDED")
152
148
  throw new PlatformError("COMMAND_FAILED", `module ${item.moduleRef} status observation did not return SUCCEEDED`);
153
- }
154
149
  const parsed = moduleStatusObservationSchema.safeParse(item.result.data);
155
- if (!parsed.success) {
156
- throw new PlatformError("COMMAND_FAILED", `module ${item.moduleRef} returned an invalid status observation: ${parsed.error.message}`);
157
- }
150
+ if (!parsed.success)
151
+ throw new PlatformError("COMMAND_FAILED", `module ${item.moduleRef} returned invalid status: ${parsed.error.message}`);
158
152
  const module = byRef.get(item.moduleRef);
159
- if (module === undefined)
153
+ if (!module)
160
154
  throw new PlatformError("COMMAND_FAILED", `unknown module ${item.moduleRef}`);
161
155
  return {
162
156
  moduleRef: item.moduleRef,
163
157
  version: module.moduleVersion,
164
- configStatus: parsed.data.configStatus,
165
- ...(parsed.data.missingConfig === undefined
166
- ? {}
167
- : { missingConfig: parsed.data.missingConfig }),
158
+ setupStatus: parsed.data.setupStatus,
168
159
  runtimeStatus: parsed.data.runtimeStatus,
169
160
  };
170
161
  });
171
- return outcome("modules", "SUCCEEDED", root, { modules: output });
162
+ return outcome("status", "SUCCEEDED", root, { modules: output });
172
163
  }
173
164
  async function handleDocs(root) {
174
- const catalog = new AutoModuleCatalog(root);
175
- const modules = await discoverModules({ workspaceRoot: root, catalog });
176
- const docs = await aggregateModuleDocs(root, catalog, modules);
177
- return outcome("docs", "SUCCEEDED", root, { modules: docs });
165
+ const { catalog, modules } = await buildContext(root);
166
+ const docs = await observeDocs(catalog, modules, root);
167
+ const byRef = new Map(modules.map((module) => [module.moduleRef, module]));
168
+ return outcome("docs", "SUCCEEDED", root, {
169
+ modules: docs.map((item) => ({
170
+ moduleRef: item.moduleRef,
171
+ version: byRef.get(item.moduleRef)?.moduleVersion,
172
+ docs: item.result.data,
173
+ })),
174
+ });
178
175
  }
179
176
  async function validateInstalledPackageSet(root, candidates, previousManaged) {
180
177
  const expectedNames = candidates.map((item) => item.packageName).sort();
181
178
  const declaredNames = await workspaceProFlowDependencies(root);
182
- if (JSON.stringify(declaredNames) !== JSON.stringify(expectedNames)) {
179
+ if (JSON.stringify(declaredNames) !== JSON.stringify(expectedNames))
183
180
  throw new PlatformError("COMMAND_FAILED", `managed dependency set mismatch: expected ${expectedNames.join(", ")}, observed ${declaredNames.join(", ")}`);
184
- }
185
181
  for (const candidate of candidates) {
186
182
  const observed = await observeWorkspaceInstalledVersion(root, candidate.packageName);
187
- if (observed !== candidate.moduleVersion) {
183
+ if (observed !== candidate.moduleVersion)
188
184
  throw new PlatformError("COMMAND_FAILED", `installed version mismatch for ${candidate.packageName}: expected ${candidate.moduleVersion}, observed ${observed ?? "missing"}`);
189
- }
190
185
  }
191
- for (const stale of previousManaged.filter((name) => !expectedNames.includes(name))) {
192
- if ((await observeWorkspaceInstalledVersion(root, stale)) !== undefined) {
186
+ for (const stale of previousManaged.filter((name) => !expectedNames.includes(name)))
187
+ if ((await observeWorkspaceInstalledVersion(root, stale)) !== undefined)
193
188
  throw new PlatformError("COMMAND_FAILED", `stale managed package remains installed after synchronization: ${stale}`);
194
- }
195
- }
196
189
  const catalog = new InstalledModuleCatalog(root);
197
190
  const sources = await catalog.sources();
198
191
  const modules = await discoverModules({ catalog, sources });
@@ -200,9 +193,8 @@ async function validateInstalledPackageSet(root, candidates, previousManaged) {
200
193
  for (const candidate of candidates) {
201
194
  const module = byPackage.get(candidate.packageName);
202
195
  if (module === undefined ||
203
- module.moduleVersion !== candidate.moduleVersion) {
196
+ module.moduleVersion !== candidate.moduleVersion)
204
197
  throw new PlatformError("DESCRIPTOR_INVALID", `installed descriptor mismatch for ${candidate.packageName}@${candidate.moduleVersion}`);
205
- }
206
198
  }
207
199
  }
208
200
  async function handleInstall(root, runtime) {
@@ -212,12 +204,10 @@ async function handleInstall(root, runtime) {
212
204
  ? {}
213
205
  : { runner: runtime.registryRunner }),
214
206
  });
215
- if (discovered.rejected.length > 0) {
207
+ if (discovered.rejected.length > 0)
216
208
  throw new PlatformError("REGISTRY_RESPONSE_INVALID", `registry contains rejected ProFlow packages: ${discovered.rejected.map((item) => `${item.packageName}:${item.reason}`).join(", ")}`);
217
- }
218
- if (discovered.candidates.length === 0) {
209
+ if (discovered.candidates.length === 0)
219
210
  throw new PlatformError("PACKAGE_NOT_FOUND", "no ProFlow packages were discovered in the configured scope");
220
- }
221
211
  const previousManaged = await workspaceProFlowDependencies(root);
222
212
  const mutation = await syncWorkspacePackages({
223
213
  workspaceRoot: root,
@@ -234,7 +224,9 @@ async function handleInstall(root, runtime) {
234
224
  });
235
225
  await validateInstalledPackageSet(root, discovered.candidates, previousManaged);
236
226
  const metadata = await ensureWorkspaceMetadata(root);
237
- return outcome("install", "SUCCEEDED", root, {
227
+ const { catalog, modules } = await buildContext(root);
228
+ const moduleInstall = await installModulesThin(catalog, modules, root);
229
+ return outcome("install", batchStatus(moduleInstall), root, {
238
230
  registry: discovered.registry,
239
231
  packageManager: mutation.packageManager,
240
232
  packages: discovered.candidates.map((item) => ({
@@ -242,7 +234,8 @@ async function handleInstall(root, runtime) {
242
234
  version: item.moduleVersion,
243
235
  })),
244
236
  workspace: metadata,
245
- next: "platform modules",
237
+ modules: moduleInstall,
238
+ next: "platform status",
246
239
  });
247
240
  }
248
241
  async function workspaceProFlowDependencies(root) {
@@ -256,10 +249,9 @@ async function workspaceProFlowDependencies(root) {
256
249
  const value = record[field];
257
250
  if (typeof value !== "object" || value === null || Array.isArray(value))
258
251
  continue;
259
- for (const name of Object.keys(value)) {
252
+ for (const name of Object.keys(value))
260
253
  if (name.startsWith(PRO_FLOW_PACKAGE_PREFIX))
261
254
  names.add(name);
262
- }
263
255
  }
264
256
  return [...names].sort();
265
257
  }
@@ -273,6 +265,13 @@ async function workspaceProFlowDependencies(root) {
273
265
  }
274
266
  async function handleUninstall(root, runtime) {
275
267
  const packageNames = await workspaceProFlowDependencies(root);
268
+ const { catalog, modules } = await buildContext(root);
269
+ const moduleUninstall = await uninstallModulesThin(catalog, modules, root);
270
+ if (!moduleUninstall.completed)
271
+ return outcome("uninstall", batchStatus(moduleUninstall), root, {
272
+ modules: moduleUninstall,
273
+ removed: [],
274
+ });
276
275
  const mutation = await removeWorkspacePackages({
277
276
  workspaceRoot: root,
278
277
  packageNames,
@@ -284,26 +283,39 @@ async function handleUninstall(root, runtime) {
284
283
  : { executableAvailable: runtime.executableAvailable }),
285
284
  });
286
285
  return outcome("uninstall", "SUCCEEDED", root, {
286
+ modules: moduleUninstall,
287
287
  packageManager: mutation.packageManager,
288
288
  removed: packageNames,
289
289
  preserved: [".proflow"],
290
290
  });
291
291
  }
292
+ async function handleSetup(root, parsed) {
293
+ const { catalog, modules } = await buildContext(root);
294
+ const target = parsed.moduleRef === undefined
295
+ ? undefined
296
+ : {
297
+ moduleRef: parsed.moduleRef,
298
+ ...(Object.hasOwn(parsed, "input") ? { input: parsed.input } : {}),
299
+ };
300
+ const result = await setupModulesThin(catalog, modules, root, target);
301
+ return outcome("setup", batchStatus(result), root, result);
302
+ }
292
303
  async function handleStart(root) {
293
304
  const { catalog, modules } = await buildContext(root);
294
- const result = await preflightAndStartModules(catalog, modules);
295
- return outcome("start", result.completed ? "SUCCEEDED" : failedLifecycleStatus(result.results), root, result);
305
+ const result = await startModulesThin(catalog, modules, root);
306
+ return outcome("start", batchStatus(result), root, result);
296
307
  }
297
308
  async function handleStop(root) {
298
309
  const { catalog, modules } = await buildContext(root);
299
- const result = await stopModulesThin(catalog, modules);
300
- return outcome("stop", result.completed ? "SUCCEEDED" : failedLifecycleStatus(result.results), root, result);
310
+ const result = await stopModulesThin(catalog, modules, root);
311
+ return outcome("stop", batchStatus(result), root, result);
301
312
  }
302
313
  function helpOutcome() {
303
314
  return outcome("help", "SUCCEEDED", undefined, {
304
- usage: "platform <modules|docs|install|uninstall|start|stop> [--json]",
315
+ usage: "platform <install|uninstall|status|setup|docs|start|stop> [--json]",
305
316
  commands: [...COMMANDS],
306
317
  install: "platform install [--workspace <path>]",
318
+ setup: "platform setup [--module <moduleRef> --input '<json>']",
307
319
  });
308
320
  }
309
321
  export async function runCli(argv, runtime = {}) {
@@ -317,24 +329,25 @@ export async function runCli(argv, runtime = {}) {
317
329
  try {
318
330
  if (parsed.command === "help")
319
331
  return JSON.stringify(helpOutcome());
320
- if (parsed.command === "version") {
332
+ if (parsed.command === "version")
321
333
  return JSON.stringify(outcome("version", "SUCCEEDED", undefined, {
322
334
  version: platformCliDescriptor.moduleVersion,
323
335
  }));
324
- }
325
336
  const cwd = await canonicalWorkspace(runtime.cwd ?? process.cwd());
326
337
  const root = parsed.command === "install" && parsed.workspace !== undefined
327
338
  ? await canonicalWorkspace(cwd, parsed.workspace)
328
339
  : cwd;
329
340
  switch (parsed.command) {
330
- case "modules":
331
- return JSON.stringify(await handleModules(root));
332
- case "docs":
333
- return JSON.stringify(await handleDocs(root));
334
341
  case "install":
335
342
  return JSON.stringify(await handleInstall(root, runtime));
336
343
  case "uninstall":
337
344
  return JSON.stringify(await handleUninstall(root, runtime));
345
+ case "status":
346
+ return JSON.stringify(await handleStatus(root));
347
+ case "setup":
348
+ return JSON.stringify(await handleSetup(root, parsed));
349
+ case "docs":
350
+ return JSON.stringify(await handleDocs(root));
338
351
  case "start":
339
352
  return JSON.stringify(await handleStart(root));
340
353
  case "stop":
@@ -346,13 +359,12 @@ export async function runCli(argv, runtime = {}) {
346
359
  }
347
360
  }
348
361
  function errorOutcome(command, error) {
349
- if (error instanceof PlatformError) {
362
+ if (error instanceof PlatformError)
350
363
  return {
351
364
  command,
352
365
  status: "FAILED",
353
366
  error: { code: error.code, message: error.message },
354
367
  };
355
- }
356
368
  return {
357
369
  command,
358
370
  status: "FAILED",
@@ -362,62 +374,44 @@ function errorOutcome(command, error) {
362
374
  },
363
375
  };
364
376
  }
365
- function isRecord(value) {
366
- return typeof value === "object" && value !== null && !Array.isArray(value);
367
- }
368
- function renderModules(data) {
377
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
378
+ function renderStatus(data) {
369
379
  if (!isRecord(data) || !Array.isArray(data.modules))
370
380
  return "No modules.";
371
- const lines = ["ProFlow Modules", ""];
372
- for (const raw of data.modules) {
373
- if (!isRecord(raw))
374
- continue;
375
- const missing = Array.isArray(raw.missingConfig)
376
- ? raw.missingConfig
377
- .filter((item) => typeof item === "string")
378
- .join(",")
379
- : "-";
380
- lines.push(`${String(raw.moduleRef)} ${String(raw.version)} config=${String(raw.configStatus)} runtime=${String(raw.runtimeStatus)} missing=${missing}`);
381
- }
382
- return lines.join("\n");
381
+ return [
382
+ "ProFlow Modules",
383
+ "",
384
+ ...data.modules
385
+ .filter(isRecord)
386
+ .map((raw) => `${String(raw.moduleRef)} ${String(raw.version)} setup=${String(raw.setupStatus)} runtime=${String(raw.runtimeStatus)}`),
387
+ ].join("\n");
383
388
  }
384
389
  function renderDocs(data) {
385
390
  if (!isRecord(data) || !Array.isArray(data.modules))
386
391
  return "No module docs.";
387
392
  const lines = ["ProFlow Docs"];
388
- for (const raw of data.modules) {
389
- if (!isRecord(raw))
390
- continue;
391
- lines.push("", `## ${String(raw.moduleRef)} @ ${String(raw.version)}`);
392
- if (!Array.isArray(raw.documents))
393
- continue;
394
- for (const document of raw.documents) {
395
- if (!isRecord(document))
396
- continue;
397
- lines.push("", `### ${String(document.id)}`, String(document.content ?? ""));
398
- }
399
- }
393
+ for (const raw of data.modules)
394
+ if (isRecord(raw))
395
+ lines.push("", `## ${String(raw.moduleRef)} @ ${String(raw.version)}`, JSON.stringify(raw.docs ?? {}, null, 2));
400
396
  return lines.join("\n");
401
397
  }
402
398
  export function renderHumanResult(result) {
403
- if (result.status === "FAILED") {
399
+ if (result.status === "FAILED")
404
400
  return `${result.command.toUpperCase()} FAILED${result.error ? ` [${result.error.code}] ${result.error.message}` : ""}`;
405
- }
406
- if (result.command === "help") {
401
+ if (result.command === "help")
407
402
  return [
408
403
  "ProFlow Platform CLI",
409
404
  "",
410
405
  ...COMMANDS.map((command) => `platform ${command}`),
411
406
  "",
412
407
  "platform install --workspace <path>",
408
+ "platform setup --module <moduleRef> --input '<json>'",
413
409
  "append --json for machine-readable output",
414
410
  ].join("\n");
415
- }
416
- if (result.command === "version" && isRecord(result.data)) {
411
+ if (result.command === "version" && isRecord(result.data))
417
412
  return String(result.data.version ?? platformCliDescriptor.moduleVersion);
418
- }
419
- if (result.command === "modules")
420
- return renderModules(result.data);
413
+ if (result.command === "status")
414
+ return renderStatus(result.data);
421
415
  if (result.command === "docs")
422
416
  return renderDocs(result.data);
423
417
  return [
@@ -10,8 +10,6 @@ export interface ResolvedModule {
10
10
  requires: ModuleDescriptor["requires"];
11
11
  requirements: ModuleRequirement[];
12
12
  configSlots: ConfigSlot[];
13
- lifecycle: string[];
14
- verification: ModuleDescriptor["verification"];
15
13
  effects: DeploymentEffect[];
16
14
  source: {
17
15
  type: "workspace" | "installed";
@@ -1,4 +1,3 @@
1
- import type { DeploymentAdapterBinding } from "../binding/production-bindings.ts";
2
1
  import type { ResolvedModule } from "../contracts.ts";
3
2
  import type { ModuleCatalog, ModuleSource } from "../modules.ts";
4
3
  export interface DiscoverOptions {
@@ -9,8 +8,7 @@ export interface DiscoverOptions {
9
8
  export declare class AutoModuleCatalog implements ModuleCatalog {
10
9
  private readonly workspace;
11
10
  private readonly installed;
12
- private readonly bindings;
13
- constructor(root?: string, bindings?: ReadonlyMap<string, DeploymentAdapterBinding>);
11
+ constructor(root?: string);
14
12
  sources(): Promise<ModuleSource[]>;
15
13
  loadDescriptor(source: ModuleSource): Promise<unknown>;
16
14
  loadAdapter(source: ModuleSource): Promise<unknown>;
@@ -7,11 +7,9 @@ import { readPackageJson } from "./workspace.js";
7
7
  export class AutoModuleCatalog {
8
8
  workspace;
9
9
  installed;
10
- bindings;
11
- constructor(root, bindings) {
10
+ constructor(root) {
12
11
  this.workspace = new WorkspaceModuleCatalog(root);
13
12
  this.installed = new InstalledModuleCatalog(root);
14
- this.bindings = bindings ?? new Map();
15
13
  }
16
14
  async sources() {
17
15
  const workspaceSources = await this.workspace.sources();
@@ -32,11 +30,6 @@ export class AutoModuleCatalog {
32
30
  : this.installed.loadDescriptor(source);
33
31
  }
34
32
  async loadAdapter(source) {
35
- // A production binder may supply a bound adapter for a service module
36
- // (createBehaviorAdapter(realService)); it wins over the unbound default.
37
- const binding = this.bindings.get(source.packageName);
38
- if (binding !== undefined)
39
- return binding;
40
33
  return source.type === "workspace"
41
34
  ? this.workspace.loadAdapter(source)
42
35
  : this.installed.loadAdapter(source);
@@ -96,8 +89,6 @@ function toResolvedModule(descriptor, source) {
96
89
  requires: descriptor.requires,
97
90
  requirements: descriptor.requirements,
98
91
  configSlots: descriptor.configSlots,
99
- lifecycle: descriptor.lifecycle.supported,
100
- verification: descriptor.verification,
101
92
  effects: descriptor.effects,
102
93
  source: resolvedSource,
103
94
  };
@@ -1,4 +1,4 @@
1
- export declare const platformErrorCodes: readonly ["INVALID_REQUEST", "DESCRIPTOR_INVALID", "DUPLICATE_IDENTITY", "DEPENDENCY_UNRESOLVED", "DEPENDENCY_INCOMPATIBLE", "DEPENDENCY_CYCLE", "CONFIG_INVALID", "WORKSPACE_NOT_FOUND", "WORKSPACE_INSTANCE_INVALID", "PACKAGE_MANAGER_UNSUPPORTED", "PACKAGE_MANAGER_CONFLICT", "PACKAGE_MANAGER_UNAVAILABLE", "LIFECYCLE_UNSUPPORTED", "UNINSTALL_FAILED", "REGISTRY_UNAVAILABLE", "REGISTRY_AUTH_REQUIRED", "REGISTRY_RESPONSE_INVALID", "PACKAGE_NOT_FOUND", "PACKAGE_NOT_PROFLOW", "COMMAND_FAILED"];
1
+ export declare const platformErrorCodes: readonly ["INVALID_REQUEST", "DESCRIPTOR_INVALID", "DUPLICATE_IDENTITY", "DEPENDENCY_UNRESOLVED", "DEPENDENCY_INCOMPATIBLE", "DEPENDENCY_CYCLE", "WORKSPACE_NOT_FOUND", "WORKSPACE_INSTANCE_INVALID", "PACKAGE_MANAGER_UNSUPPORTED", "PACKAGE_MANAGER_CONFLICT", "PACKAGE_MANAGER_UNAVAILABLE", "UNINSTALL_FAILED", "REGISTRY_UNAVAILABLE", "REGISTRY_AUTH_REQUIRED", "REGISTRY_RESPONSE_INVALID", "PACKAGE_NOT_FOUND", "PACKAGE_NOT_PROFLOW", "COMMAND_FAILED"];
2
2
  export type PlatformErrorCode = (typeof platformErrorCodes)[number];
3
3
  export declare class PlatformError extends Error {
4
4
  readonly code: PlatformErrorCode;
@@ -5,13 +5,11 @@ export const platformErrorCodes = [
5
5
  "DEPENDENCY_UNRESOLVED",
6
6
  "DEPENDENCY_INCOMPATIBLE",
7
7
  "DEPENDENCY_CYCLE",
8
- "CONFIG_INVALID",
9
8
  "WORKSPACE_NOT_FOUND",
10
9
  "WORKSPACE_INSTANCE_INVALID",
11
10
  "PACKAGE_MANAGER_UNSUPPORTED",
12
11
  "PACKAGE_MANAGER_CONFLICT",
13
12
  "PACKAGE_MANAGER_UNAVAILABLE",
14
- "LIFECYCLE_UNSUPPORTED",
15
13
  "UNINSTALL_FAILED",
16
14
  "REGISTRY_UNAVAILABLE",
17
15
  "REGISTRY_AUTH_REQUIRED",
@@ -1,8 +1,6 @@
1
1
  export type { CliOutcome, CliRuntimeOptions, CliStatus, } from "./cli.ts";
2
2
  export { renderHumanResult, runCli } from "./cli.ts";
3
3
  export { AutoModuleCatalog, discoverModules } from "./discovery/discover.ts";
4
- export type { AggregatedDocument, AggregatedModuleDocs, } from "./docs/aggregate.ts";
5
- export { aggregateModuleDocs } from "./docs/aggregate.ts";
6
4
  export type { PlatformErrorCode } from "./errors.ts";
7
5
  export { PlatformError } from "./errors.ts";
8
6
  export type { ModuleCatalog, ModuleSource } from "./modules.ts";
package/dist/src/index.js CHANGED
@@ -1,4 +1,3 @@
1
1
  export { renderHumanResult, runCli } from "./cli.js";
2
2
  export { AutoModuleCatalog, discoverModules } from "./discovery/discover.js";
3
- export { aggregateModuleDocs } from "./docs/aggregate.js";
4
3
  export { PlatformError } from "./errors.js";
@@ -1,17 +1,10 @@
1
- import { type LifecyclePrimitive, type ModuleOperationResult } from "@tomflow/proflow-module-contract";
1
+ import { type ModuleCommandContext, type ModuleManagementCommand, type ModuleOperationResult } from "@tomflow/proflow-module-contract";
2
2
  import type { ResolvedModule } from "../contracts.ts";
3
3
  import type { ModuleCatalog } from "../modules.ts";
4
- export interface LifecycleDispatchResult {
4
+ export interface ModuleDispatchResult {
5
5
  moduleRef: string;
6
- primitive: LifecyclePrimitive;
6
+ command: ModuleManagementCommand;
7
7
  result: ModuleOperationResult;
8
8
  observedEffects: string[];
9
9
  }
10
- /**
11
- * Dispatches a single lifecycle primitive against one module through its
12
- * public deployment adapter. The descriptor is the source of truth for what is
13
- * supported: a primitive not declared in `lifecycle` is rejected with
14
- * `LIFECYCLE_UNSUPPORTED` rather than faked. The adapter result is always
15
- * runtime-validated against the Module Operation Result schema.
16
- */
17
- export declare function dispatchLifecycle(catalog: ModuleCatalog, module: ResolvedModule, primitive: LifecyclePrimitive): Promise<LifecycleDispatchResult>;
10
+ export declare function dispatchModuleCommand(catalog: ModuleCatalog, module: ResolvedModule, command: ModuleManagementCommand, context: ModuleCommandContext): Promise<ModuleDispatchResult>;