@powerhousedao/ph-clint-cli 0.1.0-dev.11 → 0.1.0-dev.110

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 (110) hide show
  1. package/dist/cli.js +53 -16
  2. package/dist/codegen/index.d.ts +8 -36
  3. package/dist/codegen/index.js +6 -293
  4. package/dist/commands/clint-project-build.d.ts +73 -1
  5. package/dist/commands/clint-project-build.js +11 -28
  6. package/dist/commands/clint-project-init.d.ts +126 -10
  7. package/dist/commands/clint-project-init.js +72 -47
  8. package/dist/commands/clint-project-publish.d.ts +74 -1
  9. package/dist/commands/clint-project-publish.js +6 -4
  10. package/dist/commands/clint-project-regen.d.ts +73 -1
  11. package/dist/commands/clint-project-regen.js +26 -2
  12. package/dist/commands/clint-skills-sync.d.ts +82 -0
  13. package/dist/commands/clint-skills-sync.js +56 -0
  14. package/dist/framework.d.ts +318 -80
  15. package/dist/framework.gen.d.ts +50 -14
  16. package/dist/framework.js +1 -5
  17. package/{prompts/agent-profiles/AgentBase.md → dist/gen/agent-profiles/PhClintDevAgent.md} +1 -1
  18. package/dist/gen/skills/cli-setup/.cli-docs.md +135 -0
  19. package/dist/gen/skills/cli-setup/SKILL.md +125 -0
  20. package/dist/gen/skills/cli-setup/references/00.assess-cli-needs.md +53 -0
  21. package/dist/gen/skills/cli-setup/references/01.define-config-schema.md +78 -0
  22. package/dist/gen/skills/cli-setup/references/02.wire-cli.md +141 -0
  23. package/dist/gen/skills/cli-setup/references/03.add-entrypoint.md +128 -0
  24. package/dist/gen/skills/cli-setup/references/expected-outcome.md +3 -0
  25. package/dist/gen/skills/command-definition/.cli-docs.md +84 -0
  26. package/dist/gen/skills/command-definition/SKILL.md +99 -0
  27. package/dist/gen/skills/command-definition/references/00.assess-requirements.md +58 -0
  28. package/dist/gen/skills/command-definition/references/01.define-schema.md +72 -0
  29. package/dist/gen/skills/command-definition/references/02.implement-execute.md +118 -0
  30. package/dist/gen/skills/command-definition/references/03.add-prompting.md +54 -0
  31. package/dist/gen/skills/command-definition/references/expected-outcome.md +3 -0
  32. package/dist/gen/skills/service-definition/.cli-docs.md +214 -0
  33. package/dist/gen/skills/service-definition/SKILL.md +148 -0
  34. package/dist/gen/skills/service-definition/references/00.assess-service.md +69 -0
  35. package/dist/gen/skills/service-definition/references/01.define-service.md +166 -0
  36. package/dist/gen/skills/service-definition/references/02.add-preflight.md +132 -0
  37. package/dist/gen/skills/service-definition/references/03.add-project-scanner.md +82 -0
  38. package/dist/gen/skills/service-definition/references/04.wire-events.md +120 -0
  39. package/dist/gen/skills/service-definition/references/expected-outcome.md +3 -0
  40. package/dist/main.js +0 -0
  41. package/dist/services/clint-project.js +21 -0
  42. package/dist/spec/ensure-document.d.ts +17 -0
  43. package/dist/spec/ensure-document.js +56 -0
  44. package/dist/spec/file.d.ts +1 -4
  45. package/dist/spec/file.js +1 -34
  46. package/dist/spec/from-document.d.ts +4 -1
  47. package/dist/spec/from-document.js +4 -16
  48. package/dist/spec/types.d.ts +1 -62
  49. package/dist/spec/types.js +1 -112
  50. package/dist/triggers/publish-trigger.d.ts +77 -0
  51. package/dist/triggers/publish-trigger.js +137 -0
  52. package/dist/triggers/spec-change.d.ts +60 -22
  53. package/dist/triggers/spec-change.js +154 -101
  54. package/package.json +31 -31
  55. package/dist/codegen/builders/agent-base-md.d.ts +0 -5
  56. package/dist/codegen/builders/agent-base-md.js +0 -18
  57. package/dist/codegen/builders/agent-ts.d.ts +0 -9
  58. package/dist/codegen/builders/agent-ts.js +0 -34
  59. package/dist/codegen/builders/app-index-ts.d.ts +0 -18
  60. package/dist/codegen/builders/app-index-ts.js +0 -33
  61. package/dist/codegen/builders/build-skills-ts.d.ts +0 -4
  62. package/dist/codegen/builders/build-skills-ts.js +0 -37
  63. package/dist/codegen/builders/cli-package-json.d.ts +0 -8
  64. package/dist/codegen/builders/cli-package-json.js +0 -96
  65. package/dist/codegen/builders/cli-ts.d.ts +0 -7
  66. package/dist/codegen/builders/cli-ts.js +0 -132
  67. package/dist/codegen/builders/config-ts.d.ts +0 -8
  68. package/dist/codegen/builders/config-ts.js +0 -17
  69. package/dist/codegen/builders/eslint-config-js.d.ts +0 -4
  70. package/dist/codegen/builders/eslint-config-js.js +0 -13
  71. package/dist/codegen/builders/framework-gen-ts.d.ts +0 -20
  72. package/dist/codegen/builders/framework-gen-ts.js +0 -62
  73. package/dist/codegen/builders/framework-ts.d.ts +0 -21
  74. package/dist/codegen/builders/framework-ts.js +0 -74
  75. package/dist/codegen/builders/gitignore.d.ts +0 -4
  76. package/dist/codegen/builders/gitignore.js +0 -18
  77. package/dist/codegen/builders/index.d.ts +0 -44
  78. package/dist/codegen/builders/index.js +0 -61
  79. package/dist/codegen/builders/jest-config-js.d.ts +0 -4
  80. package/dist/codegen/builders/jest-config-js.js +0 -19
  81. package/dist/codegen/builders/main-ts.d.ts +0 -5
  82. package/dist/codegen/builders/main-ts.js +0 -13
  83. package/dist/codegen/builders/mastra-index-ts.d.ts +0 -8
  84. package/dist/codegen/builders/mastra-index-ts.js +0 -30
  85. package/dist/codegen/builders/publish-config-ts.d.ts +0 -6
  86. package/dist/codegen/builders/publish-config-ts.js +0 -18
  87. package/dist/codegen/builders/readme-md.d.ts +0 -5
  88. package/dist/codegen/builders/readme-md.js +0 -44
  89. package/dist/codegen/builders/root-package-json.d.ts +0 -10
  90. package/dist/codegen/builders/root-package-json.js +0 -40
  91. package/dist/codegen/builders/tsconfig-json.d.ts +0 -4
  92. package/dist/codegen/builders/tsconfig-json.js +0 -22
  93. package/dist/codegen/exec.d.ts +0 -20
  94. package/dist/codegen/exec.js +0 -41
  95. package/dist/codegen/hashes.d.ts +0 -6
  96. package/dist/codegen/hashes.js +0 -60
  97. package/dist/codegen/markers.d.ts +0 -36
  98. package/dist/codegen/markers.js +0 -86
  99. package/dist/codegen/migrate/flat-to-split.d.ts +0 -15
  100. package/dist/codegen/migrate/flat-to-split.js +0 -119
  101. package/dist/codegen/scaffold.d.ts +0 -34
  102. package/dist/codegen/scaffold.js +0 -60
  103. package/dist/codegen/write.d.ts +0 -6
  104. package/dist/codegen/write.js +0 -32
  105. package/dist/commands/init.d.ts +0 -57
  106. package/dist/commands/init.js +0 -168
  107. package/dist/commands/regen.d.ts +0 -18
  108. package/dist/commands/regen.js +0 -68
  109. package/prompts/skills-ext/.gitkeep +0 -0
  110. package/prompts/skills-tpl/.gitkeep +0 -0
