@powerhousedao/ph-cli 6.2.3-dev.2 → 6.2.3-dev.20

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 (56) hide show
  1. package/dist/{build-uQXq6_HU.mjs → build-BM7yZxAf.mjs} +68 -8
  2. package/dist/build-BM7yZxAf.mjs.map +1 -0
  3. package/dist/build-D4-3Ks7v.mjs +4 -0
  4. package/dist/{cli-connect-override-D3hh4aH_.mjs → cli-connect-override-BJ5mgqM1.mjs} +46 -9
  5. package/dist/cli-connect-override-BJ5mgqM1.mjs.map +1 -0
  6. package/dist/cli.mjs +172 -22
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/connect-build-DNQgVniR.mjs +149 -0
  9. package/dist/connect-build-DNQgVniR.mjs.map +1 -0
  10. package/dist/{connect-config-BWGiW3IB.mjs → connect-config-C3sDVZ59.mjs} +7 -6
  11. package/dist/connect-config-C3sDVZ59.mjs.map +1 -0
  12. package/dist/{connect-studio-D6rfWCNB.mjs → connect-studio-oKEsKMZg.mjs} +4 -4
  13. package/dist/{connect-studio-D6rfWCNB.mjs.map → connect-studio-oKEsKMZg.mjs.map} +1 -1
  14. package/dist/connect-studio-xE1Tr6KS.mjs +5 -0
  15. package/dist/generate-piece-B8Kbsshu.mjs +61 -0
  16. package/dist/generate-piece-B8Kbsshu.mjs.map +1 -0
  17. package/dist/generate-piece-action-DZ14j8Gi.mjs +26 -0
  18. package/dist/generate-piece-action-DZ14j8Gi.mjs.map +1 -0
  19. package/dist/generate-piece-trigger-CvzZOIPh.mjs +27 -0
  20. package/dist/generate-piece-trigger-CvzZOIPh.mjs.map +1 -0
  21. package/dist/{generate-processor-_WOx-mMe.mjs → generate-processor-BK7moaDe.mjs} +3 -3
  22. package/dist/{generate-processor-_WOx-mMe.mjs.map → generate-processor-BK7moaDe.mjs.map} +1 -1
  23. package/dist/{generate-subgraph-BsHUstpl.mjs → generate-subgraph-CCXHyg4b.mjs} +3 -3
  24. package/dist/{generate-subgraph-BsHUstpl.mjs.map → generate-subgraph-CCXHyg4b.mjs.map} +1 -1
  25. package/dist/{init-BZP6gvYd.mjs → init-B3Tp7X17.mjs} +4 -4
  26. package/dist/{init-BZP6gvYd.mjs.map → init-B3Tp7X17.mjs.map} +1 -1
  27. package/dist/{inspect-DXjbQEV_.mjs → inspect-B8eX-XPA.mjs} +11 -4
  28. package/dist/inspect-B8eX-XPA.mjs.map +1 -0
  29. package/dist/{migrate-jGKfE02L.mjs → migrate-CM_3Luws.mjs} +3 -3
  30. package/dist/{migrate-jGKfE02L.mjs.map → migrate-CM_3Luws.mjs.map} +1 -1
  31. package/dist/{registry-auth-DxEWCJu2.mjs → registry-auth-C9en-6FX.mjs} +3 -3
  32. package/dist/{registry-auth-DxEWCJu2.mjs.map → registry-auth-C9en-6FX.mjs.map} +1 -1
  33. package/dist/scripts/generate-commands-docs.ts +8 -0
  34. package/dist/{switchboard-CJMoMzWx.mjs → switchboard-Cabg_xYF.mjs} +3 -3
  35. package/dist/{switchboard-CJMoMzWx.mjs.map → switchboard-Cabg_xYF.mjs.map} +1 -1
  36. package/dist/switchboard-DTJkt8lG.mjs +4 -0
  37. package/dist/{switchboard-migrate-NQ7LHWSi.mjs → switchboard-migrate-RN3lGK4Q.mjs} +3 -3
  38. package/dist/{switchboard-migrate-NQ7LHWSi.mjs.map → switchboard-migrate-RN3lGK4Q.mjs.map} +1 -1
  39. package/dist/{switchboard-reset-BcQXlcVf.mjs → switchboard-reset-BWLfgYuv.mjs} +3 -3
  40. package/dist/{switchboard-reset-BcQXlcVf.mjs.map → switchboard-reset-BWLfgYuv.mjs.map} +1 -1
  41. package/dist/{utils-BzwczAW-.mjs → utils-B6flWWiG.mjs} +3 -3
  42. package/dist/{utils-C4isxXSO.mjs → utils-jTHrApMW.mjs} +3 -3
  43. package/dist/{utils-C4isxXSO.mjs.map → utils-jTHrApMW.mjs.map} +1 -1
  44. package/dist/{vetra-DkF6EJMY.mjs → vetra-DCD3t7Qh.mjs} +24 -14
  45. package/dist/vetra-DCD3t7Qh.mjs.map +1 -0
  46. package/package.json +12 -11
  47. package/dist/build-C-A5-ipO.mjs +0 -4
  48. package/dist/build-uQXq6_HU.mjs.map +0 -1
  49. package/dist/cli-connect-override-D3hh4aH_.mjs.map +0 -1
  50. package/dist/connect-build-WL4axo4z.mjs +0 -43
  51. package/dist/connect-build-WL4axo4z.mjs.map +0 -1
  52. package/dist/connect-config-BWGiW3IB.mjs.map +0 -1
  53. package/dist/connect-studio-BIQzyq5B.mjs +0 -5
  54. package/dist/inspect-DXjbQEV_.mjs.map +0 -1
  55. package/dist/switchboard-iRFugh8I.mjs +0 -4
  56. package/dist/vetra-DkF6EJMY.mjs.map +0 -1
@@ -1,8 +1,10 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a81d56d6-7b6c-5288-ac91-899d56570def")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="77b90ef5-8c73-5383-af68-d361a5f4c32f")}catch(e){}}();
3
3
  import { execSync } from "node:child_process";
4
- import { browserBuildConfig, nodeBuildConfig } from "@powerhousedao/shared/build-config";
5
- import { existsSync, readFileSync } from "node:fs";
4
+ import { browserEntry, buildBrowserBuildConfig, buildNodeBuildConfig, findBundledSharedDeps } from "@powerhousedao/shared/build-config";
5
+ import { assertPiecesOutDir, buildPieces, expandEntryGlobs, pieceListPath, planPieces, syncDistManifest } from "@powerhousedao/shared/build-pieces";
6
+ import { EXTERNALIZABLE_SHARED_SPECIFIERS, findSharedImports } from "@powerhousedao/shared/connect";
7
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
6
8
  import { join } from "node:path";
7
9
  import { detect, resolveCommand } from "package-manager-detector";
8
10
  import { readPackage } from "read-pkg";
@@ -29,15 +31,37 @@ async function assertManifestNameMatchesPackage(projectPath) {
29
31
  }
