@tomflow/proflow-platform-cli 0.1.12 → 0.1.14

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @tomflow/proflow-platform-cli
2
2
 
3
+ ## 0.1.14
4
+
5
+ ### Patch Changes
6
+
7
+ - Gate `platform start` on managed preflight, make platform-level `restart` a stop-then-start sequence without an extra preflight, and render lifecycle / verify / doctor results clearly for human users.
8
+
9
+ ## 0.1.13
10
+
11
+ ### Patch Changes
12
+
13
+ - Fully clean Workspace uninstall artifacts by removing empty ProFlow layout directories and stale pnpm release-age entries across prior managed versions.
14
+
3
15
  ## 0.1.12
4
16
 
5
17
  ### Patch Changes
@@ -5,7 +5,7 @@ export declare const behaviorAdapter: {
5
5
  ok: boolean;
6
6
  status: "SUCCEEDED";
7
7
  moduleRef: "platform-cli";
8
- moduleVersion: "0.1.12";
8
+ moduleVersion: "0.1.14";
9
9
  data?: {} | null;
10
10
  };
11
11
  observedEffects: never[];
@@ -16,7 +16,7 @@ export declare const behaviorAdapter: {
16
16
  ok: boolean;
17
17
  status: "SUCCEEDED";
18
18
  moduleRef: "platform-cli";
19
- moduleVersion: "0.1.12";
19
+ moduleVersion: "0.1.14";
20
20
  data?: {} | null;
21
21
  };
22
22
  observedEffects: never[];
@@ -27,7 +27,7 @@ export declare const behaviorAdapter: {
27
27
  ok: boolean;
28
28
  status: "SUCCEEDED";
29
29
  moduleRef: "platform-cli";
30
- moduleVersion: "0.1.12";
30
+ moduleVersion: "0.1.14";
31
31
  data?: {} | null;
32
32
  };
33
33
  observedEffects: never[];
@@ -38,7 +38,7 @@ export declare const behaviorAdapter: {
38
38
  ok: boolean;
39
39
  status: "SUCCEEDED";
40
40
  moduleRef: "platform-cli";
41
- moduleVersion: "0.1.12";
41
+ moduleVersion: "0.1.14";
42
42
  data?: {} | null;
43
43
  };
44
44
  observedEffects: never[];
@@ -49,7 +49,7 @@ export declare const behaviorAdapter: {
49
49
  ok: boolean;
50
50
  status: "SUCCEEDED";
51
51
  moduleRef: "platform-cli";
52
- moduleVersion: "0.1.12";
52
+ moduleVersion: "0.1.14";
53
53
  data?: {} | null;
54
54
  };
55
55
  observedEffects: never[];