@@ -1,26 +1,29 @@
1
1
  /**
2
- * `spec-change` trigger — watches the `powerhouse/ph-clint-project` document
3
- * on the Reactor drive and, when its state changes, enqueues a work item
4
- * that re-runs the code generator in update mode.
2
+ * `spec-change` trigger — watches ALL `powerhouse/ph-clint-project` documents
3
+ * and, when any change, re-runs the code generator for each affected project.
5
4
  *
6
5
  * Flow:
7
6
  * 1. `createDocumentChangeTrigger` (from ph-clint) owns the subscription,
8
- * event coalescing, doc loading, and type narrowing.
9
- * 2. `documentId` resolves the target doc lazily: it prefers
10
- * `config.projectDocumentId`, falling back to a drive scan for the first
11
- * `powerhouse/ph-clint-project` document (and pinning the id into local
12
- * config on success).
13
- * 3. `onChange` converts the doc state to a `ClintProjectSpec`, hashes it,
7
+ * event coalescing, doc loading, and type narrowing. No `documentId` is
8
+ * set, so it loads ALL matching documents on each poll.
9
+ * 2. `getProjectMapping()` merges an on-disk scan (via the clint-project
10
+ * service's projectScanner) with personal-drive folder entries to
11
+ * correlate each document to an on-disk project directory.
12
+ * 3. For each document, `specFromDocumentState()` builds a spec, hashes it,
14
13
  * and compares against `.ph/ph-clint-cli/.last-spec-hash`. If unchanged,
15
- * emits nothing. If different, returns a `function` work item that calls
16
- * `generateProject(spec, workdir, 'update')` and writes the new hash.
14
+ * skips. Otherwise regenerates at the mapped target directory.
17
15
  */
18
16
  import crypto from 'node:crypto';
