@powerhousedao/codegen 6.0.0-dev.135 → 6.0.0-dev.136

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.
@@ -1,72 +1,416 @@
1
1
  import { getActionInputName, getActionInputTypeNames, getActionType, getActionTypeName } from "./src/name-builders/index.mjs";
2
2
  import { camelCase, capitalCase, constantCase, kebabCase, pascalCase } from "change-case";
3
3
  import { css, html, js, json, md, ts, tsx, yaml } from "@tmpl/core";
4
- //#region src/templates/boilerplate/AGENTS.md.ts
5
- const agentsTemplate = md`
6
- # Powerhouse Document Models Assistant
7
-
8
- This project creates document models, editors, processors and subgraphs for the Powerhouse ecosystem. Your role is to help users create these modules based on their needs.
9
-
10
- ## Core Concepts
4
+ //#region src/templates/app/components/CreateDocument.ts
5
+ const createDocumentFileTemplate = tsx`
6
+ import type { VetraDocumentModelModule } from "@powerhousedao/reactor-browser";
7
+ import {
8
+ showCreateDocumentModal,
9
+ useAllowedDocumentModelModules,
10
+ } from "@powerhousedao/reactor-browser";
11
11
 
12
- - **Document Model**: A template for creating documents. Defines schema and allowed operations for a document type.
13
- - **Document**: An instance of a document model containing actual data that follows the model's structure and can be modified using operations.
14
- - **Drive**: A document of type "powerhouse/document-drive" representing a collection of documents and folders. Add documents using "addActions" with "ADD_FILE" action.
15
- - **Action**: A proposed change to a document (JSON object with action name and input). Dispatch using "addActions" tool.
16
- - **Operation**: A completed change to a document containing the action plus metadata (index, timestamp, hash, errors). Actions become operations after dispatch.
12
+ /**
13
+ * Document creation UI component.
14
+ * Displays available document types as clickable buttons.
15
+ */
16
+ export function CreateDocument() {
17
+ const allowedDocumentModelModules = useAllowedDocumentModelModules();
17
18
 
18
- ## Technology Primer
19
+ return (
20
+ <div>
21
+ {/* Customize section title here */}
22
+ <h3 className="mb-3 mt-4 text-sm font-bold text-gray-600">
23
+ Create document
24
+ </h3>
25
+ {/* Customize layout by changing flex-wrap, gap, or grid layout */}
26
+ <div className="flex w-full flex-wrap gap-4">
27
+ {allowedDocumentModelModules?.map((documentModelModule) => {
28
+ return (
29
+ <CreateDocumentButton
30
+ key={documentModelModule.documentModel.global.id}
31
+ documentModelModule={documentModelModule}
32
+ />
33
+ );
34
+ })}
35
+ </div>
36
+ </div>
37
+ );
38
+ }
19
39
 