30
32
  async function runBuild(args) {
31
33
  const { outDir } = args;
32
- await assertManifestNameMatchesPackage(process.cwd());
34
+ const projectRoot = process.cwd();
35
+ await assertManifestNameMatchesPackage(projectRoot);
36
+ const target = {
37
+ projectRoot,
38
+ outDir,
39
+ pieces: planPieces(projectRoot, outDir)
40
+ };
41
+ assertPiecesOutDir(target);
42
+ const sharedDeps = !args.noSharedDeps;
33
43
  await build({
34
- ...browserBuildConfig,
44
+ ...buildBrowserBuildConfig({ sharedDeps }),
35
45
  outDir: join(outDir, "browser")
36
46
  });
47
+ if (sharedDeps) {
48
+ const bundled = findBundledSharedDeps(findSharedImportsInSources(projectRoot, browserEntry), readDistBrowserFiles(join(outDir, "browser")));
49
+ if (bundled.length > 0) console.warn(`⚠ shared deps bundled instead of externalized: ${bundled.join(", ")} — check your neverBundle config`);
50
+ }
37
51
  await build({
38
- ...nodeBuildConfig,
52
+ ...buildNodeBuildConfig({ sharedDeps }),
39
53
  outDir: join(outDir, "node")
40
54
  });
55
+ let built = [];
56
+ if (existsSync(pieceListPath(target))) {
57
+ const pkg = await readPackage({ cwd: projectRoot });
58
+ built = await buildPieces(target, {
59
+ name: pkg.name,
60
+ version: pkg.version,
61
+ license: typeof pkg.license === "string" ? pkg.license : void 0
62
+ }, { bundle: build });
63
+ }
64
+ syncDistManifest(target, built);
41
65
  const agent = (await detect())?.agent ?? "npm";
42
66
  const tscCommand = resolveCommand(agent, "execute-local", ["tsc", "--build"]);
43
67
  if (tscCommand === null) {
@@ -64,8 +88,44 @@ async function runBuild(args) {
64
88
  }
65
89
  execSync(`${executeLocalCommand.command} ${executeLocalCommand.args.join(" ")}`);
66
90
  }
91
+ /**
92
+ * Every shared specifier imported from the entry sources; the post-build
93
+ * scan compares these against the built output.
94
+ *
95
+ * Scoped to the specifiers the build actually externalizes: a specifier the
96
+ * vendor does not publish (the bare `@powerhousedao/shared` root, an
97
+ * unvendored subpath) is deliberately bundled, so reporting it as "bundled
98
+ * instead of externalized" would be a false alarm.
99
+ */
100
+ function findSharedImportsInSources(root, globs) {
101
+ const found = /* @__PURE__ */ new Set();
102
+ for (const file of expandEntryGlobs(root, globs)) {
103
+ const src = readFileSync(file, "utf8");
104
+ for (const spec of findSharedImports(src, EXTERNALIZABLE_SHARED_SPECIFIERS)) found.add(spec);
105
+ }
106
+ return [...found].sort();
107
+ }
108
+ /**
109
+ * The built JS outputs of a browser build (entry files and chunks).
110
+ */
111
+ function readDistBrowserFiles(dir) {
112
+ const out = [];
113
+ if (!existsSync(dir)) return out;
114
+ const walk = (d) => {
115
+ for (const e of readdirSync(d, { withFileTypes: true })) {
116
+ const p = join(d, e.name);
117
+ if (e.isDirectory()) walk(p);
118
+ else if (e.isFile() && e.name.endsWith(".js")) out.push({
119
+ path: p,
120
+ content: readFileSync(p, "utf8")
121
+ });
122
+ }
123
+ };
124
+ walk(dir);
125
+ return out;
126
+ }
67
127
  //#endregion
68
128
  export { runBuild as n, assertManifestNameMatchesPackage as t };
69
129
 
70
- //# sourceMappingURL=build-uQXq6_HU.mjs.map
71
- //# debugId=a81d56d6-7b6c-5288-ac91-899d56570def
130
+ //# sourceMappingURL=build-BM7yZxAf.mjs.map
131
+ //# debugId=77b90ef5-8c73-5383-af68-d361a5f4c32f
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-BM7yZxAf.mjs","sources":["../src/services/build.ts"],"sourcesContent":["import {\n browserEntry,\n buildBrowserBuildConfig,\n buildNodeBuildConfig,\n findBundledSharedDeps,\n} from \"@powerhousedao/shared/build-config\";\nimport type { BuiltPiece } from \"@powerhousedao/shared/build-pieces\";\nimport {\n assertPiecesOutDir,\n buildPieces,\n expandEntryGlobs,\n pieceListPath,\n planPieces,\n syncDistManifest,\n} from \"@powerhousedao/shared/build-pieces\";\nimport {\n findSharedImports,\n EXTERNALIZABLE_SHARED_SPECIFIERS,\n} from \"@powerhousedao/shared/connect\";\nimport { execSync } from \"node:child_process\";\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { detect, resolveCommand } from \"package-manager-detector\";\nimport { readPackage } from \"read-pkg\";\nimport { build as tsdownBuild } from \"tsdown\";\nimport type { BuildArgs } from \"../types.js\";\n\n/**\n * A Powerhouse package's `powerhouse.manifest.json` \"name\" must match its\n * `package.json` \"name\" — Connect and the registry resolve installed versions\n * by treating the manifest name as the npm package name, so a mismatch silently\n * breaks resolution. Fail the build early if they diverge. No-op when the\n * project has no manifest (nothing to compare).\n */\nexport async function assertManifestNameMatchesPackage(projectPath: string) {\n const manifestPath = join(projectPath, \"powerhouse.manifest.json\");\n if (!existsSync(manifestPath)) return;\n\n const { name: packageName } = await readPackage({ cwd: projectPath });\n\n let manifestName: unknown;\n try {\n manifestName = (\n JSON.parse(readFileSync(manifestPath, \"utf-8\")) as { name?: unknown }\n ).name;\n } catch {\n throw new Error(\n `Failed to parse \"powerhouse.manifest.json\" at ${manifestPath}. Make sure it is valid JSON.`,\n );\n }\n\n if (manifestName !== packageName) {\n throw new Error(\n `Package name mismatch — \"package.json\" and \"powerhouse.manifest.json\" must have the same \"name\":\\n` +\n ` package.json \"name\": ${JSON.stringify(packageName)}\\n` +\n ` powerhouse.manifest.json \"name\": ${JSON.stringify(manifestName)}\\n\\n` +\n `Update one so they match, then run the build again.`,\n );\n }\n}\n\nexport async function runBuild(args: BuildArgs) {\n const { outDir } = args;\n const projectRoot = process.cwd();\n\n // Fail fast if the manifest name and package.json name have drifted apart.\n await assertManifestNameMatchesPackage(projectRoot);\n\n const target = {\n projectRoot,\n outDir,\n pieces: planPieces(projectRoot, outDir),\n };\n // Before any bundler runs: an out-dir a host will never read from is worth\n // nothing built, and the failure names what the contract is.\n assertPiecesOutDir(target);\n const sharedDeps = !args.noSharedDeps;\n\n await tsdownBuild({\n ...buildBrowserBuildConfig({ sharedDeps }),\n outDir: join(outDir, \"browser\"),\n });\n\n // Advisory: a shared dep the source imports but the output no longer\n // references as a bare import was inlined despite the external set.\n if (sharedDeps) {\n const imported = findSharedImportsInSources(projectRoot, browserEntry);\n const bundled = findBundledSharedDeps(\n imported,\n readDistBrowserFiles(join(outDir, \"browser\")),\n );\n if (bundled.length > 0) {\n console.warn(\n `⚠ shared deps bundled instead of externalized: ${bundled.join(\", \")} — check your neverBundle config`,\n );\n }\n }\n\n await tsdownBuild({\n ...buildNodeBuildConfig({ sharedDeps }),\n outDir: join(outDir, \"node\"),\n });\n\n // After the node build: it cleans <outDir>/node, where the pieces land. The\n // built list is the gate, so a `bundle:` entry is validated with no piece dir.\n let built: BuiltPiece[] = [];\n if (existsSync(pieceListPath(target))) {\n const pkg = await readPackage({ cwd: projectRoot });\n built = await buildPieces(\n target,\n {\n name: pkg.name,\n version: pkg.version,\n license: typeof pkg.license === \"string\" ? pkg.license : undefined,\n },\n { bundle: tsdownBuild },\n );\n }\n syncDistManifest(target, built);\n\n const detectResult = await detect();\n const agent = detectResult?.agent ?? \"npm\";\n\n // Emit types with tsc\n const tscCommand = resolveCommand(agent, \"execute-local\", [\"tsc\", \"--build\"]);\n if (tscCommand === null) {\n console.error(\n \"You need to have typescript installed to use the `build` command.\",\n );\n process.exit(1);\n }\n console.log(\"\\n▶ Emitting types via tsc...\");\n try {\n execSync(`${tscCommand.command} ${tscCommand.args.join(\" \")}`, {\n stdio: \"inherit\",\n });\n console.log(\"✔ Types emitted to\", join(outDir, \"types\"));\n } catch {\n console.warn(\n \"✘ tsc reported errors above; declarations were still written. Fix the errors to keep types accurate.\",\n );\n }\n\n const executeLocalCommand = resolveCommand(agent, \"execute-local\", [\n \"tailwindcss\",\n \"-i\",\n \"./style.css\",\n \"-o\",\n \"./dist/style.css\",\n ]);\n if (executeLocalCommand === null) {\n console.error(\n \"You need to have tailwindcss installed to use the `build` command.\",\n );\n process.exit(1);\n }\n execSync(\n `${executeLocalCommand.command} ${executeLocalCommand.args.join(\" \")}`,\n );\n}\n\n/**\n * Every shared specifier imported from the entry sources; the post-build\n * scan compares these against the built output.\n *\n * Scoped to the specifiers the build actually externalizes: a specifier the\n * vendor does not publish (the bare `@powerhousedao/shared` root, an\n * unvendored subpath) is deliberately bundled, so reporting it as \"bundled\n * instead of externalized\" would be a false alarm.\n */\nfunction findSharedImportsInSources(root: string, globs: string[]): string[] {\n const found = new Set<string>();\n for (const file of expandEntryGlobs(root, globs)) {\n const src = readFileSync(file, \"utf8\");\n for (const spec of findSharedImports(\n src,\n EXTERNALIZABLE_SHARED_SPECIFIERS,\n )) {\n found.add(spec);\n }\n }\n return [...found].sort();\n}\n\n/**\n * The built JS outputs of a browser build (entry files and chunks).\n */\nfunction readDistBrowserFiles(\n dir: string,\n): { path: string; content: string }[] {\n const out: { path: string; content: string }[] = [];\n if (!existsSync(dir)) return out;\n const walk = (d: string) => {\n for (const e of readdirSync(d, { withFileTypes: true })) {\n const p = join(d, e.name);\n if (e.isDirectory()) walk(p);\n else if (e.isFile() && e.name.endsWith(\".js\")) {\n out.push({ path: p, content: readFileSync(p, \"utf8\") });\n }\n }\n };\n walk(dir);\n return out;\n}\n"],"names":["tsdownBuild"],"mappings":"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","debug_id":"77b90ef5-8c73-5383-af68-d361a5f4c32f"}
@@ -0,0 +1,4 @@
1
+ import { n as runBuild } from "./build-BM7yZxAf.mjs";
2
+ export { runBuild };
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="703b12bd-5a5f-549f-a381-fd48bfa4da4b")}catch(e){}}();
4
+ //# debugId=703b12bd-5a5f-549f-a381-fd48bfa4da4b
@@ -1,8 +1,32 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1cfb2ec9-21ac-545a-a4fa-c392fd478bc4")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="263d4ba3-af66-597b-ae25-c655ce397a4a")}catch(e){}}();
3
3
  import { deepMerge, phConnectRuntimeConfigSchema } from "@powerhousedao/shared/connect";