@@ -3,7 +3,7 @@ export declare const descriptor: {
3
3
  readonly contractVersion: "1.0.0";
4
4
  readonly moduleRef: "platform-cli";
5
5
  readonly packageName: "@tomflow/proflow-platform-cli";
6
- readonly moduleVersion: "0.1.12";
6
+ readonly moduleVersion: "0.1.14";
7
7
  readonly kind: "cli";
8
8
  readonly templateVersion: "1.0.0";
9
9
  readonly platformCompatibility: ">=1.0.0 <2.0.0";
@@ -3,7 +3,7 @@ export const descriptor = {
3
3
  contractVersion: "1.0.0",
4
4
  moduleRef: "platform-cli",
5
5
  packageName: "@tomflow/proflow-platform-cli",
6
- moduleVersion: "0.1.12",
6
+ moduleVersion: "0.1.14",
7
7
  kind: "cli",
8
8
  templateVersion: "1.0.0",
9
9
  platformCompatibility: ">=1.0.0 <2.0.0",
@@ -22,8 +22,8 @@ export async function cleanupWorkspacePackageManagerArtifacts(options) {
22
22
  const manager = await readWorkspacePackageManagerSelection(options.workspaceRoot);
23
23
  if (manager.name !== "pnpm")
24
24
  return;
25
- const removedPackageSpecs = new Set(options.removedModules.map((module) => `${module.packageName}@${module.moduleVersion}`));
26
- await cleanupPnpmReleaseAgeExcludes(options.workspaceRoot, removedPackageSpecs);
25
+ const removedPackageNames = new Set(options.removedModules.map((module) => module.packageName));
26
+ await cleanupPnpmReleaseAgeExcludes(options.workspaceRoot, removedPackageNames);
27
27
  await normalizeEmptyPnpmRootImporter(options.workspaceRoot);
28
28
  }
29
29
  export function createWorkspacePackageManagerDriver(options) {
@@ -156,7 +156,7 @@ async function readWorkspaceManifest(workspaceRoot) {
156
156
  return undefined;
157
157
  }
158
158
  }
159
- async function cleanupPnpmReleaseAgeExcludes(workspaceRoot, removedPackageSpecs) {
159
+ async function cleanupPnpmReleaseAgeExcludes(workspaceRoot, removedPackageNames) {
160
160
  const path = join(workspaceRoot, "pnpm-workspace.yaml");
161
161
  let raw;
162
162
  try {
@@ -181,7 +181,11 @@ async function cleanupPnpmReleaseAgeExcludes(workspaceRoot, removedPackageSpecs)
181
181
  if (match === null)
182
182
  return true;
183
183
  const value = stripYamlQuotes(match[1] ?? "");
184
- return !removedPackageSpecs.has(value);
184
+ for (const packageName of removedPackageNames) {
185
+ if (value === packageName || value.startsWith(`${packageName}@`))
186
+ return false;
187
+ }
188
+ return true;
185
189
  });
186
190
  const hasListItem = retained.some((line) => /^\s*-\s+/.test(line));
187
191
  const replacement = hasListItem ? [lines[keyIndex] ?? "", ...retained] : [];
package/dist/src/cli.js CHANGED
@@ -855,15 +855,26 @@ async function handlePlatformInstanceUninstall(args, runtime) {
855
855
  // into a future install of the same directory. Business/domain data outside
856
856
  // `.proflow/deployment` is intentionally preserved.
857
857
  await rm(ctx.paths.deployment, { recursive: true, force: true });
858
- try {
859
- await rmdir(ctx.paths.proflow);
860
- }
861
- catch (error) {
862
- const code = typeof error === "object" && error !== null
863
- ? Reflect.get(error, "code")
864
- : undefined;
865
- if (code !== "ENOENT" && code !== "ENOTEMPTY")
866
- throw error;
858
+ for (const path of [
859
+ ctx.paths.logsDeployment,
860
+ ctx.paths.logs,
861
+ ctx.paths.config,
862
+ ctx.paths.data,
863
+ ctx.paths.runtime,
864
+ ctx.paths.cache,
865
+ ctx.paths.tmp,
866
+ ctx.paths.proflow,
867
+ ]) {
868
+ try {
869
+ await rmdir(path);
870
+ }
871
+ catch (error) {
872
+ const code = typeof error === "object" && error !== null
873
+ ? Reflect.get(error, "code")
874
+ : undefined;
875
+ if (code !== "ENOENT" && code !== "ENOTEMPTY")
876
+ throw error;
877
+ }
867
878
  }
868
879
  const completed = binding;
869
880
  await clearGlobalBinding({
@@ -896,6 +907,12 @@ async function handlePlatformInstanceUninstall(args, runtime) {
896
907
  }
897
908
  }
898
909
  async function handleLifecycle(ctx, args, primitive) {
910
+ if (primitive === "start") {
911
+ const preflight = await handlePreflight(ctx, args);
912
+ if (preflight.status !== "SUCCEEDED") {
913
+ return outcome("start", preflight.status, preflight.data);
914
+ }
915
+ }
899
916
  const modules = await discoverModules({ catalog: ctx.catalog });
900
917
  const selected = selectModules(modules, args.positional[0]);
901
918
  const result = primitive === "start"
@@ -1171,7 +1188,82 @@ function toMachineResult(outcomeResult) {
1171
1188
  function isRecord(value) {
1172
1189
  return typeof value === "object" && value !== null && !Array.isArray(value);
1173
1190
  }
1191
+ function humanArrayLines(data) {
1192
+ const isVerification = data.some((item) => isRecord(item) && isRecord(item.record));
1193
+ const isDoctor = data.some((item) => isRecord(item) && Array.isArray(item.errors) && isRecord(item.nextAction));
1194
+ const lines = [
1195
+ isVerification ? "Verification:" : isDoctor ? "Doctor:" : "Lifecycle:",
1196
+ ];
1197
+ let skippedUnsupported = 0;
1198
+ for (const item of data) {
1199
+ if (!isRecord(item))
1200
+ continue;
1201
+ const moduleRef = typeof item.moduleRef === "string" ? item.moduleRef : "unknown";
1202
+ const runStatus = typeof item.status === "string" ? item.status : "UNKNOWN";
1203
+ if (runStatus === "SKIP_UNSUPPORTED") {
1204
+ skippedUnsupported += 1;
1205
+ continue;
1206
+ }
1207
+ const result = isRecord(item.result) ? item.result : undefined;
1208
+ const resultStatus = result !== undefined && typeof result.status === "string"
1209
+ ? result.status
1210
+ : runStatus;
1211
+ let detail = "";
1212
+ const actionRequired = result !== undefined && isRecord(result.actionRequired)
1213
+ ? result.actionRequired
1214
+ : undefined;
1215
+ const error = result !== undefined && isRecord(result.error) ? result.error : undefined;
1216
+ if (actionRequired !== undefined) {
1217
+ const action = typeof actionRequired.action === "string"
1218
+ ? actionRequired.action
1219
+ : "action-required";
1220
+ const description = typeof actionRequired.description === "string"
1221
+ ? actionRequired.description
1222
+ : "human action required";
1223
+ detail = ` — ${action}: ${description}`;
1224
+ }
1225
+ else if (error !== undefined) {
1226
+ const code = typeof error.code === "string" ? error.code : "COMMAND_FAILED";
1227
+ const message = typeof error.message === "string" ? error.message : "Unknown error";
1228
+ detail = ` — ${code}: ${message}`;
1229
+ }
1230
+ else if (isRecord(item.record) &&
1231
+ typeof item.record.summary === "string") {
1232
+ detail = ` — ${item.record.summary}`;
1233
+ }
1234
+ lines.push(`- ${moduleRef}: ${resultStatus}${detail}`);
1235
+ if (Array.isArray(item.errors)) {
1236
+ for (const doctorError of item.errors) {
1237
+ if (!isRecord(doctorError))
1238
+ continue;
1239
+ const code = typeof doctorError.code === "string"
1240
+ ? doctorError.code
1241
+ : "COMMAND_FAILED";
1242
+ const message = typeof doctorError.message === "string"
1243
+ ? doctorError.message
1244
+ : "Unknown error";
1245
+ lines.push(` Error: ${code}: ${message}`);
1246
+ }
1247
+ }
1248
+ if (isRecord(item.nextAction)) {
1249
+ if (item.nextAction.kind === "human-action" &&
1250
+ typeof item.nextAction.action === "string" &&
1251
+ typeof item.nextAction.description === "string") {
1252
+ lines.push(` Next: ${item.nextAction.action} — ${item.nextAction.description}`);
1253
+ }
1254
+ else if (item.nextAction.kind === "repair-plan" &&
1255
+ typeof item.nextAction.summary === "string") {
1256
+ lines.push(` Next: platform plan --intent repair — ${item.nextAction.summary}`);
1257
+ }
1258
+ }
1259
+ }
1260
+ if (skippedUnsupported > 0)
1261
+ lines.push(`Skipped unsupported: ${skippedUnsupported}`);
1262
+ return lines;
1263
+ }
1174
1264
  function humanDetailLines(data) {
1265
+ if (Array.isArray(data))
1266
+ return humanArrayLines(data);
1175
1267
  if (!isRecord(data)) {
1176
1268
  return data === undefined ? [] : [String(data)];
1177
1269
  }
@@ -34,9 +34,10 @@ export declare function startModules(catalog: ModuleCatalog, modules: readonly R
34
34
  */
35
35
  export declare function stopModules(catalog: ModuleCatalog, modules: readonly ResolvedModule[]): Promise<LifecycleRunResult[]>;
36
36
  /**
37
- * Restarts a module set in forward dependency topological order, dispatching
38
- * `restart` only to modules that explicitly declare it. Dependencies are
39
- * settled before the modules that consume them.
37
+ * Restarts a module set as a platform-level stop start sequence. Stop runs in
38
+ * reverse dependency order; only after every executed stop succeeds does start
39
+ * run in forward dependency order with the same dependency blocking rules as a
40
+ * normal start. Module-native `restart` primitives are not used here.
40
41
  */
41
42
  export declare function restartModules(catalog: ModuleCatalog, modules: readonly ResolvedModule[]): Promise<LifecycleRunResult[]>;
42
43
  /**
@@ -172,12 +172,17 @@ export async function stopModules(catalog, modules) {
172
172
  return runInOrder(catalog, modules, order, "stop");
173
173
  }
174
174
  /**
175
- * Restarts a module set in forward dependency topological order, dispatching
176
- * `restart` only to modules that explicitly declare it. Dependencies are
177
- * settled before the modules that consume them.
175
+ * Restarts a module set as a platform-level stop start sequence. Stop runs in
176
+ * reverse dependency order; only after every executed stop succeeds does start
177
+ * run in forward dependency order with the same dependency blocking rules as a
178
+ * normal start. Module-native `restart` primitives are not used here.
178
179
  */
179
180
  export async function restartModules(catalog, modules) {
180
- return runInOrder(catalog, modules, buildDependencyGraph(modules).order, "restart");
181
+ const stopped = await stopModules(catalog, modules);
182
+ const stopBlocked = stopped.some((item) => item.result !== undefined && item.result.status !== "SUCCEEDED");
183
+ if (stopBlocked)
184
+ return stopped;
185
+ return startModules(catalog, modules);
181
186
  }
182
187
  /**
183
188
  * Queries current reality by dispatching the `status` primitive to every
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomflow/proflow-platform-cli",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -24,8 +24,8 @@
24
24
  "@tomflow/proflow-module-contract": "^0.1.1"
25
25
  },
26
26
  "devDependencies": {
27
- "@tomflow/proflow-module-template": "^0.1.2",
28
- "@tomflow/proflow-deployment-conformance": "^0.1.2"
27
+ "@tomflow/proflow-deployment-conformance": "^0.1.2",
28
+ "@tomflow/proflow-module-template": "^0.1.2"
29
29
  },
30
30
  "description": "Deterministic platform-level deployment discovery, planning, lifecycle and verification CLI.",
31
31
  "keywords": [
@@ -3,7 +3,7 @@
3
3
  "contractVersion": "1.0.0",
4
4
  "moduleRef": "platform-cli",
5
5
  "packageName": "@tomflow/proflow-platform-cli",
6
- "moduleVersion": "0.1.12",
6
+ "moduleVersion": "0.1.14",
7
7
  "kind": "cli",
8
8
  "templateVersion": "1.0.0",
9
9
  "platformCompatibility": ">=1.0.0 <2.0.0",