20
- - **Reactor**: The core Powerhouse engine. It is modular and storage-agnostic, loads document models at runtime, and synchronizes documents across nodes via drives.
21
- - **Reactor Package**: A deployable bundle that extends the Reactor. It contains one or more document models, editors, processors, and subgraphs. A Vetra project generates a Reactor Package.
22
- - **Connect**: The Powerhouse web application for document management. End users open Connect to browse drives, create documents, and interact with editors.
23
- - **Switchboard**: The Powerhouse API service. It exposes GraphQL and MCP endpoints so external tools can read/write documents programmatically.
24
- - **Vetra**: The local development environment for building Reactor Packages. It includes Vetra Studio (a local Connect instance) and Vetra Switchboard (a local Switchboard with reactor-mcp). Start it with \`ph vetra\`.
40
+ type Props = {
41
+ documentModelModule: VetraDocumentModelModule;
42
+ };
43
+ function CreateDocumentButton({ documentModelModule }: Props) {
44
+ const documentType = documentModelModule.documentModel.global.id;
45
+ const documentModelName =
46
+ documentModelModule.documentModel.global.name || documentType;
47
+ const documentModelDescription =
48
+ documentModelModule.documentModel.global.description;
49
+ return (
50
+ <button
51
+ className="cursor-pointer rounded-md bg-gray-200 py-2 px-3 hover:bg-gray-300"
52
+ title={documentModelName}
53
+ aria-description={documentModelDescription}
54
+ onClick={() => showCreateDocumentModal(documentType)}
55
+ >
56
+ {documentModelName}
57
+ </button>
58
+ );
59
+ }
60
+ `.raw;
61
+ //#endregion
62
+ //#region src/templates/app/components/DriveContents.ts
63
+ const appDriveContentsFileTemplate = () => tsx`
64
+ import { CreateDocument } from "./CreateDocument.js";
65
+ import { EmptyState } from "./EmptyState.js";
66
+ import { Files } from "./Files.js";
67
+ import { Folders } from "./Folders.js";
68
+ import { NavigationBreadcrumbs } from "./NavigationBreadcrumbs.js";
25
69
 
26
- ## CRITICAL: MCP Tool Usage Rules
70
+ /** Shows the documents and folders in the selected drive */
71
+ export function DriveContents() {
72
+ return (
73
+ <div className="space-y-6 px-6">
74
+ <NavigationBreadcrumbs />
75
+ <Folders />
76
+ <Files />
77
+ <EmptyState />
78
+ <CreateDocument />
79
+ </div>
80
+ );
81
+ }
27
82
 
28
- **MANDATORY**: The \`reactor-mcp\` MUST BE USED when handling documents or document-models for the Powerhouse/Vetra ecosystem.
29
- If the \`reactor-mcp\` server is unavailable, ask the user to run \`ph vetra\` on a separate terminal to start the server and try to reconnect to the MCP server, DO NOT run it yourself.
30
83
 
31
- ### Key Requirements:
84
+ `.raw;
85
+ //#endregion
86
+ //#region src/templates/app/components/DriveExplorer.ts
87
+ const driveExplorerFileTemplate = tsx`
88
+ import type { EditorProps } from "document-model";
89
+ import { FolderTree } from "./FolderTree.js";
90
+ import { DriveContents } from "./DriveContents.js";
32
91
 
33
- - Never set document IDs manually - they're auto-generated by 'createDocument'
34
- - Minimize "addActions" calls by batching multiple actions together
35
- - Add new document model documents to "vetra-{hash}" drive unless specified otherwise
36
- - Always check document model schema before calling addActions
37
- - Use MCP tools for ALL document and document-model operations
92
+ /**
93
+ * Main drive explorer component with sidebar navigation and content area.
94
+ * Layout: Left sidebar (folder tree) + Right content area (files/folders + document editor)
95
+ */
96
+ export function DriveExplorer({ children }: EditorProps) {
97
+ // if a document is selected then it's editor will be passed as children
98
+ const showDocumentEditor = !!children;
38
99
 
39
- ## Document Model Creation Workflow
100
+ return (
101
+ <div className="flex h-full">
102
+ <FolderTree />
103
+ <div className="flex-1 overflow-y-auto p-4">
104
+ {/* Conditional rendering: Document editor or folder contents */}
105
+ {showDocumentEditor ? (
106
+ /* Document editor view */
107
+ children
108
+ ) : (
109
+ /* Folder contents view */
110
+ <DriveContents />
111
+ )}
112
+ </div>
113
+ </div>
114
+ );
115
+ }
116
+ `.raw;
117
+ //#endregion
118
+ //#region src/templates/app/components/EmptyState.ts
119
+ const emptyStateFileTemplate = tsx`
120
+ import { useNodesInSelectedDriveOrFolder } from "@powerhousedao/reactor-browser";
40
121
 
41
- ### 1. Planning Phase
122
+ /** Shows a message when the selected drive or folder is empty */
123
+ export function EmptyState() {
124
+ const nodes = useNodesInSelectedDriveOrFolder();
125
+ const hasNodes = nodes.length > 0;
126
+ if (hasNodes) return null;
42
127
 
43
- **MANDATORY**: Present your proposal to the user and ask for confirmation before implementing ANY document model.
128
+ return (
129
+ <div className="py-12 text-center text-gray-500">
130
+ <p className="text-lg">This folder is empty</p>
131
+ <p className="mt-2 text-sm">Create your first document or folder below</p>
132
+ </div>
133
+ );
134
+ }
135
+ `.raw;
136
+ //#endregion
137
+ //#region src/templates/app/components/Files.ts
138
+ const appFilesFileTemplate = () => tsx`
139
+ import { FileItem } from "@powerhousedao/design-system/connect";
140
+ import {
141
+ useNodesInSelectedDriveOrFolder,
142
+ isFileNodeKind,
143
+ } from "@powerhousedao/reactor-browser";
44
144
 
45
- - **ALWAYS** describe the proposed document model structure (state schema, operations, modules) before creating
46
- - **NEVER** proceed with implementation without explicit user approval of your proposal
47
- - When in doubt, ask for clarification
48
- - Break complex models into logical modules and operations
145
+ /** Shows the files in the selected drive or folder */
146
+ export function Files() {
147
+ const nodes = useNodesInSelectedDriveOrFolder();
148
+ const fileNodes = nodes.filter((n) => isFileNodeKind(n));
149
+ const hasFiles = fileNodes.length > 0;
49
150
 
50
- #### Document Type ID Format
151
+ if (!hasFiles) return null;
51
152
 
52
- - **Type ID**: \`{organization}/{document-type-name}\` (e.g., \`pizza-plaza/order\`, \`acme/invoice\`)
53
- - **File extension**: 2-4 characters with leading dot (e.g., \`.ordr\`, \`.inv\`)
54
- - **Name**: Must match \`/[a-zA-Z][a-zA-Z0-9 ]*/\` — human-readable, capitalized (e.g., \`"Order"\`, \`"Invoice"\`)
153
+ return (
154
+ <div>
155
+ <h3 className="mb-2 text-sm font-semibold text-gray-600">Documents</h3>
156
+ <div className="flex flex-wrap gap-4">
157
+ {fileNodes.map((fileNode) => (
158
+ <FileItem key={fileNode.id} fileNode={fileNode} />
159
+ ))}
160
+ </div>
161
+ </div>
162
+ );
163
+ }
55
164
 
56
- ### 2. Pre-Implementation Requirements
165
+ `.raw;
166
+ //#endregion
167
+ //#region src/templates/app/components/Folders.ts
168
+ const appFoldersFileTemplate = () => tsx`
169
+ import { FolderItem } from "@powerhousedao/design-system/connect";
170
+ import {
171
+ useNodesInSelectedDriveOrFolder,
172
+ isFolderNodeKind,
173
+ } from "@powerhousedao/reactor-browser";
57
174
 
58
- **MANDATORY**: Check document model schema before making any MCP tool calls.
175
+ /** Shows the folders in the selected drive or folder */
176
+ export function Folders() {
177
+ const nodes = useNodesInSelectedDriveOrFolder();
178
+ const folderNodes = nodes.filter((n) => isFolderNodeKind(n));
179
+ const hasFolders = folderNodes.length > 0;
180
+ if (!hasFolders) return null;
59
181
 
60
- - **ALWAYS** use \`mcp__reactor-mcp__getDocumentModelSchema\` with \`type: "powerhouse/document-model"\` first
61
- - Review input schema requirements for operations like \`ADD_MODULE\`, \`ADD_OPERATION\`, etc.
62
- - Ensure all required parameters (like \`id\` or \`scope\` fields) are included in action inputs
63
- - This prevents failed tool calls and reduces iteration
182
+ return (
183
+ <div>
184
+ <h3 className="mb-2 text-sm font-bold text-gray-600">Folders</h3>
185
+ <div className="flex flex-wrap gap-4">
186
+ {folderNodes.map((folderNode) => (
187
+ <FolderItem key={folderNode.id} folderNode={folderNode} />
188
+ ))}
189
+ </div>
190
+ </div>
191
+ );
192
+ }
193
+ `.raw;
194
+ //#endregion
195
+ //#region src/templates/app/components/FolderTree.ts
196
+ const folderTreeFileTemplate = tsx`
197
+ import {
198
+ Sidebar,
199
+ SidebarProvider,
200
+ type SidebarNode,
201
+ } from "@powerhousedao/document-engineering";
202
+ import {
203
+ setSelectedNode,
204
+ useNodesInSelectedDrive,
205
+ useSelectedDrive,
206
+ useSelectedNode,
207
+ } from "@powerhousedao/reactor-browser";
208
+ import type { Node } from "@powerhousedao/shared/document-drive";
209
+ import { useMemo } from "react";
64
210
 
65
- ### 3. Implementation Requirements
211
+ function buildSidebarNodes(
212
+ nodes: Node[],
213
+ parentId: string | null | undefined,
214
+ ): SidebarNode[] {
215
+ return nodes
216
+ .filter((n) => {
217
+ if (parentId == null) {
218
+ return n.parentFolder == null;
219
+ }
220
+ return n.parentFolder === parentId;
221
+ })
222
+ .map((node): SidebarNode => {
223
+ if (node.kind === "folder") {
224
+ return {
225
+ id: node.id,
226
+ title: node.name,
227
+ icon: "FolderClose" as const,
228
+ expandedIcon: "FolderOpen" as const,
229
+ children: buildSidebarNodes(nodes, node.id),
230
+ };
231
+ }
232
+ return {
233
+ id: node.id,
234
+ title: node.name,
235
+ icon: "File" as const,
236
+ };
237
+ });
238
+ }
66
239
 
67
- - Document model reducers must be **pure synchronous functions**
68
- - Reducers receive current state and operation, always returning the same result
69
- - Values like dates/IDs must come from operation input, not generated in reducer
240
+ function transformNodesToSidebarNodes(
241
+ nodes: Node[],
242
+ driveName: string,
243
+ ): SidebarNode[] {
244
+ return [
245
+ {
246
+ id: "root",
247
+ title: driveName,
248
+ icon: "Drive" as const,
249
+ children: buildSidebarNodes(nodes, null),
250
+ },
251
+ ];
252
+ }
253
+
254
+ /**
255
+ * Hierarchical folder tree navigation component using Sidebar from document-engineering.
256
+ * Displays folders and files in a tree structure with expand/collapse functionality, search, and resize support.
257
+ */
258
+ export function FolderTree() {
259
+ const [selectedDrive] = useSelectedDrive();
260
+ const nodes = useNodesInSelectedDrive();
261
+ const selectedNode = useSelectedNode();
262
+ const driveName = selectedDrive.header.name;
263
+ // Transform Node[] to hierarchical SidebarNode structure
264
+ const sidebarNodes = useMemo(
265
+ () => transformNodesToSidebarNodes(nodes || [], driveName),
266
+ [nodes, driveName],
267
+ );
268
+
269
+ const handleActiveNodeChange = (node: SidebarNode) => {
270
+ // If root node is selected, pass undefined to match existing behavior
271
+ if (node.id === "root") {
272
+ setSelectedNode(undefined);
273
+ } else {
274
+ setSelectedNode(node.id);
275
+ }
276
+ };
277
+ // Map selectedNodeId to activeNodeId (use "root" when undefined)
278
+ const activeNodeId =
279
+ !selectedNode || selectedNode.id === selectedDrive.header.id
280
+ ? "root"
281
+ : selectedNode.id;
282
+
283
+ return (
284
+ <SidebarProvider nodes={sidebarNodes}>
285
+ <Sidebar
286
+ className="pt-1"
287
+ nodes={sidebarNodes}
288
+ activeNodeId={activeNodeId}
289
+ onActiveNodeChange={handleActiveNodeChange}
290
+ sidebarTitle="Drive Explorer"
291
+ showSearchBar={true}
292
+ resizable={true}
293
+ allowPinning={false}
294
+ showStatusFilter={false}
295
+ initialWidth={256}
296
+ defaultLevel={2}
297
+ />
298
+ </SidebarProvider>
299
+ );
300
+ }
301
+ `.raw;
302
+ //#endregion
303
+ //#region src/templates/app/components/NavigationBreadcrumbs.ts
304
+ const driveExplorerNavigationBreadcrumbsFileTemplate = () => tsx`
305
+ import { Breadcrumbs } from "@powerhousedao/design-system/connect";
306
+
307
+ /** Shows the navigation breadcrumbs for the selected drive or folder */
308
+ export function NavigationBreadcrumbs() {
309
+ return (
310
+ <div className="border-b border-gray-200 pb-3 space-y-3">
311
+ <Breadcrumbs />
312
+ </div>
313
+ );
314
+ }
315
+ `.raw;
316
+ //#endregion
317
+ //#region src/templates/app/config.ts
318
+ const appConfigFileTemplate = (v) => ts`
319
+ import type { PHAppConfig } from "@powerhousedao/reactor-browser";
320
+
321
+ /** Editor config for the <%= pascalCaseAppName %> */
322
+ export const editorConfig: PHAppConfig = {
323
+ isDragAndDropEnabled: ${v.isDragAndDropEnabledString},
324
+ allowedDocumentTypes: ${v.allowedDocumentTypesString}
325
+ };
326
+ `.raw;
327
+ //#endregion
328
+ //#region src/templates/app/editor.ts
329
+ const appEditorFileTemplate = () => tsx`
330
+ import { useSetPHAppConfig } from "@powerhousedao/reactor-browser";
331
+ import type { EditorProps } from "document-model";
332
+ import { DriveExplorer } from "./components/DriveExplorer.js";
333
+ import { editorConfig } from "./config.js";
334
+
335
+ /** Editor component for the app */
336
+ export default function Editor(props: EditorProps) {
337
+ // set the config for this app
338
+ // you can update these configs in \`./config.ts\`
339
+ useSetPHAppConfig(editorConfig);
340
+ return (
341
+ <div className="bg-gray-50 p-6">
342
+ <DriveExplorer {...props} />
343
+ </div>
344
+ );
345
+ }
346
+ `.raw;
347
+ //#endregion
348
+ //#region src/templates/boilerplate/AGENTS.md.ts
349
+ const agentsTemplate = md`
350
+ # Powerhouse Document Models Assistant
351
+
352
+ This project creates document models, editors, processors and subgraphs for the Powerhouse ecosystem. Your role is to help users create these modules based on their needs.
353
+
354
+ ## Core Concepts
355
+
356
+ - **Document Model**: A template for creating documents. Defines schema and allowed operations for a document type.
357
+ - **Document**: An instance of a document model containing actual data that follows the model's structure and can be modified using operations.
358
+ - **Drive**: A document of type "powerhouse/document-drive" representing a collection of documents and folders. Add documents using "addActions" with "ADD_FILE" action.
359
+ - **Action**: A proposed change to a document (JSON object with action name and input). Dispatch using "addActions" tool.
360
+ - **Operation**: A completed change to a document containing the action plus metadata (index, timestamp, hash, errors). Actions become operations after dispatch.
361
+
362
+ ## Technology Primer
363
+
364
+ - **Reactor**: The core Powerhouse engine. It is modular and storage-agnostic, loads document models at runtime, and synchronizes documents across nodes via drives.
365
+ - **Reactor Package**: A deployable bundle that extends the Reactor. It contains one or more document models, editors, processors, and subgraphs. A Vetra project generates a Reactor Package.
366
+ - **Connect**: The Powerhouse web application for document management. End users open Connect to browse drives, create documents, and interact with editors.
367
+ - **Switchboard**: The Powerhouse API service. It exposes GraphQL and MCP endpoints so external tools can read/write documents programmatically.
368
+ - **Vetra**: The local development environment for building Reactor Packages. It includes Vetra Studio (a local Connect instance) and Vetra Switchboard (a local Switchboard with reactor-mcp). Start it with \`ph vetra\`.
369
+
370
+ ## CRITICAL: MCP Tool Usage Rules
371
+
372
+ **MANDATORY**: The \`reactor-mcp\` MUST BE USED when handling documents or document-models for the Powerhouse/Vetra ecosystem.
373
+ If the \`reactor-mcp\` server is unavailable, ask the user to run \`ph vetra\` on a separate terminal to start the server and try to reconnect to the MCP server, DO NOT run it yourself.
374
+
375
+ ### Key Requirements:
376
+
377
+ - Never set document IDs manually - they're auto-generated by 'createDocument'
378
+ - Minimize "addActions" calls by batching multiple actions together
379
+ - Add new document model documents to "vetra-{hash}" drive unless specified otherwise
380
+ - Always check document model schema before calling addActions
381
+ - Use MCP tools for ALL document and document-model operations
382
+
383
+ ## Document Model Creation Workflow
384
+
385
+ ### 1. Planning Phase
386
+
387
+ **MANDATORY**: Present your proposal to the user and ask for confirmation before implementing ANY document model.
388
+
389
+ - **ALWAYS** describe the proposed document model structure (state schema, operations, modules) before creating
390
+ - **NEVER** proceed with implementation without explicit user approval of your proposal
391
+ - When in doubt, ask for clarification
392
+ - Break complex models into logical modules and operations
393
+
394
+ #### Document Type ID Format
395
+
396
+ - **Type ID**: \`{organization}/{document-type-name}\` (e.g., \`pizza-plaza/order\`, \`acme/invoice\`)
397
+ - **File extension**: 2-4 characters with leading dot (e.g., \`.ordr\`, \`.inv\`)
398
+ - **Name**: Must match \`/[a-zA-Z][a-zA-Z0-9 ]*/\` — human-readable, capitalized (e.g., \`"Order"\`, \`"Invoice"\`)
399
+
400
+ ### 2. Pre-Implementation Requirements
401
+
402
+ **MANDATORY**: Check document model schema before making any MCP tool calls.
403
+
404
+ - **ALWAYS** use \`mcp__reactor-mcp__getDocumentModelSchema\` with \`type: "powerhouse/document-model"\` first
405
+ - Review input schema requirements for operations like \`ADD_MODULE\`, \`ADD_OPERATION\`, etc.
406
+ - Ensure all required parameters (like \`id\` or \`scope\` fields) are included in action inputs
407
+ - This prevents failed tool calls and reduces iteration
408
+
409
+ ### 3. Implementation Requirements
410
+
411
+ - Document model reducers must be **pure synchronous functions**
412
+ - Reducers receive current state and operation, always returning the same result
413
+ - Values like dates/IDs must come from operation input, not generated in reducer
70
414
  - Reducer code goes into SET_OPERATION_REDUCER action (no function header needed)
71
415
  - Reducers are wrapped with Mutative - you can mutate the state object directly
72
416
  - External imports go at the beginning of the actual reducer file in \`src/\`
@@ -1405,14 +1749,6 @@ const indexHtmlTemplate = html(_templateObject$1 || (_templateObject$1 = _tagged
1405
1749
  var _templateObject;
1406
1750
  const legacyIndexHtmlTemplate = html(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta\n name=\"description\"\n content=\"Connect is a hub for your most important documents and processes, translated into software. Easily capture data in a structured way with dedicated business process packages. Collaborate on shared documents with ease while using your preferred storage solution (decentralized, centralized, or local).\"\n />\n <title>Powerhouse Connect</title>\n <link rel=\"icon\" href=\"/icon.ico\" />\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link\n href=\"https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap\"\n rel=\"stylesheet\"\n />\n <style>\n @import \"tailwindcss\";\n @import \"@powerhousedao/design-system/style.css\";\n @import \"@powerhousedao/document-engineering/style.css\";\n @source \"./node_modules/@powerhousedao/connect\";\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\">\n // initializes Connect on '<div id=\"root\"></div>'\n import \"@powerhousedao/connect/main.js\";\n <\/script>\n </body>\n </html>\n"]))).raw;
1407
1751
  //#endregion
1408
- //#region src/templates/boilerplate/main.tsx.ts
1409
- const mainTsxTemplate = tsx`
1410
- import { startConnect } from "@powerhousedao/connect";
1411
- import * as localPackage from "./index.js";
1412
-
1413
- startConnect(localPackage);
1414
- `.raw;
1415
- //#endregion
1416
1752
  //#region src/templates/boilerplate/index.ts
1417
1753
  const indexTsTemplate = ts`