4
4
  import AjvNs from "ajv";
5
5
  import { isPlainObject, stringToPath } from "remeda";
6
+ //#region src/utils/merge-default-drives.ts
7
+ function isLocalDrive(drive) {
8
+ return "local" in drive;
9
+ }
10
+ const driveKey = (drive) => isLocalDrive(drive) ? `local:${drive.id}` : drive.url;
11
+ /**
12
+ * Concatenate groups of `connect.drives.defaultDrives` in the order given,
13
+ * de-duplicating by drive identity (URL for remote entries, id for local
14
+ * ones). The first occurrence of a drive wins, so earlier groups keep their
15
+ * position and metadata — e.g. the Vetra drive `ph vetra` starts stays first
16
+ * even when the project's `powerhouse.config.json` lists the same drive.
17
+ */
18
+ function mergeDefaultDrives(...groups) {
19
+ const seen = /* @__PURE__ */ new Set();
20
+ const out = [];
21
+ for (const group of groups) for (const drive of group) {
22
+ const key = driveKey(drive);
23
+ if (seen.has(key)) continue;
24
+ seen.add(key);
25
+ out.push(drive);
26
+ }
27
+ return out;
28
+ }
29
+ //#endregion
6
30
  //#region src/utils/connect-config-validation.ts
7
31
  const validateConnect = new (AjvNs.default ?? AjvNs)({
8
32
  allErrors: true,
@@ -132,7 +156,7 @@ function wasFlagExplicitlyPassed(longName) {
132
156
  return process.argv.some((arg) => arg === dashed || arg.startsWith(`${dashed}=`));
133
157
  }
134
158
  /**
135
- * Build a `connect.*` partial from the 19 field flags. Only includes paths
159
+ * Build a `connect.*` partial from the 20 field flags. Only includes paths
136
160
  * the user explicitly set (undefined values are excluded).
137
161
  *
138
162
  * Single source of truth for the flag → JSON-path mapping; consumed by both
@@ -143,6 +167,7 @@ function buildConnectFlagPatch(args) {
143
167
  const app = {};
144
168
  setIfDefined(app, "basePath", args.basePath);
145
169
  setIfDefined(app, "logLevel", args.logLevel);
170
+ setIfDefined(app, "workflowsEnabled", args.workflows);
146
171
  if (Object.keys(app).length > 0) out.app = app;
147
172
  const renown = {};
148
173
  setIfDefined(renown, "url", args.renownUrl);
@@ -210,6 +235,7 @@ function buildCliConnectOverride(args) {
210
235
  renownSwitchboardUrl: args.renownSwitchboardUrl,
211
236
  allowAddDrive: args.allowAddDrive,
212
237
  externalPackages: args.externalPackages,
238
+ workflows: args.workflows,
213
239
  remoteDrivesEnabled: args.remoteDrivesEnabled,
214
240
  remoteDrivesAllowAdd: args.remoteDrivesAllowAdd,
215
241
  remoteDrivesAllowDelete: args.remoteDrivesAllowDelete,
@@ -258,11 +284,15 @@ function buildCliConnectOverride(args) {
258
284
  * `callerOverride` is supplied by wrappers around studio (notably `ph vetra`,
259
285
  * which sets default drives + preserveStrategy directly). The flag override
260
286
  * deep-merges on top of it: caller choices apply for every flag the user
261
- * didn't type, but an explicitly passed flag (e.g. `--default-drives-url`)
262
- * always wins.
287
+ * didn't type, and an explicitly passed flag wins for its own field —
288
+ * except `drives.defaultDrives`, which merges additively: a flag's drives
289
+ * are appended to the caller's list (de-duplicated by drive identity) rather
290
+ * than replacing it, so vetra's own drives stay in Connect's default set.
291
+ * Without a caller override (plain `ph connect studio`) only the flag can
292
+ * carry defaultDrives, so that command's behavior is unchanged.
263
293
  */
264
294
  function buildStudioConnectOverride(args, callerOverride) {
265
- return [
295
+ const layers = [
266
296
  callerOverride,
267
297
  buildConnectFlagPatch({
268
298
  basePath: wasFlagExplicitlyPassed("base") ? args.connectBasePath : void 0,
@@ -272,10 +302,17 @@ function buildStudioConnectOverride(args, callerOverride) {
272
302
  renownNamespace: args.renownNamespace
273
303
  }),
274
304
  { app: { studioMode: true } }
275
- ].filter((o) => o !== void 0 && Object.keys(o).length > 0).reduce((acc, o) => deepMerge(acc, o), {});
305
+ ].filter((o) => o !== void 0 && Object.keys(o).length > 0);
306
+ const merged = layers.reduce((acc, o) => deepMerge(acc, o), {});
307
+ const driveGroups = layers.map((l) => l.drives?.defaultDrives).filter((d) => Array.isArray(d) && d.length > 0);
308
+ if (driveGroups.length > 1) merged.drives = {
309
+ ...merged.drives,
310
+ defaultDrives: mergeDefaultDrives(...driveGroups)
311
+ };
312
+ return merged;
276
313
  }
277
314
  //#endregion
278
- export { parseDefaultDrivesUrl as a, validateConnectKeyValue as c, wasFlagExplicitlyPassed as i, validateConnectPatch as l, buildConnectFlagPatch as n, normalizeKey as o, buildStudioConnectOverride as r, parseCliValue as s, buildCliConnectOverride as t };
315
+ export { parseDefaultDrivesUrl as a, validateConnectKeyValue as c, wasFlagExplicitlyPassed as i, validateConnectPatch as l, buildConnectFlagPatch as n, normalizeKey as o, buildStudioConnectOverride as r, parseCliValue as s, buildCliConnectOverride as t, mergeDefaultDrives as u };
279
316
 
280
- //# sourceMappingURL=cli-connect-override-D3hh4aH_.mjs.map
281
- //# debugId=1cfb2ec9-21ac-545a-a4fa-c392fd478bc4
317
+ //# sourceMappingURL=cli-connect-override-BJ5mgqM1.mjs.map
318
+ //# debugId=263d4ba3-af66-597b-ae25-c655ce397a4a
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-connect-override-BJ5mgqM1.mjs","sources":["../src/utils/merge-default-drives.ts","../src/utils/connect-config-validation.ts","../src/utils/parse-default-drives.ts","../src/utils/cli-connect-override.ts"],"sourcesContent":["import type { PHConnectDefaultDrive } from \"@powerhousedao/shared/clis\";\n\nfunction isLocalDrive(\n drive: PHConnectDefaultDrive,\n): drive is Extract<PHConnectDefaultDrive, { local: true }> {\n return \"local\" in drive;\n}\n\n// Identity key for de-duplication: remote entries are keyed by URL; local\n// entries are keyed by `local:<id>` so a local drive id can never collide\n// with a remote URL that happens to be the same string.\nconst driveKey = (drive: PHConnectDefaultDrive): string =>\n isLocalDrive(drive) ? `local:${drive.id}` : drive.url;\n\n/**\n * Concatenate groups of `connect.drives.defaultDrives` in the order given,\n * de-duplicating by drive identity (URL for remote entries, id for local\n * ones). The first occurrence of a drive wins, so earlier groups keep their\n * position and metadata — e.g. the Vetra drive `ph vetra` starts stays first\n * even when the project's `powerhouse.config.json` lists the same drive.\n */\nexport function mergeDefaultDrives(\n ...groups: PHConnectDefaultDrive[][]\n): PHConnectDefaultDrive[] {\n const seen = new Set<string>();\n const out: PHConnectDefaultDrive[] = [];\n for (const group of groups) {\n for (const drive of group) {\n const key = driveKey(drive);\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(drive);\n }\n }\n return out;\n}\n","// Ajv-backed validation for `ph connect config` writes.\n//\n// Two entry points:\n//\n// - validateConnectKeyValue(key, value)\n// For the `<key> <value>` form. Sets the value at the dotted path inside a\n// stub connect block, then validates the result against the runtime schema.\n// Catches both invalid paths (key doesn't map to a real field) and invalid\n// types (e.g. `connect.renown.chainId \"abc\"` — schema says number).\n//\n// - validateConnectPatch(patch)\n// For the `--json` form. Validates the whole patch as a partial connect.*\n// blob. Same schema, but we only check the keys actually present in the\n// patch (additional keys still fail per `additionalProperties: false`).\n//\n// Both return a typed `connect.*` partial on success or throw with a multi-\n// line, actionable message on failure.\n\nimport { phConnectRuntimeConfigSchema } from \"@powerhousedao/shared/connect\";\nimport type { PHConnectRuntimeConfig } from \"@powerhousedao/shared/clis\";\nimport AjvNs from \"ajv\";\nimport { isPlainObject, stringToPath } from \"remeda\";\n\ntype PlainObject = Record<string, unknown>;\ntype ConnectPartial = Partial<PHConnectRuntimeConfig>;\n\n// Ajv ships as CJS — under NodeNext ESM the default lands on `.default` while\n// types still point at the class on the namespace. Normalize the constructor.\ntype AjvCtor = new (opts?: Record<string, unknown>) => {\n compile: (schema: unknown) => AjvValidate;\n};\ntype AjvError = { instancePath?: string; message?: string };\ntype AjvValidate = ((data: unknown) => boolean) & {\n errors?: AjvError[] | null;\n};\n\nconst Ajv = ((AjvNs as unknown as { default?: AjvCtor }).default ??\n (AjvNs as unknown as AjvCtor)) as AjvCtor;\n\nconst ajv = new Ajv({ allErrors: true, strict: false });\nconst validateConnect: AjvValidate = ajv.compile(phConnectRuntimeConfigSchema);\n\n/**\n * Parse the CLI-supplied value. Tries JSON first so `true`, `42`, `\"a\"`,\n * `null`, `[1,2]` coerce; falls back to the raw string for unquoted text.\n *\n * Examples:\n * \"true\" -> true (boolean)\n * \"42\" -> 42 (number)\n * '\"x\"' -> \"x\" (string, quoted)\n * \"x\" -> \"x\" (string, bare)\n * \"[1,2]\" -> [1, 2] (array)\n */\nexport function parseCliValue(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\n/**\n * Strip the optional leading \"connect.\" prefix so callers can pass either\n * \"connect.renown.url\" or \"renown.url\" interchangeably.\n */\nexport function normalizeKey(key: string): string {\n return key.startsWith(\"connect.\") ? key.slice(\"connect.\".length) : key;\n}\n\nfunction formatErrors(errors: AjvError[] | null | undefined): string {\n if (!errors || errors.length === 0) return \"unknown validation error\";\n return errors\n .map((e) => {\n const path = e.instancePath || \"(root)\";\n return ` ${path} ${e.message ?? \"\"}`.trim();\n })\n .join(\"\\n\");\n}\n\n/**\n * Validate a single `<key> <value>` pair. Returns the parsed connect-partial\n * that, when deep-merged into the existing config, applies the change.\n *\n * Throws on:\n * - Empty key\n * - Path that doesn't exist in the schema\n * - Value whose type doesn't match the schema at the leaf path\n */\nexport function validateConnectKeyValue(\n key: string,\n rawValue: string,\n): ConnectPartial {\n const normalized = normalizeKey(key);\n if (!normalized) {\n throw new Error(\n \"ph connect config: key cannot be empty. Pass a dotted path inside connect.* (e.g. connect.renown.url).\",\n );\n }\n const parsed = parseCliValue(rawValue);\n // Build a nested-stub object from the dotted path so Ajv can validate\n // the value's shape against the schema (e.g. \"renown.url\" + parsed →\n // { renown: { url: parsed } }). Remeda's `setPath` requires the path\n // to exist; this is the sparse-creation case, so we fold the parts.\n const stub = stringToPath(normalized).reduceRight<unknown>(\n (acc, key) => ({ [String(key)]: acc }),\n parsed,\n ) as PlainObject;\n if (!validateConnect(stub)) {\n throw new Error(\n `ph connect config: validation failed for key=\"${normalized}\" value=${JSON.stringify(parsed)} (parsed as ${typeof parsed}):\\n${formatErrors(validateConnect.errors)}`,\n );\n }\n return stub;\n}\n\n/**\n * Validate a `--json` bulk override. Returns the parsed partial.\n *\n * `packageRegistryUrl` is a top-level runtime field (not part of the\n * `connect.*` schema). If present in the payload, it is extracted before\n * validation so the connect-only blob can be checked against the schema,\n * then re-attached on the returned object so the caller can route it.\n */\nexport function validateConnectPatch(raw: string): ConnectPartial & {\n packageRegistryUrl?: unknown;\n} {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n throw new Error(\n `ph connect config --json: invalid JSON (${msg}). Expected a partial connect.* blob, e.g. --json '{\"renown\":{\"url\":\"...\"}}'.`,\n { cause: e },\n );\n }\n if (!isPlainObject(parsed)) {\n throw new Error(\n `ph connect config --json: payload must be a JSON object, got ${typeof parsed}.`,\n );\n }\n // Extract `packageRegistryUrl` (top-level field, not in the connect schema)\n // before validating, so a payload like `{\"packageRegistryUrl\":\"…\"}` doesn't\n // fail the `additionalProperties: false` check on the connect schema.\n const top = parsed as PlainObject;\n const hasPackageRegistryUrl = Object.prototype.hasOwnProperty.call(\n top,\n \"packageRegistryUrl\",\n );\n const packageRegistryUrl = top.packageRegistryUrl;\n const connectOnly: PlainObject = { ...top };\n delete connectOnly.packageRegistryUrl;\n if (!validateConnect(connectOnly)) {\n throw new Error(\n `ph connect config --json: validation failed:\\n${formatErrors(validateConnect.errors)}`,\n );\n }\n return hasPackageRegistryUrl\n ? ({ ...connectOnly, packageRegistryUrl } as ConnectPartial & {\n packageRegistryUrl?: unknown;\n })\n : (connectOnly as ConnectPartial);\n}\n","/**\n * Comma-separated URL string → array of `{url, name: null, icon: null}`\n * entries suitable for `connect.drives.defaultDrives`. Used by ph-cli's\n * CLI-override builders and by `ph vetra` when forwarding the local\n * switchboard's drive URLs into the runtime config.\n */\nexport const parseDefaultDrivesUrl = (\n v: string,\n): Array<{ url: string; name: null; icon: null }> =>\n v\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean)\n .map((url) => ({ url, name: null, icon: null }));\n","// Builds a `connectOverride` partial from CLI flags. Shared by:\n//\n// - `ph connect build` — uses `buildCliConnectOverride` to produce the\n// `cliConnectOverride` patch the Vite plugin applies at the top of the\n// precedence ladder:\n//\n// DEFAULT_CONNECT_CONFIG < env-var seeds < source connect.* < --json < individual --flag\n//\n// - `ph connect config` — uses `buildConnectFlagPatch` (the per-field\n// partial builder) to translate flag-set values into the patch that\n// gets dual-written to source + dist `powerhouse.config.json`.\n//\n// `--json` parses as a partial `connect.*` blob and merges in first; then any\n// individual --flag values merge on top, so a flag beats a conflicting --json\n// value.\n\nimport type {\n PHConnectDefaultDrive,\n PHConnectRuntimeConfig,\n} from \"@powerhousedao/shared/clis\";\nimport { deepMerge } from \"@powerhousedao/shared/connect\";\nimport { mergeDefaultDrives } from \"./merge-default-drives.js\";\nimport type { ConnectBuildArgs, ConnectStudioArgs } from \"../types.js\";\nimport {\n normalizeKey,\n parseCliValue,\n validateConnectKeyValue,\n} from \"./connect-config-validation.js\";\nimport { parseDefaultDrivesUrl } from \"./parse-default-drives.js\";\n\ntype PlainObject = Record<string, unknown>;\n\n/**\n * Structural input shape consumed by `buildConnectFlagPatch`. Every property\n * is strict-optional — `undefined` means \"user did not pass this flag\" and\n * the path is excluded from the patch.\n *\n * Callers with cmd-ts-typed args where some flags have built-in defaults\n * (e.g. the 4 commonArgs flags `--base` / `--log-level` /\n * `--default-drives-url` / `--drive-preserve-strategy`) must filter through\n * `wasFlagExplicitlyPassed` BEFORE building this input — otherwise default\n * values like `\"info\"` will silently clobber source `powerhouse.config.json`\n * values.\n */\nexport type ConnectFlagInput = {\n // Strict-optional flags from connectRuntimeOverrideArgs (excluding\n // `packagesRegistry`, which is a top-level runtime field — see\n // `buildCliConnectOverride`).\n json?: string | undefined;\n renownUrl?: string | undefined;\n renownNetworkId?: string | undefined;\n renownChainId?: number | undefined;\n renownNamespace?: string | undefined;\n renownSwitchboardUrl?: string | undefined;\n allowAddDrive?: boolean | undefined;\n externalPackages?: boolean | undefined;\n workflows?: boolean | undefined;\n remoteDrivesEnabled?: boolean | undefined;\n remoteDrivesAllowAdd?: boolean | undefined;\n remoteDrivesAllowDelete?: boolean | undefined;\n localDrivesEnabled?: boolean | undefined;\n localDrivesAllowAdd?: boolean | undefined;\n localDrivesAllowDelete?: boolean | undefined;\n appName?: string | undefined;\n homeBackground?: string | undefined;\n sentryDsn?: string | undefined;\n sentryEnv?: string | undefined;\n sentryTracingEnabled?: boolean | undefined;\n // commonArgs flags. Callers must apply `wasFlagExplicitlyPassed`\n // filtering (see above).\n basePath?: string | undefined;\n logLevel?: string | undefined;\n defaultDrivesUrl?: string | undefined;\n drivesPreserveStrategy?: string | undefined;\n};\n\n/**\n * Parse the `--json` payload (if any). Throws on malformed JSON or on a\n * non-object root with a clear, command-line-visible error.\n */\nfunction parseJsonOverride(raw: string | undefined): PlainObject {\n if (raw === undefined || raw === \"\") return {};\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n throw new Error(\n `--json: invalid JSON (${msg}). Expected a partial 'connect.*' blob, e.g. --json '{\"renown\":{\"url\":\"...\"}}'.`,\n { cause: e },\n );\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(\n `--json: payload must be a JSON object, got ${typeof parsed}.`,\n );\n }\n return parsed as PlainObject;\n}\n\n/**\n * Re-exported for `runConnectConfig` so the same JSON validation runs for\n * both `build --json` and `config --json`.\n */\nexport function parseConnectJsonArg(raw: string | undefined): PlainObject {\n return parseJsonOverride(raw);\n}\n\nfunction setIfDefined<V>(\n target: PlainObject,\n key: string,\n value: V | undefined,\n): void {\n if (value !== undefined) target[key] = value;\n}\n\n/**\n * Detect whether the user literally typed `--<longName>` on the command\n * line. Used to gate the 4 commonArgs flags through `cliConnectOverride` —\n * those flags have cmd-ts defaults, so their parsed value is always\n * defined, and a naive merge would silently clobber source values with the\n * default on every build.\n *\n * Handles both `--flag value` and `--flag=value` forms.\n */\nexport function wasFlagExplicitlyPassed(longName: string): boolean {\n const dashed = `--${longName}`;\n return process.argv.some(\n (arg) => arg === dashed || arg.startsWith(`${dashed}=`),\n );\n}\n\n/**\n * Build a `connect.*` partial from the 20 field flags. Only includes paths\n * the user explicitly set (undefined values are excluded).\n *\n * Single source of truth for the flag → JSON-path mapping; consumed by both\n * `ph connect build` and `ph connect config`.\n */\nexport function buildConnectFlagPatch(args: ConnectFlagInput): PlainObject {\n const out: PlainObject = {};\n\n const app: PlainObject = {};\n setIfDefined(app, \"basePath\", args.basePath);\n setIfDefined(app, \"logLevel\", args.logLevel);\n setIfDefined(app, \"workflowsEnabled\", args.workflows);\n if (Object.keys(app).length > 0) out.app = app;\n\n const renown: PlainObject = {};\n setIfDefined(renown, \"url\", args.renownUrl);\n setIfDefined(renown, \"networkId\", args.renownNetworkId);\n setIfDefined(renown, \"chainId\", args.renownChainId);\n setIfDefined(renown, \"namespace\", args.renownNamespace);\n setIfDefined(renown, \"switchboardUrl\", args.renownSwitchboardUrl);\n if (Object.keys(renown).length > 0) out.renown = renown;\n\n const packages: PlainObject = {};\n setIfDefined(packages, \"externalEnabled\", args.externalPackages);\n if (Object.keys(packages).length > 0) out.packages = packages;\n\n // --home-background: empty string is the explicit \"set null\" form\n // (cmd-ts can't pass `null` directly through a string option).\n const branding: PlainObject = {};\n setIfDefined(branding, \"appName\", args.appName);\n if (args.homeBackground !== undefined) {\n branding.homeBackground =\n args.homeBackground === \"\" ? null : args.homeBackground;\n }\n if (Object.keys(branding).length > 0) out.branding = branding;\n\n // --sentry-dsn: empty string is the explicit \"set null\" form (disables\n // Sentry). Same pattern as --home-background.\n const sentry: PlainObject = {};\n if (args.sentryDsn !== undefined) {\n sentry.dsn = args.sentryDsn === \"\" ? null : args.sentryDsn;\n }\n setIfDefined(sentry, \"env\", args.sentryEnv);\n setIfDefined(sentry, \"tracing\", args.sentryTracingEnabled);\n if (Object.keys(sentry).length > 0) out.sentry = sentry;\n\n const drives: PlainObject = {};\n setIfDefined(drives, \"allowAddDrive\", args.allowAddDrive);\n setIfDefined(drives, \"preserveStrategy\", args.drivesPreserveStrategy);\n if (args.defaultDrivesUrl !== undefined && args.defaultDrivesUrl !== \"\") {\n drives.defaultDrives = parseDefaultDrivesUrl(args.defaultDrivesUrl);\n }\n\n const remote: PlainObject = {};\n setIfDefined(remote, \"enabled\", args.remoteDrivesEnabled);\n setIfDefined(remote, \"allowAdd\", args.remoteDrivesAllowAdd);\n setIfDefined(remote, \"allowDelete\", args.remoteDrivesAllowDelete);\n\n const local: PlainObject = {};\n setIfDefined(local, \"enabled\", args.localDrivesEnabled);\n setIfDefined(local, \"allowAdd\", args.localDrivesAllowAdd);\n setIfDefined(local, \"allowDelete\", args.localDrivesAllowDelete);\n\n const sections: PlainObject = {};\n if (Object.keys(remote).length > 0) sections.remote = remote;\n if (Object.keys(local).length > 0) sections.local = local;\n if (Object.keys(sections).length > 0) drives.sections = sections;\n if (Object.keys(drives).length > 0) out.drives = drives;\n\n return out;\n}\n\n/**\n * Combine `--json` and the individual flag values into the two override\n * inputs `ph connect build` forwards to the Vite plugin:\n *\n * - `connectOverride`: a partial `connect.*` patch (deep-merged at the top\n * of the runtime-config precedence ladder).\n * - `packageRegistryUrl`: a separate top-level override; mirrors the\n * source-config top-level field (the SPA reads it directly).\n *\n * `--packages-registry` and `--json` containing a top-level\n * `packageRegistryUrl` both flow into `packageRegistryUrl`; the flag wins on\n * collision. Returns `undefined` for whichever override was not supplied.\n *\n * The 4 commonArgs flags (`--base`, `--log-level`, `--default-drives-url`,\n * `--drive-preserve-strategy`) are gated through `wasFlagExplicitlyPassed`\n * because they carry cmd-ts defaults that would otherwise leak into the\n * override on every build.\n */\nexport function buildCliConnectOverride(args: ConnectBuildArgs): {\n connectOverride: PHConnectRuntimeConfig | undefined;\n packageRegistryUrl: string | undefined;\n} {\n const fromJson = parseJsonOverride(args.json);\n\n const input: ConnectFlagInput = {\n renownUrl: args.renownUrl,\n renownNetworkId: args.renownNetworkId,\n renownChainId: args.renownChainId,\n renownNamespace: args.renownNamespace,\n renownSwitchboardUrl: args.renownSwitchboardUrl,\n allowAddDrive: args.allowAddDrive,\n externalPackages: args.externalPackages,\n workflows: args.workflows,\n remoteDrivesEnabled: args.remoteDrivesEnabled,\n remoteDrivesAllowAdd: args.remoteDrivesAllowAdd,\n remoteDrivesAllowDelete: args.remoteDrivesAllowDelete,\n localDrivesEnabled: args.localDrivesEnabled,\n localDrivesAllowAdd: args.localDrivesAllowAdd,\n localDrivesAllowDelete: args.localDrivesAllowDelete,\n appName: args.appName,\n homeBackground: args.homeBackground,\n sentryDsn: args.sentryDsn,\n sentryEnv: args.sentryEnv,\n sentryTracingEnabled: args.sentryTracingEnabled,\n // commonArgs flags — only forward when the user explicitly passed them.\n basePath: wasFlagExplicitlyPassed(\"base\")\n ? args.connectBasePath\n : undefined,\n logLevel: wasFlagExplicitlyPassed(\"log-level\") ? args.logLevel : undefined,\n defaultDrivesUrl: wasFlagExplicitlyPassed(\"default-drives-url\")\n ? args.defaultDrivesUrl\n : undefined,\n drivesPreserveStrategy: wasFlagExplicitlyPassed(\"drive-preserve-strategy\")\n ? args.drivesPreserveStrategy\n : undefined,\n };\n\n const fromFlags = buildConnectFlagPatch(input);\n\n // Positional `<key> <value>` override (only set when both are present;\n // `runConnectBuild` rejects the 1-positional case up front because build\n // has no read mode). Layered on top of --json + flags so a positional\n // override wins on collision — matches the user's literal command line.\n let positionalRegistry: string | undefined;\n let fromPositional: PlainObject = {};\n if (args.keyPositional !== undefined && args.valuePositional !== undefined) {\n const normalized = normalizeKey(args.keyPositional);\n if (!normalized) {\n throw new Error(\n \"ph connect build: positional <key> cannot be empty. Pass a dotted path inside connect.* (e.g. connect.renown.url).\",\n );\n }\n if (normalized === \"packageRegistryUrl\") {\n const parsed = parseCliValue(args.valuePositional);\n if (typeof parsed !== \"string\") {\n throw new Error(\n `ph connect build: positional packageRegistryUrl must be a string (got ${typeof parsed}).`,\n );\n }\n positionalRegistry = parsed;\n } else {\n fromPositional = validateConnectKeyValue(\n normalized,\n args.valuePositional,\n );\n }\n }\n\n // Top-level `packageRegistryUrl` can come from --json (top-level),\n // --packages-registry flag, or positional `packageRegistryUrl <value>`.\n // Precedence (highest → lowest): positional > flag > --json.\n const jsonRegistry =\n typeof fromJson.packageRegistryUrl === \"string\"\n ? (fromJson.packageRegistryUrl as string)\n : undefined;\n const packageRegistryUrl =\n positionalRegistry ?? args.packagesRegistry ?? jsonRegistry;\n // Strip the top-level field from the JSON patch before deep-merging into\n // the connect partial — it isn't a `connect.*` field.\n const jsonConnect = { ...fromJson };\n delete jsonConnect.packageRegistryUrl;\n\n const hasJsonConnect = Object.keys(jsonConnect).length > 0;\n const hasFlags = Object.keys(fromFlags).length > 0;\n const hasPositional = Object.keys(fromPositional).length > 0;\n const connectOverride =\n !hasJsonConnect && !hasFlags && !hasPositional\n ? undefined\n : deepMerge(\n deepMerge(\n jsonConnect as PHConnectRuntimeConfig,\n fromFlags as PHConnectRuntimeConfig,\n ),\n fromPositional as PHConnectRuntimeConfig,\n );\n\n return { connectOverride, packageRegistryUrl };\n}\n\n/**\n * Parallel of `buildCliConnectOverride` for `ph connect studio` / `ph vetra`.\n * Studio only exposes the 4 commonArgs flags (`--base`, `--log-level`,\n * `--default-drives-url`, `--drive-preserve-strategy`); each is gated through\n * `wasFlagExplicitlyPassed` so cmd-ts defaults don't leak into the override.\n *\n * `callerOverride` is supplied by wrappers around studio (notably `ph vetra`,\n * which sets default drives + preserveStrategy directly). The flag override\n * deep-merges on top of it: caller choices apply for every flag the user\n * didn't type, and an explicitly passed flag wins for its own field —\n * except `drives.defaultDrives`, which merges additively: a flag's drives\n * are appended to the caller's list (de-duplicated by drive identity) rather\n * than replacing it, so vetra's own drives stay in Connect's default set.\n * Without a caller override (plain `ph connect studio`) only the flag can\n * carry defaultDrives, so that command's behavior is unchanged.\n */\nexport function buildStudioConnectOverride(\n args: ConnectStudioArgs,\n callerOverride: PHConnectRuntimeConfig | undefined,\n): PHConnectRuntimeConfig | undefined {\n const flagOverride = buildConnectFlagPatch({\n basePath: wasFlagExplicitlyPassed(\"base\")\n ? args.connectBasePath\n : undefined,\n logLevel: wasFlagExplicitlyPassed(\"log-level\") ? args.logLevel : undefined,\n defaultDrivesUrl: wasFlagExplicitlyPassed(\"default-drives-url\")\n ? args.defaultDrivesUrl\n : undefined,\n drivesPreserveStrategy: wasFlagExplicitlyPassed(\"drive-preserve-strategy\")\n ? args.drivesPreserveStrategy\n : undefined,\n renownNamespace: args.renownNamespace,\n }) as PHConnectRuntimeConfig;\n\n // Studio commands (`ph connect studio`, `ph vetra`) always run in studio\n // mode: Connect loads the vetra package and offers builder document types.\n const studioOverride: PHConnectRuntimeConfig = { app: { studioMode: true } };\n const layers = [callerOverride, flagOverride, studioOverride].filter(\n (o): o is PHConnectRuntimeConfig =>\n o !== undefined && Object.keys(o).length > 0,\n );\n const merged = layers.reduce(\n (acc, o) => deepMerge(acc, o),\n {} as PHConnectRuntimeConfig,\n );\n\n // `deepMerge` replaces arrays, so the flag's defaultDrives would clobber\n // the caller's list; re-apply them as the de-duplicated union instead.\n // Only needed when two or more layers contribute default drives (the\n // plain-studio single-layer case is already exactly the flag's list).\n const driveGroups = layers\n .map((l) => l.drives?.defaultDrives)\n .filter(\n (d): d is PHConnectDefaultDrive[] => Array.isArray(d) && d.length > 0,\n );\n if (driveGroups.length > 1) {\n merged.drives = {\n ...merged.drives,\n defaultDrives: mergeDefaultDrives(...driveGroups),\n };\n }\n return merged;\n}\n"],"names":[],"mappings":"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","debug_id":"263d4ba3-af66-597b-ae25-c655ce397a4a"}
package/dist/cli.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ab6e0f84-63f5-57ba-a18e-7091ccbf13c6")}catch(e){}}();
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="61a4e538-407a-541a-bdb1-5323d64da65e")}catch(e){}}();
4
4
  import { initCliTelemetry } from "@powerhousedao/shared/clis/telemetry";
