@powerhousedao/ph-clint-cli 0.1.0-dev.9 → 0.1.0-dev.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +53 -11
- package/dist/codegen/actions.d.ts +46 -0
- package/dist/codegen/actions.js +424 -0
- package/dist/codegen/builders/agent-ts.d.ts +4 -4
- package/dist/codegen/builders/agent-ts.js +92 -2
- package/dist/codegen/builders/app-index-ts.d.ts +3 -10
- package/dist/codegen/builders/app-index-ts.js +30 -20
- package/dist/codegen/builders/cli-package-json.js +46 -14
- package/dist/codegen/builders/cli-ts.js +87 -49
- package/dist/codegen/builders/config-ts.d.ts +1 -1
- package/dist/codegen/builders/config-ts.js +2 -8
- package/dist/codegen/builders/demo-agent-ts.d.ts +8 -0
- package/dist/codegen/builders/demo-agent-ts.js +50 -0
- package/dist/codegen/builders/eslint-config-js.d.ts +1 -1
- package/dist/codegen/builders/eslint-config-js.js +7 -4
- package/dist/codegen/builders/framework-gen-ts.d.ts +11 -6
- package/dist/codegen/builders/framework-gen-ts.js +73 -21
- package/dist/codegen/builders/framework-ts.js +33 -7
- package/dist/codegen/builders/index.d.ts +10 -2
- package/dist/codegen/builders/index.js +30 -6
- package/dist/codegen/builders/manifest-json.d.ts +6 -0
- package/dist/codegen/builders/manifest-json.js +31 -0
- package/dist/codegen/builders/mastra-index-ts.d.ts +3 -0
- package/dist/codegen/builders/mastra-index-ts.js +47 -5
- package/dist/codegen/builders/publish-config-js.d.ts +8 -0
- package/dist/codegen/builders/publish-config-js.js +33 -0
- package/dist/codegen/builders/readme-md.js +7 -6
- package/dist/codegen/builders/root-package-json.js +11 -12
- package/dist/codegen/builders/smoke-test-ts.d.ts +2 -0
- package/dist/codegen/builders/smoke-test-ts.js +15 -0
- package/dist/codegen/exec.d.ts +0 -18
- package/dist/codegen/exec.js +0 -27
- package/dist/codegen/generated.d.ts +17 -0
- package/dist/codegen/generated.js +49 -0
- package/dist/codegen/index.d.ts +8 -36
- package/dist/codegen/index.js +6 -293
- package/dist/codegen/scaffold.d.ts +41 -3
- package/dist/codegen/scaffold.js +106 -16
- package/dist/commands/clint-project-build.d.ts +77 -1
- package/dist/commands/clint-project-build.js +11 -28
- package/dist/commands/clint-project-init.d.ts +130 -10
- package/dist/commands/clint-project-init.js +72 -47
- package/dist/commands/clint-project-publish.d.ts +78 -1
- package/dist/commands/clint-project-publish.js +6 -4
- package/dist/commands/clint-project-regen.d.ts +77 -1
- package/dist/commands/clint-project-regen.js +26 -2
- package/dist/commands/clint-skills-sync.d.ts +86 -0
- package/dist/commands/clint-skills-sync.js +56 -0
- package/dist/framework.d.ts +322 -60
- package/dist/framework.gen.d.ts +50 -10
- package/dist/framework.js +1 -5
- package/{prompts/agent-profiles/AgentBase.md → dist/gen/agent-profiles/PhClintDevAgent.md} +1 -1
- package/dist/gen/skills/cli-setup/.cli-docs.md +135 -0
- package/dist/gen/skills/cli-setup/SKILL.md +125 -0
- package/dist/gen/skills/cli-setup/references/00.assess-cli-needs.md +53 -0
- package/dist/gen/skills/cli-setup/references/01.define-config-schema.md +78 -0
- package/dist/gen/skills/cli-setup/references/02.wire-cli.md +141 -0
- package/dist/gen/skills/cli-setup/references/03.add-entrypoint.md +128 -0
- package/dist/gen/skills/cli-setup/references/expected-outcome.md +3 -0
- package/dist/gen/skills/command-definition/.cli-docs.md +84 -0
- package/dist/gen/skills/command-definition/SKILL.md +99 -0
- package/dist/gen/skills/command-definition/references/00.assess-requirements.md +58 -0
- package/dist/gen/skills/command-definition/references/01.define-schema.md +72 -0
- package/dist/gen/skills/command-definition/references/02.implement-execute.md +118 -0
- package/dist/gen/skills/command-definition/references/03.add-prompting.md +54 -0
- package/dist/gen/skills/command-definition/references/expected-outcome.md +3 -0
- package/dist/gen/skills/service-definition/.cli-docs.md +214 -0
- package/dist/gen/skills/service-definition/SKILL.md +148 -0
- package/dist/gen/skills/service-definition/references/00.assess-service.md +69 -0
- package/dist/gen/skills/service-definition/references/01.define-service.md +166 -0
- package/dist/gen/skills/service-definition/references/02.add-preflight.md +132 -0
- package/dist/gen/skills/service-definition/references/03.add-project-scanner.md +82 -0
- package/dist/gen/skills/service-definition/references/04.wire-events.md +120 -0
- package/dist/gen/skills/service-definition/references/expected-outcome.md +3 -0
- package/dist/main.js +0 -0
- package/dist/services/clint-project.js +21 -0
- package/dist/skills/sync.d.ts +40 -0
- package/dist/skills/sync.js +119 -0
- package/dist/spec/ensure-document.d.ts +17 -0
- package/dist/spec/ensure-document.js +56 -0
- package/dist/spec/file.d.ts +1 -4
- package/dist/spec/file.js +1 -34
- package/dist/spec/from-document.d.ts +4 -1
- package/dist/spec/from-document.js +4 -16
- package/dist/spec/types.d.ts +1 -62
- package/dist/spec/types.js +1 -112
- package/dist/triggers/publish-trigger.d.ts +81 -0
- package/dist/triggers/publish-trigger.js +137 -0
- package/dist/triggers/spec-change.d.ts +60 -18
- package/dist/triggers/spec-change.js +154 -101
- package/package.json +15 -20
- package/dist/codegen/builders/publish-config-ts.d.ts +0 -6
- package/dist/codegen/builders/publish-config-ts.js +0 -18
- package/dist/commands/init.d.ts +0 -57
- package/dist/commands/init.js +0 -168
- package/dist/commands/regen.d.ts +0 -18
- package/dist/commands/regen.js +0 -68
- package/prompts/skills-ext/.gitkeep +0 -0
- package/prompts/skills-tpl/.gitkeep +0 -0
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `spec-change` trigger — watches
|
|
3
|
-
*
|
|
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
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* 3.
|
|
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
|
-
*
|
|
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(
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
//
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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 (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
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,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerhousedao/ph-clint-cli",
|
|
3
|
-
"version": "0.1.0-dev.
|
|
3
|
+
"version": "0.1.0-dev.91",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -10,40 +10,35 @@
|
|
|
10
10
|
"ph-clint": "./dist/main.js"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
|
-
"dist"
|
|
14
|
-
"prompts"
|
|
13
|
+
"dist"
|
|
15
14
|
],
|
|
16
15
|
"scripts": {
|
|
17
16
|
"build:skills": "tsx scripts/build-skills.ts",
|
|
18
17
|
"build": "pnpm build:skills && tsc",
|
|
19
18
|
"dev": "tsx src/main.ts",
|
|
20
19
|
"start": "node dist/main.js",
|
|
21
|
-
"test": "NODE_OPTIONS='--experimental-vm-modules' jest --detectOpenHandles",
|
|
20
|
+
"test": "NODE_OPTIONS='--experimental-vm-modules' jest --detectOpenHandles --coverage",
|
|
21
|
+
"test:e2e": "NODE_OPTIONS='--experimental-vm-modules' jest --detectOpenHandles --testPathPatterns 'tests/(e2e|codegen-e2e)/' --testPathIgnorePatterns '/node_modules/'",
|
|
22
22
|
"lint": "eslint src",
|
|
23
23
|
"mastra:dev": "mastra dev",
|
|
24
24
|
"mastra:build": "mastra build",
|
|
25
25
|
"mastra:start": "mastra start"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@powerhousedao/ph-clint": "^0.1.0-dev.9",
|
|
29
|
-
"@powerhousedao/ph-clint-app": "^0.1.0-dev.9",
|
|
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
28
|
"@electric-sql/pglite": "0.3.15",
|
|
37
|
-
"
|
|
29
|
+
"@mastra/core": "1.41.0",
|
|
30
|
+
"@mastra/libsql": "1.12.1",
|
|
31
|
+
"@mastra/memory": "1.20.2",
|
|
32
|
+
"@powerhousedao/ph-clint": "0.1.0-dev.91",
|
|
33
|
+
"@powerhousedao/ph-clint-app": "0.1.0-dev.91",
|
|
34
|
+
"@powerhousedao/ph-clint-dev": "0.1.0-dev.91",
|
|
35
|
+
"@powerhousedao/reactor": "6.2.0-dev.23",
|
|
36
|
+
"@powerhousedao/reactor-api": "6.2.0-dev.23",
|
|
37
|
+
"@powerhousedao/shared": "6.2.0-dev.23",
|
|
38
|
+
"document-model": "6.2.0-dev.23",
|
|
38
39
|
"kysely": "^0.27.0",
|
|
39
40
|
"kysely-pglite-dialect": "^1.3.0",
|
|
40
|
-
"
|
|
41
|
-
"zod": "^4.3.6"
|
|
42
|
-
},
|
|
43
|
-
"pnpm": {
|
|
44
|
-
"overrides": {
|
|
45
|
-
"mastra>@mastra/deployer": "1.22.0"
|
|
46
|
-
}
|
|
41
|
+
"zod": "4.3.6"
|
|
47
42
|
},
|
|
48
43
|
"devDependencies": {
|
|
49
44
|
"@jest/globals": "^30.2.0",
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Builds the root `publish.config.ts` for split-layout projects.
|
|
3
|
-
* Defines a single lockstep group containing both the app and cli packages.
|
|
4
|
-
*/
|
|
5
|
-
import { type ClintProjectSpec } from '../../spec/types.js';
|
|
6
|
-
export declare function buildPublishConfigTs(spec: ClintProjectSpec): string;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export function buildPublishConfigTs(spec) {
|
|
2
|
-
const app = `${spec.name}-app`;
|
|
3
|
-
const cli = `${spec.name}-cli`;
|
|
4
|
-
return `import { definePublishConfig } from '@powerhousedao/ph-clint-dev/publish';
|
|
5
|
-
|
|
6
|
-
export default definePublishConfig({
|
|
7
|
-
groups: {
|
|
8
|
-
'${spec.name}': {
|
|
9
|
-
version: '${spec.version}',
|
|
10
|
-
packages: [
|
|
11
|
-
{ path: '${app}', category: 'app' },
|
|
12
|
-
{ path: '${cli}', category: 'cli' },
|
|
13
|
-
],
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
});
|
|
17
|
-
`;
|
|
18
|
-
}
|
package/dist/commands/init.d.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { type ClintProjectSpec } from '../spec/types.js';
|
|
3
|
-
declare const inputSchema: z.ZodObject<{
|
|
4
|
-
dir: z.ZodOptional<z.ZodString>;
|
|
5
|
-
name: z.ZodString;
|
|
6
|
-
description: z.ZodOptional<z.ZodString>;
|
|
7
|
-
enablePowerhouse: z.ZodDefault<z.ZodBoolean>;
|
|
8
|
-
enableMastra: z.ZodDefault<z.ZodBoolean>;
|
|
9
|
-
enableRoutine: z.ZodDefault<z.ZodBoolean>;
|
|
10
|
-
force: z.ZodDefault<z.ZodBoolean>;
|
|
11
|
-
skipPhInit: z.ZodDefault<z.ZodBoolean>;
|
|
12
|
-
skipInstall: z.ZodDefault<z.ZodBoolean>;
|
|
13
|
-
}, z.core.$strip>;
|
|
14
|
-
type InitInput = z.output<typeof inputSchema>;
|
|
15
|
-
export declare function buildSpec(input: InitInput): ClintProjectSpec;
|
|
16
|
-
export declare const init: import("@powerhousedao/ph-clint").Command<z.ZodObject<{
|
|
17
|
-
dir: z.ZodOptional<z.ZodString>;
|
|
18
|
-
name: z.ZodString;
|
|
19
|
-
description: z.ZodOptional<z.ZodString>;
|
|
20
|
-
enablePowerhouse: z.ZodDefault<z.ZodBoolean>;
|
|
21
|
-
enableMastra: z.ZodDefault<z.ZodBoolean>;
|
|
22
|
-
enableRoutine: z.ZodDefault<z.ZodBoolean>;
|
|
23
|
-
force: z.ZodDefault<z.ZodBoolean>;
|
|
24
|
-
skipPhInit: z.ZodDefault<z.ZodBoolean>;
|
|
25
|
-
skipInstall: z.ZodDefault<z.ZodBoolean>;
|
|
26
|
-
}, z.core.$strip>, {
|
|
27
|
-
text: string;
|
|
28
|
-
data?: undefined;
|
|
29
|
-
} | {
|
|
30
|
-
text: string;
|
|
31
|
-
data: {
|
|
32
|
-
targetDir: string;
|
|
33
|
-
spec: {
|
|
34
|
-
name: string;
|
|
35
|
-
version: string;
|
|
36
|
-
description: string;
|
|
37
|
-
features: {
|
|
38
|
-
powerhouse: {
|
|
39
|
-
enabled: boolean;
|
|
40
|
-
switchboard: boolean;
|
|
41
|
-
connect: boolean;
|
|
42
|
-
};
|
|
43
|
-
mastra: {
|
|
44
|
-
enabled: boolean;
|
|
45
|
-
};
|
|
46
|
-
routine: {
|
|
47
|
-
enabled: boolean;
|
|
48
|
-
};
|
|
49
|
-
};
|
|
50
|
-
documentTypes: string[];
|
|
51
|
-
scope?: string | undefined;
|
|
52
|
-
bin?: string | undefined;
|
|
53
|
-
};
|
|
54
|
-
fileCount: number;
|
|
55
|
-
};
|
|
56
|
-
}, Record<string, unknown>>;
|
|
57
|
-
export {};
|
package/dist/commands/init.js
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `ph-clint init` — the project bootstrap wizard.
|
|
3
|
-
*
|
|
4
|
-
* Behavior:
|
|
5
|
-
* 1. Resolve target dir (positional `dir`, defaults to cwd).
|
|
6
|
-
* 2. Assert it is empty (or `--force`).
|
|
7
|
-
* 3. Collect project identity + feature toggles (prompt for missing).
|
|
8
|
-
* 4. Assemble a ClintProjectSpec and validate with Zod.
|
|
9
|
-
* 5. Write the spec + emit the generated tree via `generateProject`.
|
|
10
|
-
* 6. (Split layout) run `ph init` in `{name}-app/` unless `--skip-ph-init`.
|
|
11
|
-
* 7. Run `pnpm install` in generated sub-projects unless `--skip-install`.
|
|
12
|
-
* 8. Print next-steps guidance.
|
|
13
|
-
*/
|
|
14
|
-
import path from 'node:path';
|
|
15
|
-
import { defineCommand } from '@powerhousedao/ph-clint';
|
|
16
|
-
import { z } from 'zod';
|
|
17
|
-
import { clintProjectSpecSchema, } from '../spec/types.js';
|
|
18
|
-
import { generateProject } from '../codegen/index.js';
|
|
19
|
-
import { isDirEmptyEnough } from '../codegen/write.js';
|
|
20
|
-
import { runPhInit, runPnpmInstall } from '../codegen/scaffold.js';
|
|
21
|
-
const inputSchema = z.object({
|
|
22
|
-
dir: z
|
|
23
|
-
.string()
|
|
24
|
-
.optional()
|
|
25
|
-
.describe('Target directory (defaults to the current directory)'),
|
|
26
|
-
name: z
|
|
27
|
-
.string()
|
|
28
|
-
.describe('Project name — bare, or `@scope/name`. Lowercase letters, digits, hyphens.'),
|
|
29
|
-
description: z.string().optional().describe('Short project description'),
|
|
30
|
-
enablePowerhouse: z
|
|
31
|
-
.boolean()
|
|
32
|
-
.default(false)
|
|
33
|
-
.describe('Enable Powerhouse reactor (requires split layout)'),
|
|
34
|
-
enableMastra: z
|
|
35
|
-
.boolean()
|
|
36
|
-
.default(false)
|
|
37
|
-
.describe('Enable Mastra AI agent stack'),
|
|
38
|
-
enableRoutine: z
|
|
39
|
-
.boolean()
|
|
40
|
-
.default(false)
|
|
41
|
-
.describe('Enable the tick-based routine loop'),
|
|
42
|
-
force: z
|
|
43
|
-
.boolean()
|
|
44
|
-
.default(false)
|
|
45
|
-
.describe('Overwrite files if the target directory is not empty'),
|
|
46
|
-
skipPhInit: z
|
|
47
|
-
.boolean()
|
|
48
|
-
.default(false)
|
|
49
|
-
.describe('Do not run `ph init` in the app folder after scaffolding'),
|
|
50
|
-
skipInstall: z
|
|
51
|
-
.boolean()
|
|
52
|
-
.default(false)
|
|
53
|
-
.describe('Do not run `pnpm install` after scaffolding'),
|
|
54
|
-
});
|
|
55
|
-
/** Parse `@scope/name` into { scope, name }. */
|
|
56
|
-
function splitPackageName(raw) {
|
|
57
|
-
const match = /^@([a-z0-9][a-z0-9-]*)\/([a-z0-9][a-z0-9-]*)$/.exec(raw);
|
|
58
|
-
if (match)
|
|
59
|
-
return { scope: match[1], name: match[2] };
|
|
60
|
-
if (raw.startsWith('@')) {
|
|
61
|
-
throw new Error(`invalid package name "${raw}" — expected "@scope/name" with lowercase letters, digits, hyphens`);
|
|
62
|
-
}
|
|
63
|
-
if (!/^[a-z0-9][a-z0-9-]*$/.test(raw)) {
|
|
64
|
-
throw new Error(`invalid project name "${raw}" — expected lowercase letters, digits, hyphens`);
|
|
65
|
-
}
|
|
66
|
-
return { name: raw };
|
|
67
|
-
}
|
|
68
|
-
export function buildSpec(input) {
|
|
69
|
-
const { scope, name } = splitPackageName(input.name);
|
|
70
|
-
// Routine is forced on when Mastra is on — the REPL-only path works, but
|
|
71
|
-
// the agent routine loop is what most users actually want.
|
|
72
|
-
const routine = input.enableRoutine || input.enableMastra;
|
|
73
|
-
const candidate = {
|
|
74
|
-
name,
|
|
75
|
-
scope,
|
|
76
|
-
description: input.description ?? '',
|
|
77
|
-
features: {
|
|
78
|
-
powerhouse: { enabled: input.enablePowerhouse },
|
|
79
|
-
mastra: { enabled: input.enableMastra },
|
|
80
|
-
routine: { enabled: routine },
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
return clintProjectSpecSchema.parse(candidate);
|
|
84
|
-
}
|
|
85
|
-
export const init = defineCommand({
|
|
86
|
-
id: 'init',
|
|
87
|
-
description: 'Initialize a new ph-clint project in the target directory',
|
|
88
|
-
inputSchema,
|
|
89
|
-
prompt: {
|
|
90
|
-
promptForDefaults: true,
|
|
91
|
-
promptOptional: ['description'],
|
|
92
|
-
},
|
|
93
|
-
execute: async (input, { workdir, stdout }) => {
|
|
94
|
-
const targetDir = path.resolve(workdir, input.dir ?? '.');
|
|
95
|
-
if (!input.force) {
|
|
96
|
-
const empty = await isDirEmptyEnough(targetDir);
|
|
97
|
-
if (!empty) {
|
|
98
|
-
return {
|
|
99
|
-
text: `Error: ${targetDir} is not empty. Re-run with --force to initialize anyway,\n` +
|
|
100
|
-
'or choose a different --dir.',
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
const spec = buildSpec(input);
|
|
105
|
-
const result = await generateProject({
|
|
106
|
-
targetDir,
|
|
107
|
-
spec,
|
|
108
|
-
mode: 'create',
|
|
109
|
-
allowNonEmpty: input.force,
|
|
110
|
-
});
|
|
111
|
-
stdout(`Generated ${result.files.length} files in ${targetDir}\n`);
|
|
112
|
-
const split = spec.features.powerhouse.enabled;
|
|
113
|
-
// Reactor package scaffolding (split layout only).
|
|
114
|
-
if (split && result.appDir && !input.skipPhInit) {
|
|
115
|
-
const phResult = await runPhInit({
|
|
116
|
-
targetDir,
|
|
117
|
-
appDir: result.appDir,
|
|
118
|
-
spec,
|
|
119
|
-
log: (msg) => stdout(msg + '\n'),
|
|
120
|
-
});
|
|
121
|
-
if (!phResult.ran) {
|
|
122
|
-
stdout(`Note: \`ph init\` did not run — ${phResult.reason ?? 'see above'}.\n`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
// Dependency installation.
|
|
126
|
-
if (!input.skipInstall) {
|
|
127
|
-
const dirs = [];
|
|
128
|
-
if (split) {
|
|
129
|
-
if (result.appDir)
|
|
130
|
-
dirs.push(result.appDir);
|
|
131
|
-
dirs.push(result.cliDir);
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
dirs.push(targetDir);
|
|
135
|
-
}
|
|
136
|
-
await runPnpmInstall({
|
|
137
|
-
dirs,
|
|
138
|
-
log: (msg) => stdout(msg + '\n'),
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
const next = [];
|
|
142
|
-
next.push('');
|
|
143
|
-
next.push('Next steps:');
|
|
144
|
-
const relDir = path.relative(workdir, targetDir) || '.';
|
|
145
|
-
if (split) {
|
|
146
|
-
next.push(` cd ${relDir}`);
|
|
147
|
-
if (input.skipPhInit) {
|
|
148
|
-
next.push(` cd ${spec.name}-app && ph init . && cd ..`);
|
|
149
|
-
}
|
|
150
|
-
if (input.skipInstall) {
|
|
151
|
-
next.push(' pnpm install');
|
|
152
|
-
}
|
|
153
|
-
next.push(' pnpm dev');
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
next.push(` cd ${relDir}`);
|
|
157
|
-
if (input.skipInstall)
|
|
158
|
-
next.push(' pnpm install');
|
|
159
|
-
next.push(' pnpm dev');
|
|
160
|
-
}
|
|
161
|
-
next.push('');
|
|
162
|
-
next.push('Edit the project spec and run `ph-clint regen` to regenerate.');
|
|
163
|
-
return {
|
|
164
|
-
text: next.join('\n'),
|
|
165
|
-
data: { targetDir, spec, fileCount: result.files.length },
|
|
166
|
-
};
|
|
167
|
-
},
|
|
168
|
-
});
|
package/dist/commands/regen.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
export declare const regen: import("@powerhousedao/ph-clint").Command<z.ZodObject<{
|
|
3
|
-
dir: z.ZodOptional<z.ZodString>;
|
|
4
|
-
force: z.ZodDefault<z.ZodBoolean>;
|
|
5
|
-
}, z.core.$strip>, {
|
|
6
|
-
text: string;
|
|
7
|
-
data?: undefined;
|
|
8
|
-
} | {
|
|
9
|
-
text: string;
|
|
10
|
-
data: {
|
|
11
|
-
mode: "create" | "update";
|
|
12
|
-
files: string[];
|
|
13
|
-
skipped: string[];
|
|
14
|
-
deleted: string[];
|
|
15
|
-
migrated: boolean;
|
|
16
|
-
warnings: string[];
|
|
17
|
-
};
|
|
18
|
-
}, Record<string, unknown>>;
|