1418
1754
  import type { Manifest } from "document-model";
@@ -2089,6 +2425,14 @@ For more information on this, and how to apply and follow the GNU AGPL, see
2089
2425
  <https://www.gnu.org/licenses/>.
2090
2426
  `;
2091
2427
  //#endregion
2428
+ //#region src/templates/boilerplate/main.tsx.ts
2429
+ const mainTsxTemplate = tsx`
2430
+ import { startConnect } from "@powerhousedao/connect";
2431
+ import * as localPackage from "./index.js";
2432
+
2433
+ startConnect(localPackage);
2434
+ `.raw;
2435
+ //#endregion
2092
2436
  //#region src/templates/boilerplate/mcp.json.ts
2093
2437
  const mcpTemplate = json`
2094
2438
  {
@@ -3536,6 +3880,11 @@ const documentModelSrcIndexFileTemplate = ts`
3536
3880
  export * from "./utils.js";
3537
3881
  `.raw;
3538
3882
  //#endregion
3883
+ //#region src/templates/document-model/src/utils.ts
3884
+ const documentModelSrcUtilsTemplate = ts`
3885
+ export {};
3886
+ `.raw;
3887
+ //#endregion
3539
3888
  //#region src/templates/document-model/tests/document-model.test.ts
3540
3889
  const documentModelTestFileTemplate = (v) => ts`
3541
3890
  /**
@@ -3685,452 +4034,103 @@ function makeTestCaseForAction(action, isPhDocumentOfTypeFunctionName) {
3685
4034
  ${camelCaseActionName}(input),
3686
4035
  );
3687
4036
 
3688
- expect(${isPhDocumentOfTypeFunctionName}(updatedDocument)).toBe(true);
3689
- expect(updatedDocument.operations.${scope}).toHaveLength(1);
3690
- expect(updatedDocument.operations.${scope}[0].action.type).toBe(
3691
- "${constantCaseActionName}",
3692
- );
3693
- expect(updatedDocument.operations.${scope}[0].action.input).toStrictEqual(input);
3694
- expect(updatedDocument.operations.${scope}[0].index).toEqual(0);
3695
- });
3696
- `.raw;
3697
- }
3698
- function makeActionImportNames(v) {
3699
- const actionNames = makeCamelCaseActionNamesForImport(v.actions);
3700
- const inputSchemaNames = makeActionInputSchemasForImport(v.actions);
3701
- return [
3702
- "reducer",
3703
- "utils",
3704
- v.isPhDocumentOfTypeFunctionName,
3705
- ...actionNames,
3706
- ...inputSchemaNames
3707
- ];
3708
- }
3709
- function makeActionsImports(v) {
3710
- return ts`
3711
- import {
3712
- ${makeActionImportNames(v).join("\n")}
3713
- } from "${v.versionedDocumentModelPackageImportPath}";
3714
- `.raw;
3715
- }
3716
- function makeTestCasesForActions(actions, isPhDocumentOfTypeFunctionName) {
3717
- return actions.map((action) => makeTestCaseForAction(action, isPhDocumentOfTypeFunctionName)).join("\n\n");
3718
- }
3719
- const documentModelOperationsModuleTestFileTemplate = (v) => ts`
3720
- /**
3721
- * This is a scaffold file meant for customization:
3722
- * - change it by adding new tests or modifying the existing ones
3723
- */
3724
-
3725
- import { describe, it, expect } from 'vitest';
3726
- import { generateMock } from '@powerhousedao/common';
3727
- import {
3728
- reducer,
3729
- utils,
3730
- ${v.isPhDocumentOfTypeFunctionName},
3731
- ${makeCamelCaseActionNamesForImport(v.actions)},
3732
- ${makeActionInputSchemasForImport(v.actions)},
3733
- } from "${v.versionedDocumentModelPackageImportPath}";
3734
-
3735
- describe("${makeModuleOperationsTypeName(v.module)}", () => {
3736
- ${makeTestCasesForActions(v.actions, v.isPhDocumentOfTypeFunctionName)}
3737
- });
3738
-
3739
- `.raw;
3740
- //#endregion
3741
- //#region src/templates/document-model/src/utils.ts
3742
- const documentModelSrcUtilsTemplate = ts`
3743
- export {};
3744
- `.raw;
3745
- //#endregion
3746
- //#region src/templates/document-model/upgrades/upgrade-manifest.ts
3747
- const upgradeManifestTemplate = (v) => ts`
3748
- import type { UpgradeManifest } from "document-model";
3749
- import { latestVersion, supportedVersions } from "./versions.js";
3750
-
3751
- export const ${v.upgradeManifestName}: UpgradeManifest<typeof supportedVersions> = {
3752
- documentType: "${v.documentModelId}",
3753
- latestVersion,
3754
- supportedVersions,
3755
- upgrades: {},
3756
- };
3757
- `.raw;
3758
- //#endregion
3759
- //#region src/templates/document-model/upgrades/upgrade-transition.ts
3760
- const upgradeTransitionTemplate = (v) => ts`
3761
- import type { Action, PHDocument, UpgradeTransition } from "document-model";
3762
- import type { ${v.phStateName} as StateV${v.previousVersion} } from "${v.documentModelPackageImportPath}/v${v.previousVersion}";
3763
- import type { ${v.phStateName} as StateV${v.version} } from "${v.documentModelPackageImportPath}/v${v.version}";
3764
-
3765
- function upgradeReducer(
3766
- document: PHDocument<StateV${v.previousVersion}>,
3767
- action: Action,
3768
- ): PHDocument<StateV${v.version}> {
3769
- return {
3770
- ...document,
3771
- };
3772
- }
3773
-
3774
- export const v${v.version}: UpgradeTransition = {
3775
- toVersion: ${v.version},
3776
- upgradeReducer,
3777
- description: "",
3778
- };
3779
- `.raw;
3780
- //#endregion
3781
- //#region src/templates/document-model/utils.ts
3782
- const documentModelUtilsTemplate = ({ phStateName, pascalCaseDocumentType }) => ts`
3783
- import type { DocumentModelUtils } from "document-model";
3784
- import type { ${phStateName} } from "./gen/types.js";
3785
- import { utils as genUtils } from "./gen/utils.js";
3786
- import * as customUtils from "./src/utils.js";
3787
-
3788
- /** Utils for the ${pascalCaseDocumentType} document model */
3789
- export const utils: DocumentModelUtils<${phStateName}> = { ...genUtils, ...customUtils };
3790
- `.raw;
3791
- //#endregion
3792
- //#region src/templates/drive-editor/components/CreateDocument.ts
3793
- const createDocumentFileTemplate = tsx`
3794
- import type { VetraDocumentModelModule } from "@powerhousedao/reactor-browser";
3795
- import {
3796
- showCreateDocumentModal,
3797
- useAllowedDocumentModelModules,
3798
- } from "@powerhousedao/reactor-browser";
3799
-
3800
- /**
3801
- * Document creation UI component.
3802
- * Displays available document types as clickable buttons.
3803
- */
3804
- export function CreateDocument() {
3805
- const allowedDocumentModelModules = useAllowedDocumentModelModules();
3806
-
3807
- return (
3808
- <div>
3809
- {/* Customize section title here */}
3810
- <h3 className="mb-3 mt-4 text-sm font-bold text-gray-600">
3811
- Create document
3812
- </h3>
3813
- {/* Customize layout by changing flex-wrap, gap, or grid layout */}
3814
- <div className="flex w-full flex-wrap gap-4">
3815
- {allowedDocumentModelModules?.map((documentModelModule) => {
3816
- return (
3817
- <CreateDocumentButton
3818
- key={documentModelModule.documentModel.global.id}
3819
- documentModelModule={documentModelModule}
3820
- />
3821
- );
3822
- })}
3823
- </div>
3824
- </div>
3825
- );
3826
- }
3827
-
3828
- type Props = {
3829
- documentModelModule: VetraDocumentModelModule;
3830
- };
3831
- function CreateDocumentButton({ documentModelModule }: Props) {
3832
- const documentType = documentModelModule.documentModel.global.id;
3833
- const documentModelName =
3834
- documentModelModule.documentModel.global.name || documentType;
3835
- const documentModelDescription =
3836
- documentModelModule.documentModel.global.description;
3837
- return (
3838
- <button
3839
- className="cursor-pointer rounded-md bg-gray-200 py-2 px-3 hover:bg-gray-300"
3840
- title={documentModelName}
3841
- aria-description={documentModelDescription}
3842
- onClick={() => showCreateDocumentModal(documentType)}
3843
- >
3844
- {documentModelName}
3845
- </button>
3846
- );
3847
- }
3848
- `.raw;
3849
- //#endregion
3850
- //#region src/templates/drive-editor/components/DriveContents.ts
3851
- const driveEditorDriveContentsFileTemplate = () => tsx`
3852
- import { CreateDocument } from "./CreateDocument.js";
3853
- import { EmptyState } from "./EmptyState.js";
3854
- import { Files } from "./Files.js";
3855
- import { Folders } from "./Folders.js";
3856
- import { NavigationBreadcrumbs } from "./NavigationBreadcrumbs.js";
3857
-
3858
- /** Shows the documents and folders in the selected drive */
3859
- export function DriveContents() {
3860
- return (
3861
- <div className="space-y-6 px-6">
3862
- <NavigationBreadcrumbs />
3863
- <Folders />
3864
- <Files />
3865
- <EmptyState />
3866
- <CreateDocument />
3867
- </div>
3868
- );
3869
- }
3870
-
3871
-
3872
- `.raw;
3873
- //#endregion
3874
- //#region src/templates/drive-editor/components/DriveExplorer.ts
3875
- const driveExplorerFileTemplate = tsx`
3876
- import type { EditorProps } from "document-model";
3877
- import { FolderTree } from "./FolderTree.js";
3878
- import { DriveContents } from "./DriveContents.js";
3879
-
3880
- /**
3881
- * Main drive explorer component with sidebar navigation and content area.
3882
- * Layout: Left sidebar (folder tree) + Right content area (files/folders + document editor)
3883
- */
3884
- export function DriveExplorer({ children }: EditorProps) {
3885
- // if a document is selected then it's editor will be passed as children
3886
- const showDocumentEditor = !!children;
3887
-
3888
- return (
3889
- <div className="flex h-full">
3890
- <FolderTree />
3891
- <div className="flex-1 overflow-y-auto p-4">
3892
- {/* Conditional rendering: Document editor or folder contents */}
3893
- {showDocumentEditor ? (
3894
- /* Document editor view */
3895
- children
3896
- ) : (
3897
- /* Folder contents view */
3898
- <DriveContents />
3899
- )}
3900
- </div>
3901
- </div>
3902
- );
3903
- }
3904
- `.raw;
3905
- //#endregion
3906
- //#region src/templates/drive-editor/components/EmptyState.ts
3907
- const emptyStateFileTemplate = tsx`
3908
- import { useNodesInSelectedDriveOrFolder } from "@powerhousedao/reactor-browser";
3909
-
3910
- /** Shows a message when the selected drive or folder is empty */
3911
- export function EmptyState() {
3912
- const nodes = useNodesInSelectedDriveOrFolder();
3913
- const hasNodes = nodes.length > 0;
3914
- if (hasNodes) return null;
3915
-
3916
- return (
3917
- <div className="py-12 text-center text-gray-500">
3918
- <p className="text-lg">This folder is empty</p>
3919
- <p className="mt-2 text-sm">Create your first document or folder below</p>
3920
- </div>
3921
- );
3922
- }
3923
- `.raw;
3924
- //#endregion
3925
- //#region src/templates/drive-editor/components/Files.ts
3926
- const driveEditorFilesFileTemplate = () => tsx`
3927
- import { FileItem } from "@powerhousedao/design-system/connect";
3928
- import {
3929
- useNodesInSelectedDriveOrFolder,
3930
- isFileNodeKind,
3931
- } from "@powerhousedao/reactor-browser";
3932
-
3933
- /** Shows the files in the selected drive or folder */
3934
- export function Files() {
3935
- const nodes = useNodesInSelectedDriveOrFolder();
3936
- const fileNodes = nodes.filter((n) => isFileNodeKind(n));
3937
- const hasFiles = fileNodes.length > 0;
3938
-
3939
- if (!hasFiles) return null;
3940
-
3941
- return (
3942
- <div>
3943
- <h3 className="mb-2 text-sm font-semibold text-gray-600">Documents</h3>
3944
- <div className="flex flex-wrap gap-4">
3945
- {fileNodes.map((fileNode) => (
3946
- <FileItem key={fileNode.id} fileNode={fileNode} />
3947
- ))}
3948
- </div>
3949
- </div>
3950
- );
3951
- }
3952
-
3953
- `.raw;
3954
- //#endregion
3955
- //#region src/templates/drive-editor/components/Folders.ts
3956
- const driveEditorFoldersFileTemplate = () => tsx`
3957
- import { FolderItem } from "@powerhousedao/design-system/connect";
3958
- import {
3959
- useNodesInSelectedDriveOrFolder,
3960
- isFolderNodeKind,
3961
- } from "@powerhousedao/reactor-browser";
3962
-
3963
- /** Shows the folders in the selected drive or folder */
3964
- export function Folders() {
3965
- const nodes = useNodesInSelectedDriveOrFolder();
3966
- const folderNodes = nodes.filter((n) => isFolderNodeKind(n));
3967
- const hasFolders = folderNodes.length > 0;
3968
- if (!hasFolders) return null;
3969
-
3970
- return (
3971
- <div>
3972
- <h3 className="mb-2 text-sm font-bold text-gray-600">Folders</h3>
3973
- <div className="flex flex-wrap gap-4">
3974
- {folderNodes.map((folderNode) => (
3975
- <FolderItem key={folderNode.id} folderNode={folderNode} />
3976
- ))}
3977
- </div>
3978
- </div>
3979
- );
3980
- }
3981
- `.raw;
3982
- //#endregion
3983
- //#region src/templates/drive-editor/components/FolderTree.ts
3984
- const folderTreeFileTemplate = tsx`
3985
- import {
3986
- Sidebar,
3987
- SidebarProvider,
3988
- type SidebarNode,
3989
- } from "@powerhousedao/document-engineering";
3990
- import {
3991
- setSelectedNode,
3992
- useNodesInSelectedDrive,
3993
- useSelectedDrive,
3994
- useSelectedNode,
3995
- } from "@powerhousedao/reactor-browser";
3996
- import type { Node } from "@powerhousedao/shared/document-drive";
3997
- import { useMemo } from "react";
3998
-
3999
- function buildSidebarNodes(
4000
- nodes: Node[],
4001
- parentId: string | null | undefined,
4002
- ): SidebarNode[] {
4003
- return nodes
4004
- .filter((n) => {
4005
- if (parentId == null) {
4006
- return n.parentFolder == null;
4007
- }
4008
- return n.parentFolder === parentId;
4009
- })
4010
- .map((node): SidebarNode => {
4011
- if (node.kind === "folder") {
4012
- return {
4013
- id: node.id,
4014
- title: node.name,
4015
- icon: "FolderClose" as const,
4016
- expandedIcon: "FolderOpen" as const,
4017
- children: buildSidebarNodes(nodes, node.id),
4018
- };
4019
- }
4020
- return {
4021
- id: node.id,
4022
- title: node.name,
4023
- icon: "File" as const,
4024
- };
4037
+ expect(${isPhDocumentOfTypeFunctionName}(updatedDocument)).toBe(true);
4038
+ expect(updatedDocument.operations.${scope}).toHaveLength(1);
4039
+ expect(updatedDocument.operations.${scope}[0].action.type).toBe(
4040
+ "${constantCaseActionName}",
4041
+ );
4042
+ expect(updatedDocument.operations.${scope}[0].action.input).toStrictEqual(input);
4043
+ expect(updatedDocument.operations.${scope}[0].index).toEqual(0);
4025
4044
  });
4045
+ `.raw;
4026
4046
  }