5
5
  import { assertNodeVersion } from "@powerhousedao/shared/clis/utils";
6
- import { boolean, command, flag, multioption, oneOf, option, optional, run, string, subcommands } from "cmd-ts";
6
+ import { boolean, command, flag, multioption, oneOf, option, optional, positional, run, string, subcommands } from "cmd-ts";
7
7
  import { AGENTS, accessTokenArgs, buildArgs, connectBuildArgs, connectConfigArgs, connectPreviewArgs, connectStudioArgs, debugArgs, initArgs, inspectArgs, installArgs, listArgs, loginArgs, migrateArgs, phCliHelpCommands, publishArgs, registryLoginArgs, switchboardArgs, uninstallArgs, unpublishArgs, vetraArgs } from "@powerhousedao/shared/clis/args";
8
8
  import { DEFAULT_EXPIRY_SECONDS } from "@powerhousedao/shared/clis/constants";
9
9
  import { Directory, File } from "cmd-ts/dist/cjs/batteries/fs.js";
@@ -15,7 +15,7 @@ import { createInterface } from "node:readline/promises";
15
15
  import { bold, yellow } from "colorette";
16
16
  //#region src/get-version.ts
17
17
  function getVersion() {
18
- return "6.2.3-dev.2";
18
+ return "6.2.3-dev.20";
19
19
  }