19
17
  import fs from 'node:fs/promises';
20
18
  import path from 'node:path';
19
+ import { scanProjects, getProjectMapping } from '@powerhousedao/ph-clint';
21
20
  import { createDocumentChangeTrigger } from '../framework.js';
22
21
  import { generateProject } from '../codegen/index.js';
22
+ import { runPostGenActions } from '@powerhousedao/ph-clint-dev/codegen/actions';
23
23
  import { specFromDocumentState } from '../spec/from-document.js';
24
+ import { readProjectSpec, writeProjectSpec } from '../spec/file.js';
25
+ import { ensureSpecDocument } from '../spec/ensure-document.js';
26
+ import { clintProject } from '../services/clint-project.js';
24
27
  const DOCUMENT_TYPE = 'powerhouse/ph-clint-project';
25
28
  const HASH_DIR = path.join('.ph', 'ph-clint-cli');
26
29
  const HASH_FILE = '.last-spec-hash';
@@ -49,11 +52,13 @@ async function writeLastSpecHash(targetDir, hash) {
49
52
  await fs.mkdir(path.dirname(file), { recursive: true });
50
53
  await fs.writeFile(file, hash + '\n', 'utf8');
51
54
  }
52
- /** Stable hash of a ClintProjectSpec (sha256 of canonical-key JSON). */
55
+ /** Stable hash of a ClintProjectSpec (sha256 of canonical-key JSON).
56
+ * Excludes documentId/documentType — they don't affect codegen output. */
53
57
  export function hashSpec(spec) {
58
+ const { documentId, documentType, ...codegenRelevant } = spec;
54
59
  return crypto
55
60
  .createHash('sha256')
56
- .update(canonicalJson(spec), 'utf8')
61
+ .update(canonicalJson(codegenRelevant), 'utf8')
57
62
  .digest('hex');
58
63
  }
59
64
  function canonicalJson(value) {
@@ -70,102 +75,150 @@ function canonicalJson(value) {
70
75
  .join(',') +
71
76
  '}');
72
77
  }