4027
-
4028
- function transformNodesToSidebarNodes(
4029
- nodes: Node[],
4030
- driveName: string,
4031
- ): SidebarNode[] {
4032
- return [
4033
- {
4034
- id: "root",
4035
- title: driveName,
4036
- icon: "Drive" as const,
4037
- children: buildSidebarNodes(nodes, null),
4038
- },
4039
- ];
4047
+ function makeActionImportNames(v) {
4048
+ const actionNames = makeCamelCaseActionNamesForImport(v.actions);
4049
+ const inputSchemaNames = makeActionInputSchemasForImport(v.actions);
4050
+ return [
4051
+ "reducer",
4052
+ "utils",
4053
+ v.isPhDocumentOfTypeFunctionName,
4054
+ ...actionNames,
4055
+ ...inputSchemaNames
4056
+ ];
4040
4057
  }
4041
-
4058
+ function makeActionsImports(v) {
4059
+ return ts`
4060
+ import {
4061
+ ${makeActionImportNames(v).join("\n")}
4062
+ } from "${v.versionedDocumentModelPackageImportPath}";
4063
+ `.raw;
4064
+ }
4065
+ function makeTestCasesForActions(actions, isPhDocumentOfTypeFunctionName) {
4066
+ return actions.map((action) => makeTestCaseForAction(action, isPhDocumentOfTypeFunctionName)).join("\n\n");
4067
+ }
4068
+ const documentModelOperationsModuleTestFileTemplate = (v) => ts`
4042
4069
  /**
4043
- * Hierarchical folder tree navigation component using Sidebar from document-engineering.
4044
- * Displays folders and files in a tree structure with expand/collapse functionality, search, and resize support.
4070
+ * This is a scaffold file meant for customization:
4071
+ * - change it by adding new tests or modifying the existing ones
4045
4072
  */
4046
- export function FolderTree() {
4047
- const [selectedDrive] = useSelectedDrive();
4048
- const nodes = useNodesInSelectedDrive();
4049
- const selectedNode = useSelectedNode();
4050
- const driveName = selectedDrive.header.name;
4051
- // Transform Node[] to hierarchical SidebarNode structure
4052
- const sidebarNodes = useMemo(
4053
- () => transformNodesToSidebarNodes(nodes || [], driveName),
4054
- [nodes, driveName],
4055
- );
4056
4073
 
4057
- const handleActiveNodeChange = (node: SidebarNode) => {
4058
- // If root node is selected, pass undefined to match existing behavior
4059
- if (node.id === "root") {
4060
- setSelectedNode(undefined);
4061
- } else {
4062
- setSelectedNode(node.id);
4063
- }
4064
- };
4065
- // Map selectedNodeId to activeNodeId (use "root" when undefined)
4066
- const activeNodeId =
4067
- !selectedNode || selectedNode.id === selectedDrive.header.id
4068
- ? "root"
4069
- : selectedNode.id;
4074
+ import { describe, it, expect } from 'vitest';
4075
+ import { generateMock } from '@powerhousedao/common';
4076
+ import {
4077
+ reducer,
4078
+ utils,
4079
+ ${v.isPhDocumentOfTypeFunctionName},
4080
+ ${makeCamelCaseActionNamesForImport(v.actions)},
4081
+ ${makeActionInputSchemasForImport(v.actions)},
4082
+ } from "${v.versionedDocumentModelPackageImportPath}";
4083
+
4084
+ describe("${makeModuleOperationsTypeName(v.module)}", () => {
4085
+ ${makeTestCasesForActions(v.actions, v.isPhDocumentOfTypeFunctionName)}
4086
+ });
4070
4087
 
4071
- return (
4072
- <SidebarProvider nodes={sidebarNodes}>
4073
- <Sidebar
4074
- className="pt-1"
4075
- nodes={sidebarNodes}
4076
- activeNodeId={activeNodeId}
4077
- onActiveNodeChange={handleActiveNodeChange}
4078
- sidebarTitle="Drive Explorer"
4079
- showSearchBar={true}
4080
- resizable={true}
4081
- allowPinning={false}
4082
- showStatusFilter={false}
4083
- initialWidth={256}
4084
- defaultLevel={2}
4085
- />
4086
- </SidebarProvider>
4087
- );
4088
- }
4089
4088
  `.raw;
4090
4089
  //#endregion
4091
- //#region src/templates/drive-editor/components/NavigationBreadcrumbs.ts
4092
- const driveExplorerNavigationBreadcrumbsFileTemplate = () => tsx`
4093
- import { Breadcrumbs } from "@powerhousedao/design-system/connect";
4090
+ //#region src/templates/document-model/upgrades/upgrade-manifest.ts
4091
+ const upgradeManifestTemplate = (v) => ts`
4092
+ import type { UpgradeManifest } from "document-model";
4093
+ import { latestVersion, supportedVersions } from "./versions.js";
4094
4094
 
4095
- /** Shows the navigation breadcrumbs for the selected drive or folder */
4096
- export function NavigationBreadcrumbs() {
4097
- return (
4098
- <div className="border-b border-gray-200 pb-3 space-y-3">
4099
- <Breadcrumbs />
4100
- </div>
4101
- );
4102
- }
4103
- `.raw;
4095
+ export const ${v.upgradeManifestName}: UpgradeManifest<typeof supportedVersions> = {
4096
+ documentType: "${v.documentModelId}",
4097
+ latestVersion,
4098
+ supportedVersions,
4099
+ upgrades: {},
4100
+ };
4101
+ `.raw;
4104
4102
  //#endregion
4105
- //#region src/templates/drive-editor/config.ts
4106
- const driveEditorConfigFileTemplate = (v) => ts`
4107
- import type { PHDriveEditorConfig } from "@powerhousedao/reactor-browser";
4103
+ //#region src/templates/document-model/upgrades/upgrade-transition.ts
4104
+ const upgradeTransitionTemplate = (v) => ts`
4105
+ import type { Action, PHDocument, UpgradeTransition } from "document-model";
4106
+ import type { ${v.phStateName} as StateV${v.previousVersion} } from "${v.documentModelPackageImportPath}/v${v.previousVersion}";
4107
+ import type { ${v.phStateName} as StateV${v.version} } from "${v.documentModelPackageImportPath}/v${v.version}";
4108
4108
 
4109
- /** Editor config for the <%= pascalCaseDriveEditorName %> */
4110
- export const editorConfig: PHDriveEditorConfig = {
4111
- isDragAndDropEnabled: ${v.isDragAndDropEnabledString},
4112
- allowedDocumentTypes: ${v.allowedDocumentTypesString}
4109
+ function upgradeReducer(
4110
+ document: PHDocument<StateV${v.previousVersion}>,
4111
+ action: Action,
4112
+ ): PHDocument<StateV${v.version}> {
4113
+ return {
4114
+ ...document,
4115
+ };
4116
+ }
4117
+
4118
+ export const v${v.version}: UpgradeTransition = {
4119
+ toVersion: ${v.version},
4120
+ upgradeReducer,
4121
+ description: "",
4113
4122
  };
4114
4123
  `.raw;
4115
4124
  //#endregion
4116
- //#region src/templates/drive-editor/editor.ts
4117
- const driveEditorEditorFileTemplate = () => tsx`
4118
- import { useSetPHDriveEditorConfig } from "@powerhousedao/reactor-browser";
4119
- import type { EditorProps } from "document-model";
4120
- import { DriveExplorer } from "./components/DriveExplorer.js";
4121
- import { editorConfig } from "./config.js";
4125
+ //#region src/templates/document-model/utils.ts
4126
+ const documentModelUtilsTemplate = ({ phStateName, pascalCaseDocumentType }) => ts`
4127
+ import type { DocumentModelUtils } from "document-model";
4128
+ import type { ${phStateName} } from "./gen/types.js";
4129
+ import { utils as genUtils } from "./gen/utils.js";
4130
+ import * as customUtils from "./src/utils.js";
4122
4131
 
4123
- /** Editor component for the drive editor */
4124
- export default function Editor(props: EditorProps) {
4125
- // set the config for this drive editor
4126
- // you can update these configs in \`./config.ts\`
4127
- useSetPHDriveEditorConfig(editorConfig);
4128
- return (
4129
- <div className="bg-gray-50 p-6">
4130
- <DriveExplorer {...props} />
4131
- </div>
4132
- );
4133
- }
4132
+ /** Utils for the ${pascalCaseDocumentType} document model */
4133
+ export const utils: DocumentModelUtils<${phStateName}> = { ...genUtils, ...customUtils };
4134
4134
  `.raw;
4135
4135
  //#endregion
4136
4136
  //#region src/templates/processors/utils.ts
@@ -4165,6 +4165,12 @@ export const ${v.camelCaseName}FactoryBuilder: ProcessorFactoryBuilder = (module
4165
4165
  }
4166
4166
  `.raw;
4167
4167
  //#endregion
4168
+ //#region src/templates/processors/analytics/index.ts
4169
+ const analyticsIndexTemplate = ts`
4170
+ export * from "./factory.js";
4171
+ export * from "./processor.js";
4172
+ `.raw;
4173
+ //#endregion
4168
4174
  //#region src/templates/processors/analytics/processor.ts
4169
4175
  const analyticsProcessorTemplate = (v) => ts`
4170
4176
  import type { AnalyticsSeriesInput, AnalyticsPath, IAnalyticsStore } from "@powerhousedao/analytics-engine-core";
@@ -4197,10 +4203,11 @@ export class ${v.pascalCaseName} implements IProcessor {
4197
4203
  }
4198
4204
  `.raw;
4199
4205
  //#endregion
4200
- //#region src/templates/processors/analytics/index.ts
4201
- const analyticsIndexTemplate = ts`
4202
- export * from "./factory.js";
4203
- export * from "./processor.js";
4206
+ //#region src/templates/processors/factory-builders.ts
4207
+ const factoryBuildersTemplate = ts`
4208
+ import type { ProcessorFactoryBuilder } from "@powerhousedao/reactor";
4209
+
4210
+ export const processorFactoryBuilders: ProcessorFactoryBuilder[] = [];
4204
4211
  `.raw;
4205
4212
  //#endregion
4206
4213
  //#region src/templates/processors/factory.ts
@@ -4243,13 +4250,6 @@ export const processorFactory = async (module: IProcessorHostModule) => {
4243
4250
  };
4244
4251
  `.raw;
4245
4252
  //#endregion
4246
- //#region src/templates/processors/factory-builders.ts
4247
- const factoryBuildersTemplate = ts`
4248
- import type { ProcessorFactoryBuilder } from "@powerhousedao/reactor";
4249
-
4250
- export const processorFactoryBuilders: ProcessorFactoryBuilder[] = [];
4251
- `.raw;
4252
- //#endregion
4253
4253
  //#region src/templates/processors/index.ts
4254
4254
  const processorsIndexTemplate = ts`
4255
4255
  /**
@@ -4306,6 +4306,29 @@ export * from "./factory.js";
4306
4306
  export * from "./processor.js";
4307
4307
  `.raw;
4308
4308
  //#endregion
4309
+ //#region src/templates/processors/relational-db/migrations.ts
4310
+ const relationalDbMigrationsTemplate = () => ts`
4311
+ import type { IRelationalDb } from "@powerhousedao/reactor-browser"
4312
+
4313
+ export async function up(db: IRelationalDb<any>): Promise<void> {
4314
+ // Create table
4315
+ await db.schema
4316
+ .createTable("todo")
4317
+ .addColumn("task", "varchar(255)")
4318
+ .addColumn("status", "boolean")
4319
+ .addPrimaryKeyConstraint("todo_pkey", [
4320
+ "task"
4321
+ ])
4322
+ .ifNotExists()
4323
+ .execute();
4324
+ }
4325
+
4326
+ export async function down(db: IRelationalDb<any>): Promise<void> {
4327
+ // drop table
4328
+ await db.schema.dropTable("todo").execute();
4329
+ }
4330
+ `.raw;
4331
+ //#endregion
4309
4332
  //#region src/templates/processors/relational-db/processor.ts
4310
4333
  const defaultNamespaceComment = "// Default namespace: `${this.name}_${driveId.replaceAll(\"-\", \"_\")}`";
4311
4334
  const relationalDbProcessorTemplate = (v) => ts`
@@ -4334,29 +4357,6 @@ export class ${v.pascalCaseName} extends RelationalDbProcessor<DB> {
4334
4357
  }
4335
4358
  `.raw;
4336
4359
  //#endregion
4337
- //#region src/templates/processors/relational-db/migrations.ts
4338
- const relationalDbMigrationsTemplate = () => ts`
4339
- import type { IRelationalDb } from "@powerhousedao/reactor-browser"
4340
-
4341
- export async function up(db: IRelationalDb<any>): Promise<void> {
4342
- // Create table
4343
- await db.schema
4344
- .createTable("todo")
4345
- .addColumn("task", "varchar(255)")
4346
- .addColumn("status", "boolean")
4347
- .addPrimaryKeyConstraint("todo_pkey", [
4348
- "task"
4349
- ])
4350
- .ifNotExists()
4351
- .execute();
4352
- }
4353
-
4354
- export async function down(db: IRelationalDb<any>): Promise<void> {
4355
- // drop table
4356
- await db.schema.dropTable("todo").execute();
4357
- }
4358
- `.raw;
4359
- //#endregion
4360
4360
  //#region src/templates/processors/relational-db/schema.ts
4361
4361
  const relationalDbSchemaTemplate = () => ts`
4362
4362
  export interface Todo {
@@ -4606,6 +4606,6 @@ function camel(name) {
4606
4606
  return p.charAt(0).toLowerCase() + p.slice(1);
4607
4607
  }
4608
4608
  //#endregion
4609
- export { documentModelDocumentSchemaFileTemplate as $, upgradeManifestTemplate as A, eslintConfigTemplate as At, documentModelHooksFileTemplate as B, claudeSettingsLocalTemplate as Bt, driveEditorFilesFileTemplate as C, indexTsTemplate as Ct, createDocumentFileTemplate as D, gitIgnoreTemplate as Dt, driveEditorDriveContentsFileTemplate as E, indexHtmlTemplate as Et, makeTestCaseForAction as F, switchboardEntrypointTemplate as Ft, documentModelPhFactoriesFileTemplate as G, documentModelGenTypesTemplate as H, documentModelTestFileTemplate as I, nginxConfTemplate as It, documentModelOperationsModuleCreatorsFileTemplate as J, documentModelOperationsModuleOperationsFileTemplate as K, documentModelSrcIndexFileTemplate as L, dockerfileTemplate as Lt, documentModelOperationsModuleTestFileTemplate as M, editorsTemplate as Mt, makeActionImportNames as N, documentModelsIndexTemplate as Nt, documentModelUtilsTemplate as O, syncAndPublishWorkflowTemplate as Ot, makeActionsImports as P, documentModelsTemplate as Pt, documentModelDocumentTypeTemplate as Q, documentModelModuleFileTemplate as R, connectEntrypointTemplate as Rt, driveEditorFoldersFileTemplate as S, licenseTemplate as St, driveExplorerFileTemplate as T, legacyIndexHtmlTemplate as Tt, documentModelSchemaIndexTemplate as U, documentModelGenUtilsTemplate as V, agentsTemplate as Vt, documentModelGenReducerFileTemplate as W, getModuleExportType as X, documentModelOperationModuleActionsFileTemplate as Y, documentModelGenIndexFileTemplate as Z, analyticsFactoryTemplate as _, packageJsonScriptsTemplate as _t, subgraphLibFileTemplate as a, documentEditorEditorFileTemplate as at, driveExplorerNavigationBreadcrumbsFileTemplate as b, npmrcTemplate as bt, relationalDbMigrationsTemplate as c, viteConfigTemplate as ct, relationalDbFactoryTemplate as d, subgraphsIndexTemplate as dt, documentModelGenCreatorsFileTemplate as et, processorsIndexTemplate as f, styleTemplate as ft, analyticsProcessorTemplate as g, packageJsonExportsTemplate as gt, analyticsIndexTemplate as h, buildPowerhouseConfigTemplate as ht, customSubgraphSchemaTemplate as i, documentEditorModuleFileTemplate as it, documentModelSrcUtilsTemplate as j, editorsIndexTemplate as jt, upgradeTransitionTemplate as k, geminiSettingsTemplate as kt, relationalDbProcessorTemplate as l, tsConfigTemplate as lt, processorsFactoryTemplate as m, powerhouseManifestTemplate as mt, documentModelSubgraphSchemaTemplate as n, documentModelGenActionsFileTemplate as nt, subgraphIndexFileTemplate as o, docsFromCliHelpTemplate as ot, factoryBuildersTemplate as p, readmeTemplate as pt, documentModelOperationsModuleErrorFileTemplate as q, customSubgraphResolversTemplate as r, documentModelRootActionsFileTemplate as rt, relationalDbSchemaTemplate as s, vitestConfigTemplate as st, documentModelSubgraphResolversTemplate as t, documentModelGenControllerFileTemplate as tt, relationalDbIndexTemplate as u, tsconfigPathsTemplate as ut, driveEditorEditorFileTemplate as v, exportsTemplate as vt, emptyStateFileTemplate as w, mainTsxTemplate as wt, folderTreeFileTemplate as x, mcpTemplate as xt, driveEditorConfigFileTemplate as y, packageJsonTemplate as yt, documentModelIndexTemplate as z, cursorMcpTemplate as zt };
4609
+ export { tsConfigTemplate as $, documentModelHooksFileTemplate as A, claudeSettingsLocalTemplate as At, getModuleExportType as B, appDriveContentsFileTemplate as Bt, makeActionsImports as C, documentModelsIndexTemplate as Ct, documentModelSrcIndexFileTemplate as D, dockerfileTemplate as Dt, documentModelSrcUtilsTemplate as E, nginxConfTemplate as Et, documentModelPhFactoriesFileTemplate as F, folderTreeFileTemplate as Ft, documentModelGenControllerFileTemplate as G, documentModelDocumentTypeTemplate as H, documentModelOperationsModuleOperationsFileTemplate as I, appFoldersFileTemplate as It, documentEditorModuleFileTemplate as J, documentModelGenActionsFileTemplate as K, documentModelOperationsModuleErrorFileTemplate as L, appFilesFileTemplate as Lt, documentModelGenTypesTemplate as M, appEditorFileTemplate as Mt, documentModelSchemaIndexTemplate as N, appConfigFileTemplate as Nt, documentModelModuleFileTemplate as O, connectEntrypointTemplate as Ot, documentModelGenReducerFileTemplate as P, driveExplorerNavigationBreadcrumbsFileTemplate as Pt, viteConfigTemplate as Q, documentModelOperationsModuleCreatorsFileTemplate as R, emptyStateFileTemplate as Rt, makeActionImportNames as S, editorsTemplate as St, documentModelTestFileTemplate as T, switchboardEntrypointTemplate as Tt, documentModelDocumentSchemaFileTemplate as U, documentModelGenIndexFileTemplate as V, createDocumentFileTemplate as Vt, documentModelGenCreatorsFileTemplate as W, docsFromCliHelpTemplate as X, documentEditorEditorFileTemplate as Y, vitestConfigTemplate as Z, analyticsFactoryTemplate as _, gitIgnoreTemplate as _t, subgraphLibFileTemplate as a, buildPowerhouseConfigTemplate as at, upgradeManifestTemplate as b, eslintConfigTemplate as bt, relationalDbProcessorTemplate as c, exportsTemplate as ct, relationalDbFactoryTemplate as d, mcpTemplate as dt, tsconfigPathsTemplate as et, processorsIndexTemplate as f, mainTsxTemplate as ft, analyticsIndexTemplate as g, indexHtmlTemplate as gt, analyticsProcessorTemplate as h, legacyIndexHtmlTemplate as ht, customSubgraphSchemaTemplate as i, powerhouseManifestTemplate as it, documentModelGenUtilsTemplate as j, agentsTemplate as jt, documentModelIndexTemplate as k, cursorMcpTemplate as kt, relationalDbMigrationsTemplate as l, packageJsonTemplate as lt, factoryBuildersTemplate as m, indexTsTemplate as mt, documentModelSubgraphSchemaTemplate as n, styleTemplate as nt, subgraphIndexFileTemplate as o, packageJsonExportsTemplate as ot, processorsFactoryTemplate as p, licenseTemplate as pt, documentModelRootActionsFileTemplate as q, customSubgraphResolversTemplate as r, readmeTemplate as rt, relationalDbSchemaTemplate as s, packageJsonScriptsTemplate as st, documentModelSubgraphResolversTemplate as t, subgraphsIndexTemplate as tt, relationalDbIndexTemplate as u, npmrcTemplate as ut, documentModelUtilsTemplate as v, syncAndPublishWorkflowTemplate as vt, makeTestCaseForAction as w, documentModelsTemplate as wt, documentModelOperationsModuleTestFileTemplate as x, editorsIndexTemplate as xt, upgradeTransitionTemplate as y, geminiSettingsTemplate as yt, documentModelOperationModuleActionsFileTemplate as z, driveExplorerFileTemplate as zt };
4610
4610
 
4611
- //# sourceMappingURL=templates-CKdxigVj.mjs.map
4611
+ //# sourceMappingURL=templates-DBvz_qPL.mjs.map