20
20
  //#endregion
21
21
  //#region src/utils/constants.ts
@@ -101,11 +101,19 @@ Notes:
101
101
  //#region src/commands/build.ts
102
102
  const build$1 = command({
103
103
  name: "build",
104
+ description: `
105
+ Build a Powerhouse package for publishing: a browser bundle and a node bundle of its
106
+ document models, editors, subgraphs and processors, type declarations, and its stylesheet.
107
+
108
+ Pieces under pieces/ are built too, each into its own self-contained module under
109
+ dist/node/pieces/<name>, with a descriptor.json and package.json written beside it and
110
+ the piece listed in dist/powerhouse.manifest.json. A package that ships only pieces is an
111
+ ordinary package: it carries the same boilerplate, and every step above runs for it too.`,
104
112
  args: buildArgs,
105
113
  handler: async (args) => {
106
114
  if (args.debug) console.log(args);
107
115
  try {
108
- const { runBuild } = await import("./build-C-A5-ipO.mjs");
116
+ const { runBuild } = await import("./build-D4-3Ks7v.mjs");
109
117
  await runBuild(args);
110
118
  } catch (error) {
111
119
  console.error(error);
@@ -132,7 +140,7 @@ This command:
132
140
  args: connectStudioArgs,
133
141
  handler: async (args) => {
134
142
  if (args.debug) console.log(args);
135
- const { runConnectStudio } = await import("./connect-studio-BIQzyq5B.mjs");
143
+ const { runConnectStudio } = await import("./connect-studio-xE1Tr6KS.mjs");
136
144
  await runConnectStudio(args);
137
145
  }
138
146
  }),
@@ -152,7 +160,7 @@ Build has no read mode; passing only <key> without <value> errors out (use \`ph
152
160
  args: connectBuildArgs,
153
161
  handler: async (args) => {
154
162
  if (args.debug) console.log(args);
155
- const { runConnectBuild } = await import("./connect-build-WL4axo4z.mjs");
163
+ const { runConnectBuild } = await import("./connect-build-DNQgVniR.mjs");
156
164
  await runConnectBuild(args);
157
165
  process.exit(0);
158
166
  }
@@ -187,7 +195,7 @@ Writes go to:
187
195
  `,
188
196
  args: connectConfigArgs,
189
197
  handler: async (args) => {
190
- const { runConnectConfig } = await import("./connect-config-BWGiW3IB.mjs");
198
+ const { runConnectConfig } = await import("./connect-config-C3sDVZ59.mjs");
191
199
  await runConnectConfig(args);
192
200
  }
193
201
  })
@@ -383,6 +391,136 @@ const generateMigrationFileCmd = command({
383
391
  process.exit(0);
384
392
  }
385
393
  });