73
- /** Find the first ph-clint-project document on the default drive. */
74
- async function findProjectDocumentId(client, driveId) {
75
- try {
76
- const children = await client.getChildren(driveId);
77
- const results = (children?.results ?? []);
78
- for (const node of results) {
79
- if (node.header?.documentType === DOCUMENT_TYPE && node.header.id) {
80
- return node.header.id;
78
+ export function specToImportInput(spec) {
79
+ const main = spec.features.mastra.mainAgent;
80
+ return {
81
+ name: spec.name,
82
+ scope: spec.scope ?? null,
83
+ version: spec.version,
84
+ description: spec.description,
85
+ powerhouse: spec.features.powerhouse,
86
+ mastraEnabled: spec.features.mastra.enabled,
87
+ routineEnabled: spec.features.routine.enabled,
88
+ mainAgent: main
89
+ ? {
90
+ id: main.id,
91
+ name: main.name,
92
+ description: main.description,
93
+ attachment: main.image,
94
+ modelId: main.modelId,
95
+ profileIds: [...main.profileIds],
96
+ skills: [...main.skills],
97
+ toolPatterns: [...main.toolPatterns],
81
98
  }
82
- }
83
- }
84
- catch {
85
- // fall through
86
- }
87
- return undefined;
99
+ : null,
100
+ subAgents: spec.features.mastra.subAgents.map((s) => ({
101
+ id: s.id,
102
+ name: s.name,
103
+ description: s.description,
104
+ modelId: s.modelId,
105
+ profileIds: [...s.profileIds],
106
+ skills: [...s.skills],
107
+ toolPatterns: [...s.toolPatterns],
108
+ })),
109
+ models: spec.features.mastra.models.map((m) => ({
110
+ id: m.id,
111
+ })),
112
+ profiles: spec.features.mastra.profiles.map((p) => ({
113
+ id: p.id,
114
+ title: p.title,
115
+ content: p.content,
116
+ })),
117
+ packages: spec.packages.map((p) => ({
118
+ id: p.id,
119
+ packageName: p.packageName,
120
+ documentTypes: p.documentTypes,
121
+ })),
122
+ externalSkills: spec.externalSkills.map((s) => ({
123
+ id: s.id,
124
+ name: s.name,
125
+ githubUrl: s.githubUrl,
126
+ })),
127
+ enableChat: spec.features.mastra.common.enableChat,
128
+ proxyEnabled: spec.deployment.proxyEnabled,
129
+ observabilityEnabled: spec.deployment.observabilityEnabled,
130
+ supportedResources: spec.deployment.supportedResources,
131
+ };
88
132
  }
89
133
  export const specChangeTrigger = createDocumentChangeTrigger({
90
134
  id: 'spec-change',
91
135
  documentType: DOCUMENT_TYPE,
92
- // Resolve the target id lazily so we can also do first-time discovery and
93
- // persist the discovered id into local config.
94
- documentId: async (ctx) => {
95
- const configured = ctx.context.config.projectDocumentId &&
96
- ctx.context.config.projectDocumentId.length > 0
97
- ? ctx.context.config.projectDocumentId
98
- : undefined;
99
- if (configured)
100
- return configured;
136
+ // No documentId → watches ALL ph-clint-project docs
137
+ callOnEmpty: true, // bootstrap from disk when no documents exist yet
138
+ async onChange(docs, ctx) {
139
+ const log = ctx.context.log;
140
+ const folders = ctx.context.folders;
141
+ // Build the mapping: on-disk projects + personal drive documents
142
+ const scanner = clintProject.projectScanner;
143
+ const scanResults = scanner
144
+ ? scanProjects(ctx.context.workdir, scanner)
145
+ : [];
146
+ const mapping = await getProjectMapping(scanResults, folders);
147
+ // Auto-create spec documents for unlinked or orphaned projects
101
148
  const reactor = await ctx.reactor();
102
- if (!reactor)
103
- return undefined;
104
- const discovered = await findProjectDocumentId(reactor.client, reactor.driveId);
105
- if (!discovered) {
106
- ctx.context.log?.debug(`${TAG} no ${DOCUMENT_TYPE} document found on drive ${reactor.driveId}`);
107
- return undefined;
149
+ if (reactor && folders) {
150
+ for (const entry of mapping) {
151
+ if (!entry.path)
152
+ continue;
153
+ const existingSpec = await readProjectSpec(entry.path);
154
+ if (!existingSpec)
155
+ continue;
156
+ try {
157
+ const { docId, created } = await ensureSpecDocument({
158
+ spec: existingSpec,
159
+ targetDir: entry.path,
160
+ reactor,
161
+ folders,
162
+ });
163
+ if (created) {
164
+ log?.info(`${TAG} linked project ${entry.name} to document ${docId}`);
165
+ }
166
+ }
167
+ catch (err) {
168
+ log?.warn(`${TAG} could not ensure spec document for ${entry.name}: ${err instanceof Error ? err.message : String(err)}`);
169
+ }
170
+ }
108
171
  }
109
- // Persist into local config + mutate in-memory so future ticks skip discovery.
110
- try {
111
- const current = await ctx.context.workspace.loadLocalConfig({});
112
- await ctx.context.workspace.storeLocalConfig({
113
- ...current,
114
- projectDocumentId: discovered,
172
+ for (const doc of docs) {
173
+ const spec = specFromDocumentState(doc.state.global, {
174
+ documentId: doc.header.id,
175
+ documentType: doc.header.documentType,
176
+ });
177
+ if (!spec) {
178
+ log?.debug(`${TAG} document ${doc.header.id} state did not validate against ClintProjectSpec, skipping`);
179
+ continue;
180
+ }
181
+ // Find target directory from mapping
182
+ const entry = mapping.find((m) => m.documentId === doc.header.id);
183
+ const targetDir = entry?.path ?? path.join(ctx.context.workdir, spec.name);
184
+ // Per-project hash comparison
185
+ const nextHash = hashSpec(spec);
186
+ const prevHash = await readLastSpecHash(targetDir);
187
+ if (nextHash === prevHash) {
188
+ log?.debug(`${TAG} spec for ${spec.name} unchanged (hash=${nextHash.slice(0, 12)}…), skipping`);
189
+ continue;
190
+ }
191
+ log?.debug(`${TAG} spec for ${spec.name} changed: ${prevHash ? prevHash.slice(0, 12) + '…' : '<none>'} → ${nextHash.slice(0, 12)}…`);
192
+ log?.info(`${TAG} regenerating ${spec.name} at ${targetDir} (doc=${doc.header.id})`);
193
+ const t0 = Date.now();
194
+ const warnings = [];
195
+ const result = await generateProject({
196
+ targetDir,
197
+ spec,
198
+ mode: 'update',
199
+ force: true,
200
+ onWarn: (m) => warnings.push(m),
201
+ });
202
+ // Write spec JSON with documentId
203
+ await writeProjectSpec(targetDir, spec);
204
+ await writeLastSpecHash(targetDir, nextHash);
205
+ const elapsed = Date.now() - t0;
206
+ if (log) {
207
+ if (result.migrated)
208
+ log.info(`${TAG} migrated flat → split layout`);
209
+ log.info(`${TAG} regenerated ${spec.name} in ${elapsed}ms: ${result.files.length} written, ${result.skipped.length} skipped, ${result.deleted.length} deleted`);
210
+ for (const w of warnings)
211
+ log.warn(`${TAG} ${w}`);
212
+ }
213
+ // Run post-generation actions (ph-init, install, build, skills-sync).
214
+ // Route through ctx.context.stdout so output flows through
215
+ // routine.onOutput → service log buffer → ServicePanel.
216
+ await runPostGenActions(result.pendingActions, {
217
+ log: (msg) => ctx.context.stdout(`${TAG} ${msg}\n`),
218
+ runProcess: ctx.context.runProcess,
115
219
  });
116
- ctx.context.config.projectDocumentId = discovered;
117
- ctx.context.log?.info(`${TAG} pinned projectDocumentId=${discovered} in ${ctx.context.workspace.getLocalConfigPath()}`);
118
- }
119
- catch (err) {
120
- ctx.context.log?.warn(`${TAG} failed to persist projectDocumentId: ${err instanceof Error ? err.message : String(err)}`);
121
- }
122
- return discovered;
123
- },
124
- async onChange(doc, ctx) {
125
- const log = ctx.context.log;
126
- const spec = specFromDocumentState(doc.state.global);
127
- if (!spec) {
128
- log?.debug(`${TAG} document ${doc.header.id} state did not validate against ClintProjectSpec, skipping`);
129
- return null;
130
- }
131
- const targetDir = ctx.context.workdir;
132
- const nextHash = hashSpec(spec);
133
- const prevHash = await readLastSpecHash(targetDir);
134
- if (nextHash === prevHash) {
135
- log?.debug(`${TAG} spec unchanged (hash=${nextHash.slice(0, 12)}…), nothing to do`);
136
- return null;
137
220
  }
138
- log?.debug(`${TAG} spec changed: ${prevHash ? prevHash.slice(0, 12) + '…' : '<none>'} → ${nextHash.slice(0, 12)}…`);
139
- return {
140
- type: 'function',
141
- params: {
142
- fn: async () => {
143
- log?.info(`${TAG} regenerating project at ${targetDir} (doc=${doc.header.id})`);
144
- const t0 = Date.now();
145
- const warnings = [];
146
- const result = await generateProject({
147
- targetDir,
148
- spec,
149
- mode: 'update',
150
- onWarn: (m) => warnings.push(m),
151
- });
152
- await writeLastSpecHash(targetDir, nextHash);
153
- const elapsed = Date.now() - t0;
154
- if (log) {
155
- if (result.migrated)
156
- log.info(`${TAG} migrated flat → split layout`);
157
- log.info(`${TAG} regenerated in ${elapsed}ms: ${result.files.length} written, ${result.skipped.length} skipped, ${result.deleted.length} deleted`);
158
- for (const w of warnings)
159
- log.warn(`${TAG} ${w}`);
160
- }
161
- },
162
- },
163
- callbacks: {
164
- onFailure: (err) => {
165
- log?.error(`${TAG} regen failed: ${err.message}`);
166
- log?.debug(`${TAG} stack: ${err.stack ?? '<no stack>'}`);
167
- },
168
- },
169
- };
221
+ // Work done inline, no additional work item needed
222
+ return null;
170
223
  },
171
224
  });
package/package.json CHANGED
@@ -1,6 +1,11 @@
1
1
  {
2
2
  "name": "@powerhousedao/ph-clint-cli",
3
- "version": "0.1.0-dev.11",
3
+ "version": "0.1.0-dev.110",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/powerhouse-inc/ph-clint.git",
7
+ "directory": "packages/ph-clint-cli/ph-clint-cli"
8
+ },
4
9
  "publishConfig": {
5
10
  "access": "public"
6
11
  },
@@ -10,40 +15,23 @@
10
15
  "ph-clint": "./dist/main.js"
11
16
  },
12
17
  "files": [
13
- "dist",
14
- "prompts"
18
+ "dist"
15
19
  ],
16
- "scripts": {
17
- "build:skills": "tsx scripts/build-skills.ts",
18
- "build": "pnpm build:skills && tsc",
19
- "dev": "tsx src/main.ts",
20
- "start": "node dist/main.js",
21
- "test": "NODE_OPTIONS='--experimental-vm-modules' jest --detectOpenHandles",
22
- "lint": "eslint src",
23
- "mastra:dev": "mastra dev",
24
- "mastra:build": "mastra build",
25
- "mastra:start": "mastra start"
26
- },
27
20
  "dependencies": {
28
- "@powerhousedao/ph-clint": "^0.1.0-dev.11",
29
- "@powerhousedao/ph-clint-app": "^0.1.0-dev.11",
30
- "@mastra/core": "^1.22.0",
31
- "@mastra/libsql": "^1.7.4",
32
- "@mastra/memory": "^1.13.1",
33
- "@powerhousedao/reactor": "6.0.0-dev.170",
34
- "@powerhousedao/reactor-api": "6.0.0-dev.170",
35
- "@powerhousedao/shared": "6.0.0-dev.170",
36
21
  "@electric-sql/pglite": "0.3.15",
37
- "document-model": "6.0.0-dev.170",
22
+ "@mastra/core": "^1.41.0",
23
+ "@mastra/libsql": "^1.12.1",
24
+ "@mastra/memory": "^1.20.2",
25
+ "@powerhousedao/reactor": "6.2.3",
26
+ "@powerhousedao/reactor-api": "6.2.3",
27
+ "@powerhousedao/shared": "6.2.3",
28
+ "document-model": "6.2.3",
38
29
  "kysely": "^0.27.0",
39
30
  "kysely-pglite-dialect": "^1.3.0",
40
- "@powerhousedao/ph-clint-dev": "^0.1.0-dev.11",
41
- "zod": "^4.3.6"
42
- },
43
- "pnpm": {
44
- "overrides": {
45
- "mastra>@mastra/deployer": "1.22.0"
46
- }
31
+ "zod": "4.3.6",
32
+ "@powerhousedao/ph-clint-dev": "0.1.0-dev.110",
33
+ "@powerhousedao/ph-clint": "0.1.0-dev.110",
34
+ "@powerhousedao/ph-clint-app": "0.1.0-dev.110"
47
35
  },
48
36
  "devDependencies": {
49
37
  "@jest/globals": "^30.2.0",
@@ -55,5 +43,17 @@
55
43
  },
56
44
  "engines": {
57
45
  "node": ">=22.13.0"
46
+ },
47
+ "scripts": {
48
+ "build:skills": "tsx scripts/build-skills.ts",
49
+ "build": "pnpm build:skills && tsc",
50
+ "dev": "tsx src/main.ts",
51
+ "start": "node dist/main.js",
52
+ "test": "NODE_OPTIONS='--experimental-vm-modules' jest --detectOpenHandles --coverage",
53
+ "test:e2e": "NODE_OPTIONS='--experimental-vm-modules' jest --detectOpenHandles --testPathPatterns 'tests/(e2e|codegen-e2e)/' --testPathIgnorePatterns '/node_modules/'",
54
+ "lint": "eslint src",
55
+ "mastra:dev": "mastra dev",
56
+ "mastra:build": "mastra build",
57
+ "mastra:start": "mastra start"
58
58
  }
59
- }
59
+ }
@@ -1,5 +0,0 @@
1
- /**
2
- * Builds `prompts/agent-profiles/AgentBase.md` — the minimal base profile.
3
- */
4
- import { type ClintProjectSpec } from '../../spec/types.js';
5
- export declare function buildAgentBaseMd(spec: ClintProjectSpec): string;
@@ -1,18 +0,0 @@
1
- /**
2
- * Builds `prompts/agent-profiles/AgentBase.md` — the minimal base profile.
3
- */
4
- import { getPackageName, } from '../../spec/types.js';
5
- export function buildAgentBaseMd(spec) {
6
- return [
7
- '# Agent Base System Prompt',
8
- '',
9
- `You are {{agentName}}, an agent available through the ${getPackageName(spec)} CLI.`,
10
- '',
11
- '## Capabilities',
12
- '',
13
- 'This base profile is a minimal placeholder. Extend it with project-specific',
14
- "context, workflows, and domain knowledge. Additional sections listed in the",
15
- "agent's `sections` array are concatenated after this file at build time.",
16
- '',
17
- ].join('\n');
18
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Builds `src/agents/agent.ts` — a minimal Mastra agent factory.
3
- *
4
- * Emitted only when `features.mastra.enabled`. The generated agent falls back
5
- * to a deterministic echo-style demo provider when no API key is configured,
6
- * so `pnpm dev` works immediately out of the box.
7
- */
8
- import { type ClintProjectSpec } from '../../spec/types.js';
9
- export declare function buildAgentTs(spec: ClintProjectSpec): string;
@@ -1,34 +0,0 @@
1
- export function buildAgentTs(spec) {
2
- const id = spec.name;
3
- return [
4
- "import type { AgentProvider, AgentSetupContext, StreamChunk } from '@powerhousedao/ph-clint';",
5
- "import type { Config } from '../framework.js';",
6
- '',
7
- '/**',
8
- ' * Demo agent — deterministic echo responses. Replace with a real Mastra',
9
- " * `Agent` once you've wired your model + tools.",
10
- ' */',
11
- 'function createDemoAgent(): AgentProvider {',
12
- ' return {',
13
- ` id: '${id}',`,
14
- ' async *stream(prompt) {',
15
- ' yield {',
16
- " type: 'text-delta',",
17
- " text: `You said: ${prompt}\\n(demo mode — set an API key and replace createDemoAgent with a Mastra Agent)`,",
18
- ' } satisfies StreamChunk;',
19
- ' },',
20
- ' };',
21
- '}',
22
- '',
23
- '/**',
24
- ' * Agent factory invoked by `cli.configureAgent`. Receives the resolved',
25
- ' * config and workdir; return an AgentProvider.',
26
- ' */',
27
- 'export async function createAgent(',
28
- ' _ctx: AgentSetupContext<Config>,',
29
- '): Promise<AgentProvider> {',
30
- ' return createDemoAgent();',
31
- '}',
32
- '',
33
- ].join('\n');
34
- }
@@ -1,18 +0,0 @@
1
- /**
2
- * Builds `{name}-app/index.ts` — the top-level re-export barrel for the
3
- * reactor package. Impl code imports from `'{name}-app'` instead of drilling
4
- * into `'{name}-app/document-models/<slug>/v1/gen/...'`.
5
- *
6
- * Each entry re-exports a document-model subfolder's `index.ts`, which in
7
- * turn re-exports the module object (`PhClintProject`, ...), action creators,
8
- * document/state types, and type guards. Fully machine-owned: regen on every
9
- * run.
10
- *
11
- * Powerhouse's own codegen might emit its own `index.ts` (as is the case for
12
- * ph-clint-app today, which has manifest/editors/processors re-exports). When
13
- * that exists, leave it alone — users hand-merge. Our codegen only emits when
14
- * the file is absent or was emitted by a previous ph-clint-cli run (hash
15
- * matches the ledger).
16
- */
17
- import { type ClintProjectSpec } from '../../spec/types.js';
18
- export declare function buildAppIndexTs(spec: ClintProjectSpec): string | null;
@@ -1,33 +0,0 @@
1
- /**
2
- * Builds `{name}-app/index.ts` — the top-level re-export barrel for the
3
- * reactor package. Impl code imports from `'{name}-app'` instead of drilling
4
- * into `'{name}-app/document-models/<slug>/v1/gen/...'`.
5
- *
6
- * Each entry re-exports a document-model subfolder's `index.ts`, which in
7
- * turn re-exports the module object (`PhClintProject`, ...), action creators,
8
- * document/state types, and type guards. Fully machine-owned: regen on every
9
- * run.
10
- *
11
- * Powerhouse's own codegen might emit its own `index.ts` (as is the case for
12
- * ph-clint-app today, which has manifest/editors/processors re-exports). When
13
- * that exists, leave it alone — users hand-merge. Our codegen only emits when
14
- * the file is absent or was emitted by a previous ph-clint-cli run (hash
15
- * matches the ledger).
16
- */
17
- import { getDocumentTypeSlug, } from '../../spec/types.js';
18
- export function buildAppIndexTs(spec) {
19
- if (!spec.features.powerhouse.enabled)
20
- return null;
21
- if (spec.documentTypes.length === 0)
22
- return null;
23
- const lines = [];
24
- lines.push('// THIS FILE IS GENERATED BY ph-clint-cli.');
25
- lines.push('// Re-exports every registered document model from a single top-level');
26
- lines.push('// entry so impl code can `import { ... } from \'{name}-app\'`.');
27
- lines.push('');
28
- for (const docType of spec.documentTypes) {
29
- const slug = getDocumentTypeSlug(docType);
30
- lines.push(`export * from './document-models/${slug}/index.js';`);
31
- }
32
- return lines.join('\n') + '\n';
33
- }
@@ -1,4 +0,0 @@
1
- /**
2
- * Builds `scripts/build-skills.ts` — the build-time skill compiler.
3
- */
4
- export declare function buildBuildSkillsScript(): string;
@@ -1,37 +0,0 @@
1
- /**
2
- * Builds `scripts/build-skills.ts` — the build-time skill compiler.
3
- */
4
- export function buildBuildSkillsScript() {
5
- return [
6
- '#!/usr/bin/env tsx',
7
- '/**',
8
- ' * Build script — compiles Handlebars templates in `prompts/` into static',
9
- ' * SKILL.md files and agent instruction strings under `gen/`, using',
10
- " * ph-clint-dev's `buildSkills`.",
11
- ' */',
12
- "import path from 'node:path';",
13
- "import { buildSkills } from '@powerhousedao/ph-clint-dev';",
14
- "import { cli } from '../src/cli.js';",
15
- '',
16
- 'const PROJECT_ROOT = path.resolve(import.meta.dirname, \'..\');',
17
- '',
18
- '// @clint:begin templateVars',
19
- 'function loadTemplateVars(): Record<string, string> {',
20
- ' return {',
21
- " agentName: '{{AGENT_NAME}}',",
22
- ' };',
23
- '}',
24
- '// @clint:end templateVars',
25
- '',
26
- 'buildSkills({',
27
- " include: [path.join(PROJECT_ROOT, 'prompts')],",
28
- ' context: loadTemplateVars(),',
29
- ' output: [',
30
- " path.join(PROJECT_ROOT, 'gen'),",
31
- " path.join(PROJECT_ROOT, 'dist', 'gen'),",
32
- ' ],',
33
- ' cli,',
34
- '});',
35
- '',
36
- ].join('\n');
37
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * Builds the CLI-side `package.json` (the ph-clint CLI itself).
3
- *
4
- * When `features.powerhouse.enabled`, this file lives at
5
- * `{root}/{name}-cli/package.json`. Otherwise at `{root}/package.json`.
6
- */
7
- import { type ClintProjectSpec } from '../../spec/types.js';
8
- export declare function buildCliPackageJson(spec: ClintProjectSpec): string;
@@ -1,96 +0,0 @@
1
- /**
2
- * Builds the CLI-side `package.json` (the ph-clint CLI itself).
3
- *
4
- * When `features.powerhouse.enabled`, this file lives at
5
- * `{root}/{name}-cli/package.json`. Otherwise at `{root}/package.json`.
6
- */
7
- import { getBinName, getPackageName, } from '../../spec/types.js';
8
- import { CLI_VERSION } from '../../config.js';
9
- /**
10
- * Derive a semver range from the running ph-clint-cli version that respects
11
- * the dev / staging / production channel boundary. This is the version range
12
- * emitted into *scaffolded* projects' package.json for @powerhousedao/ph-clint
13
- * and @powerhousedao/ph-clint-dev dependencies.
14
- *
15
- * CLI_VERSION is the version of ph-clint-cli itself (read from its own
16
- * package.json at startup). Since all framework packages share a lockstep
17
- * version, this is also the correct base for the dependency range.
18
- *
19
- * Examples:
20
- * "0.1.0" → "^0.1.0" (production — stable only)
21
- * "0.1.0-staging.2" → "^0.1.0-staging.0" (staging + stable)
22
- * "0.1.0-dev.4" → "^0.1.0-dev.0" (dev + staging + stable)
23
- *
24
- * This works because semver orders prereleases alphabetically:
25
- * dev.N < staging.N < release. A caret range starting at dev.0 naturally
26
- * upgrades through staging to production.
27
- */
28
- function phClintRange(version) {
29
- const match = /^(\d+\.\d+\.\d+)(?:-([a-z]+)\.\d+)?/.exec(version);
30
- if (!match)
31
- return `^${version}`;
32
- const base = match[1];
33
- const channel = match[2]; // "dev", "staging", or undefined
34
- return channel ? `^${base}-${channel}.0` : `^${base}`;
35
- }
36
- /** Version range for @powerhousedao/ph-clint{,-dev} deps in scaffolded projects. */
37
- const PH_CLINT_VERSION = phClintRange(CLI_VERSION);
38
- const POWERHOUSE_VERSION = '6.0.0-dev.170';
39
- export function buildCliPackageJson(spec) {
40
- const { mastra, powerhouse } = spec.features;
41
- const pkgName = powerhouse.enabled
42
- ? `${getPackageName(spec)}-cli`
43
- : getPackageName(spec);
44
- const bin = getBinName(spec);
45
- const dependencies = {
46
- '@powerhousedao/ph-clint': PH_CLINT_VERSION,
47
- zod: '^4.3.6',
48
- };
49
- if (mastra.enabled) {
50
- dependencies['@mastra/core'] = '^1.22.0';
51
- dependencies['@mastra/libsql'] = '^1.7.4';
52
- dependencies['@mastra/memory'] = '^1.13.1';
53
- }
54
- if (powerhouse.enabled) {
55
- dependencies[`${spec.name}-app`] = `file:../${spec.name}-app`;
56
- dependencies['@powerhousedao/reactor'] = POWERHOUSE_VERSION;
57
- dependencies['@powerhousedao/reactor-api'] = POWERHOUSE_VERSION;
58
- dependencies['@powerhousedao/shared'] = POWERHOUSE_VERSION;
59
- dependencies['document-model'] = POWERHOUSE_VERSION;
60
- }
61
- const scripts = {
62
- 'build:skills': 'tsx scripts/build-skills.ts',
63
- build: 'pnpm build:skills && tsc',
64
- dev: 'tsx src/main.ts',
65
- start: 'node dist/main.js',
66
- test: "NODE_OPTIONS='--experimental-vm-modules' jest --detectOpenHandles",
67
- lint: 'eslint src',
68
- };
69
- if (mastra.enabled) {
70
- scripts['mastra:dev'] = 'mastra dev';
71
- scripts['mastra:build'] = 'mastra build';
72
- scripts['mastra:start'] = 'mastra start';
73
- }
74
- const pkg = {
75
- name: pkgName,
76
- version: spec.version,
77
- private: true,
78
- type: 'module',
79
- };
80
- if (spec.description)
81
- pkg.description = spec.description;
82
- pkg.bin = { [bin]: './dist/main.js' };
83
- pkg.scripts = scripts;
84
- pkg.dependencies = dependencies;
85
- pkg.devDependencies = {
86
- '@jest/globals': '^30.2.0',
87
- '@types/node': '^25.5.2',
88
- jest: '^30.2.0',
89
- '@powerhousedao/ph-clint-dev': PH_CLINT_VERSION,
90
- 'ts-jest': '^29.4.6',
91
- tsx: '^4.19.0',
92
- typescript: '^6.0.2',
93
- };
94
- pkg.engines = { node: '>=22.13.0' };
95
- return JSON.stringify(pkg, null, 2) + '\n';
96
- }