394
+ //#endregion
395
+ //#region src/commands/generate-piece-action.ts
396
+ const generatePieceActionCmd = command({
397
+ name: "piece-action",
398
+ description: "Generate an action inside an existing piece",
399
+ args: {
400
+ namePositional: positional({
401
+ type: optional(string),
402
+ displayName: "name",
403
+ description: "The name of the action, e.g. get-record"
404
+ }),
405
+ name: option({
406
+ type: optional(string),
407
+ long: "name",
408
+ short: "n",
409
+ description: "The name of the action to generate"
410
+ }),
411
+ piece: option({
412
+ type: optional(string),
413
+ long: "piece",
414
+ short: "p",
415
+ description: "The piece directory under pieces/ to add the action to. Optional when the project ships exactly one piece."
416
+ }),
417
+ ...debugArgs
418
+ },
419
+ handler: async (args) => {
420
+ const { startGeneratePieceAction } = await import("./generate-piece-action-DZ14j8Gi.mjs");
421
+ await startGeneratePieceAction(args, process.cwd());
422
+ process.exit(0);
423
+ }
424
+ });
425
+ //#endregion
426
+ //#region src/commands/generate-piece-trigger.ts
427
+ const generatePieceTriggerCmd = command({
428
+ name: "piece-trigger",
429
+ description: "Generate a trigger inside an existing piece",
430
+ args: {
431
+ namePositional: positional({
432
+ type: optional(string),
433
+ displayName: "name",
434
+ description: "The name of the trigger, e.g. new-record"
435
+ }),
436
+ name: option({
437
+ type: optional(string),
438
+ long: "name",
439
+ short: "n",
440
+ description: "The name of the trigger to generate"
441
+ }),
442
+ piece: option({
443
+ type: optional(string),
444
+ long: "piece",
445
+ short: "p",
446
+ description: "The piece directory under pieces/ to add the trigger to. Optional when the project ships exactly one piece."
447
+ }),
448
+ strategy: option({
449
+ type: oneOf(["polling", "webhook"]),
450
+ long: "strategy",
451
+ description: "How the trigger fires: polled on a schedule, or delivered to a webhook",
452
+ defaultValue: () => "polling",
453
+ defaultValueIsSerializable: true
454
+ }),
455
+ ...debugArgs
456
+ },
457
+ handler: async (args) => {
458
+ const { startGeneratePieceTrigger } = await import("./generate-piece-trigger-CvzZOIPh.mjs");
459
+ await startGeneratePieceTrigger(args, process.cwd());
460
+ process.exit(0);
461
+ }
462
+ });
463
+ //#endregion
464
+ //#region src/commands/generate-piece.ts
465
+ const generatePieceCmd = command({
466
+ name: "piece",
467
+ description: "Generate a piece: a connector whose actions and triggers a workflow can call",
468
+ args: {
469
+ namePositional: positional({
470
+ type: optional(string),
471
+ displayName: "name",
472
+ description: "The name of the piece to generate. Its directory is the kebab-case of this."
473
+ }),
474
+ name: option({
475
+ type: optional(string),
476
+ long: "name",
477
+ short: "n",
478
+ description: "The name of the piece to generate"
479
+ }),
480
+ id: option({
481
+ type: optional(string),
482
+ long: "id",
483
+ description: "The piece id a workflow block type names, e.g. @acme/piece-crm. Defaults to one derived from the package name."
484
+ }),
485
+ pieceVersion: option({
486
+ type: optional(string),
487
+ long: "piece-version",
488
+ description: "The version the pieces list declares. Defaults to the package version when the piece is named after the package, else 1.0.0."
489
+ }),
490
+ auth: option({
491
+ type: oneOf([
492
+ "none",
493
+ "secret",
494
+ "custom"
495
+ ]),
496
+ long: "auth",
497
+ description: "The kind of connection the piece asks for",
498
+ defaultValue: () => "custom",
499
+ defaultValueIsSerializable: true
500
+ }),
501
+ description: option({
502
+ type: optional(string),
503
+ long: "description",
504
+ description: "One line describing what the piece connects to"
505
+ }),
506
+ dir: option({
507
+ type: optional(Directory),
508
+ long: "dir",
509
+ description: "Name of the directory of an existing piece to re-register"
510
+ }),
511
+ all: flag({
512
+ long: "all",
513
+ short: "a",
514
+ description: "Re-register every piece in pieces/: refresh the pieces list and the manifest, and prune what is gone"
515
+ }),
516
+ ...debugArgs
517
+ },
518
+ handler: async (args) => {
519
+ const { startGeneratePiece } = await import("./generate-piece-B8Kbsshu.mjs");
520
+ await startGeneratePiece(args, process.cwd());
521
+ process.exit(0);
522
+ }
523
+ });
386
524
  const generateProcessorCmd = command({
387
525
  name: "processor",
388
526
  description: "Generate a processor",
@@ -446,7 +584,7 @@ const generateProcessorCmd = command({
446
584
  ...debugArgs
447
585
  },
448
586
  handler: async (args) => {
449
- const { startGenerateProcessor } = await import("./generate-processor-_WOx-mMe.mjs");
587
+ const { startGenerateProcessor } = await import("./generate-processor-BK7moaDe.mjs");
450
588
  await startGenerateProcessor(args, process.cwd());
451
589
  process.exit(0);
452
590
  }
@@ -487,7 +625,7 @@ const generateSubgraphCmd = command({
487
625
  ...debugArgs
488
626
  },
489
627
  handler: async (args) => {
490
- const { startGenerateSubgraph } = await import("./generate-subgraph-BsHUstpl.mjs");
628
+ const { startGenerateSubgraph } = await import("./generate-subgraph-CCXHyg4b.mjs");
491
629
  await startGenerateSubgraph(args, process.cwd());
492
630
  process.exit(0);
493
631
  }
@@ -504,6 +642,9 @@ const generate = subcommands({
504
642
  app: generateAppCmd,
505
643
  processor: generateProcessorCmd,
506
644
  subgraph: generateSubgraphCmd,
645
+ piece: generatePieceCmd,
646
+ "piece-action": generatePieceActionCmd,
647
+ "piece-trigger": generatePieceTriggerCmd,
507
648
  "migration-file": generateMigrationFileCmd
508
649
  }
509
650
  });
@@ -515,7 +656,7 @@ const init = command({
515
656
  args: initArgs,
516
657
  handler: async (args) => {
517
658
  if (args.debug) console.log({ args });
518
- const { startInit } = await import("./init-BZP6gvYd.mjs");
659
+ const { startInit } = await import("./init-B3Tp7X17.mjs");
519
660
  await startInit(args);
520
661
  process.exit(0);
521
662
  }
@@ -538,7 +679,7 @@ This command:
538
679
  args: inspectArgs,
539
680
  handler: async (args) => {
540
681
  if (args.debug) console.log(args);
541
- const { startInspect } = await import("./inspect-DXjbQEV_.mjs");
682
+ const { startInspect } = await import("./inspect-B8eX-XPA.mjs");
542
683
  startInspect(args);
543
684
  process.exit(0);
544
685
  }
@@ -617,7 +758,7 @@ Resolution order for the registry URL:
617
758
  throw error;
618
759
  }
619
760
  }
620
- const { updateConfigFile, updateStylesFile } = await import("./utils-BzwczAW-.mjs");
761
+ const { updateConfigFile, updateStylesFile } = await import("./utils-B6flWWiG.mjs");
621
762
  try {
622
763
  console.log("⚙️ Updating powerhouse config file...");
623
764
  updateConfigFile(dependenciesWithVersions, projectPath, "install", args.local ? "local" : "registry", registryUrl, args.registry !== void 0);
@@ -794,7 +935,7 @@ const migrate = command({
794
935
  description: "Run migrations",
795
936
  handler: async (args) => {
796
937
  if (args.debug) console.log(args);
797
- const { startMigrate } = await import("./migrate-jGKfE02L.mjs");
938
+ const { startMigrate } = await import("./migrate-CM_3Luws.mjs");
798
939
  await startMigrate(args);
799
940
  process.exit(0);
800
941
  }
@@ -842,7 +983,7 @@ This command:
842
983
  const { projectPath } = await getPowerhouseProjectInfo();
843
984
  if (!projectPath) throw new Error("Could not find project path.");
844
985
  const { checkNpmAuth, npmPublish, resolveRegistryUrl } = await import("@powerhousedao/shared/registry");
845
- const { mintRegistryAuthToken } = await import("./registry-auth-DxEWCJu2.mjs");
986
+ const { mintRegistryAuthToken } = await import("./registry-auth-C9en-6FX.mjs");
846
987
  const registryUrl = resolveRegistryUrl({
847
988
  registry: args.registry,
848
989
  projectPath
@@ -932,7 +1073,7 @@ Usage:
932
1073
  const projectPath = (await getPowerhouseProjectInfo().catch(() => null))?.projectPath ?? process.cwd();
933
1074
  const [{ resolveRegistryUrl, writeRegistryAuthToken }, { mintRegistryAuthToken }, { parseExpiry, formatExpiry }] = await Promise.all([
934
1075
  import("@powerhousedao/shared/registry"),
935
- import("./registry-auth-DxEWCJu2.mjs"),
1076
+ import("./registry-auth-C9en-6FX.mjs"),
936
1077
  import("@renown/sdk/node")
937
1078
  ]);
938
1079
  const registryUrl = resolveRegistryUrl({
@@ -969,7 +1110,7 @@ This command:
969
1110
  const { basePath, dbPath, migrate, migrateStatus, reset, yes } = args;
970
1111
  if (basePath) process.env.BASE_PATH = basePath;
971
1112
  if (reset) {
972
- const { resetSwitchboardDatabase } = await import("./switchboard-reset-BcQXlcVf.mjs");
1113
+ const { resetSwitchboardDatabase } = await import("./switchboard-reset-BWLfgYuv.mjs");
973
1114
  await resetSwitchboardDatabase({
974
1115
  dbPath,
975
1116
  yes
@@ -977,14 +1118,14 @@ This command:
977
1118
  process.exit(0);
978
1119
  }
979
1120
  if (migrate || migrateStatus) {
980
- const { runSwitchboardMigrations } = await import("./switchboard-migrate-NQ7LHWSi.mjs");
1121
+ const { runSwitchboardMigrations } = await import("./switchboard-migrate-RN3lGK4Q.mjs");
981
1122
  await runSwitchboardMigrations({
982
1123
  dbPath,
983
1124
  statusOnly: migrateStatus
984
1125
  });
985
1126
  process.exit(0);
986
1127
  }
987
- const { startSwitchboard } = await import("./switchboard-iRFugh8I.mjs");
1128
+ const { startSwitchboard } = await import("./switchboard-DTJkt8lG.mjs");
988
1129
  const { defaultDriveUrl, renown } = await startSwitchboard(args);
989
1130
  console.log(" ➜ Switchboard:", defaultDriveUrl);
990
1131
  if (renown) console.log(" ➜ Identity:", renown.did);
@@ -1030,7 +1171,7 @@ This command:
1030
1171
  console.error("❌ Failed to uninstall dependencies");
1031
1172
  throw error;
1032
1173
  }
1033
- const { removeStylesImports, updateConfigFile } = await import("./utils-BzwczAW-.mjs");
1174
+ const { removeStylesImports, updateConfigFile } = await import("./utils-B6flWWiG.mjs");
1034
1175
  try {
1035
1176
  console.log("⚙️ Updating powerhouse config file...");
1036
1177
  updateConfigFile(dependenciesWithVersions, projectPath, "uninstall");
@@ -1157,11 +1298,20 @@ This command:
1157
1298
  1. Starts a Vetra Switchboard with a "Vetra" drive for document storage
1158
1299
  2. Optionally connects to remote drives instead of creating a local drive
1159
1300
  3. Starts Connect Studio pointing to the Switchboard for user interaction (unless disabled)
1160
- 4. Enables real-time updates, collaboration, and code generation`,
1301
+ 4. Enables real-time updates, collaboration, and code generation
1302
+
1303
+ Default drives:
1304
+ Connect's default drives resolve to the Vetra drive (and the preview drive
1305
+ when using --watch), plus any drives configured under
1306
+ connect.drives.defaultDrives in powerhouse.config.json - de-duplicated by
1307
+ URL, so configuring project drives does not cost you the Vetra drive.
1308
+ An explicit --default-drives-url is appended to that list (de-duplicated);
1309
+ it never replaces the Vetra drive.
1310
+ `,
1161
1311
  args: vetraArgs,
1162
1312
  handler: async (args) => {
1163
1313
  if (args.debug) console.log(args);
1164
- const { startVetra } = await import("./vetra-DkF6EJMY.mjs");
1314
+ const { startVetra } = await import("./vetra-DCD3t7Qh.mjs");
1165
1315
  await startVetra(args);
1166
1316
  }
1167
1317
  }),
@@ -1284,4 +1434,4 @@ await main().catch(async (error) => {
1284
1434
  export {};
1285
1435
 
1286
1436
  //# sourceMappingURL=cli.mjs.map
1287
- //# debugId=ab6e0f84-63f5-57ba-a18e-7091ccbf13c6
1437
+ //# debugId=61a4e538-407a-541a-bdb1-5323d64da65e