@powerhousedao/ph-clint-cli 0.1.0-dev.76 → 0.1.0-dev.77

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 (37) hide show
  1. package/dist/codegen/actions.d.ts +46 -1
  2. package/dist/codegen/actions.js +424 -1
  3. package/dist/codegen/builders/cli-package-json.d.ts +8 -1
  4. package/dist/codegen/builders/cli-package-json.js +128 -1
  5. package/dist/codegen/builders/index.d.ts +52 -1
  6. package/dist/codegen/builders/index.js +85 -1
  7. package/dist/codegen/exec.d.ts +2 -1
  8. package/dist/codegen/exec.js +14 -1
  9. package/dist/codegen/generated.d.ts +17 -1
  10. package/dist/codegen/generated.js +49 -1
  11. package/dist/codegen/hashes.d.ts +6 -1
  12. package/dist/codegen/hashes.js +60 -1
  13. package/dist/codegen/markers.d.ts +36 -1
  14. package/dist/codegen/markers.js +86 -1
  15. package/dist/codegen/scaffold.d.ts +72 -1
  16. package/dist/codegen/scaffold.js +150 -1
  17. package/dist/codegen/write.d.ts +6 -1
  18. package/dist/codegen/write.js +32 -1
  19. package/dist/commands/clint-project-build.d.ts +3 -0
  20. package/dist/commands/clint-project-init.d.ts +3 -0
  21. package/dist/commands/clint-project-publish.d.ts +3 -0
  22. package/dist/commands/clint-project-regen.d.ts +3 -0
  23. package/dist/commands/clint-skills-sync.d.ts +3 -0
  24. package/dist/framework.d.ts +18 -0
  25. package/dist/framework.gen.d.ts +3 -0
  26. package/dist/main.js +0 -0
  27. package/dist/skills/sync.d.ts +40 -1
  28. package/dist/skills/sync.js +119 -1
  29. package/dist/triggers/publish-trigger.d.ts +3 -0
  30. package/dist/triggers/spec-change.d.ts +3 -0
  31. package/package.json +9 -9
  32. package/dist/codegen/builders/publish-config-ts.d.ts +0 -8
  33. package/dist/codegen/builders/publish-config-ts.js +0 -32
  34. package/dist/commands/init.d.ts +0 -57
  35. package/dist/commands/init.js +0 -168
  36. package/dist/commands/regen.d.ts +0 -18
  37. package/dist/commands/regen.js +0 -68
@@ -76,6 +76,9 @@ export declare const clintProjectPublish: import("@powerhousedao/ph-clint").Comm
76
76
  setName: (name: string | {
77
77
  name: string;
78
78
  }) => import("document-model").SetNameAction;
79
+ setPreferredEditor: (input: string | null | {
80
+ preferredEditor: string | null;
81
+ }) => import("document-model").SetPreferredEditorAction;
79
82
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
80
83
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
81
84
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
@@ -78,6 +78,9 @@ export declare const regen: import("@powerhousedao/ph-clint").Command<z.ZodObjec
78
78
  setName: (name: string | {
79
79
  name: string;
80
80
  }) => import("document-model").SetNameAction;
81
+ setPreferredEditor: (input: string | null | {
82
+ preferredEditor: string | null;
83
+ }) => import("document-model").SetPreferredEditorAction;
81
84
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
82
85
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
83
86
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
@@ -70,6 +70,9 @@ export declare const skillsSync: import("@powerhousedao/ph-clint").Command<z.Zod
70
70
  setName: (name: string | {
71
71
  name: string;
72
72
  }) => import("document-model").SetNameAction;
73
+ setPreferredEditor: (input: string | null | {
74
+ preferredEditor: string | null;
75
+ }) => import("document-model").SetPreferredEditorAction;
73
76
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
74
77
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
75
78
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
@@ -88,6 +88,9 @@ export declare const defineCommand: <TInput extends z.ZodType, TOutput = unknown
88
88
  setName: (name: string | {
89
89
  name: string;
90
90
  }) => import("document-model").SetNameAction;
91
+ setPreferredEditor: (input: string | null | {
92
+ preferredEditor: string | null;
93
+ }) => import("document-model").SetPreferredEditorAction;
91
94
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
92
95
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
93
96
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
@@ -162,6 +165,9 @@ export declare const defineCommand: <TInput extends z.ZodType, TOutput = unknown
162
165
  setName: (name: string | {
163
166
  name: string;
164
167
  }) => import("document-model").SetNameAction;
168
+ setPreferredEditor: (input: string | null | {
169
+ preferredEditor: string | null;
170
+ }) => import("document-model").SetPreferredEditorAction;
165
171
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
166
172
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
167
173
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
@@ -235,6 +241,9 @@ export declare const defineCommand: <TInput extends z.ZodType, TOutput = unknown
235
241
  setName: (name: string | {
236
242
  name: string;
237
243
  }) => import("document-model").SetNameAction;
244
+ setPreferredEditor: (input: string | null | {
245
+ preferredEditor: string | null;
246
+ }) => import("document-model").SetPreferredEditorAction;
238
247
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
239
248
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
240
249
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
@@ -308,6 +317,9 @@ export declare const defineCommand: <TInput extends z.ZodType, TOutput = unknown
308
317
  setName: (name: string | {
309
318
  name: string;
310
319
  }) => import("document-model").SetNameAction;
320
+ setPreferredEditor: (input: string | null | {
321
+ preferredEditor: string | null;
322
+ }) => import("document-model").SetPreferredEditorAction;
311
323
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
312
324
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
313
325
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
@@ -390,6 +402,9 @@ export declare const defineCommand: <TInput extends z.ZodType, TOutput = unknown
390
402
  setName: (name: string | {
391
403
  name: string;
392
404
  }) => import("document-model").SetNameAction;
405
+ setPreferredEditor: (input: string | null | {
406
+ preferredEditor: string | null;
407
+ }) => import("document-model").SetPreferredEditorAction;
393
408
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
394
409
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
395
410
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
@@ -468,6 +483,9 @@ export declare const defineCommand: <TInput extends z.ZodType, TOutput = unknown
468
483
  setName: (name: string | {
469
484
  name: string;
470
485
  }) => import("document-model").SetNameAction;
486
+ setPreferredEditor: (input: string | null | {
487
+ preferredEditor: string | null;
488
+ }) => import("document-model").SetPreferredEditorAction;
471
489
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
472
490
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
473
491
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
@@ -60,6 +60,9 @@ export declare const registry: import("@powerhousedao/ph-clint").InferRegistry<r
60
60
  setName: (name: string | {
61
61
  name: string;
62
62
  }) => import("document-model").SetNameAction;
63
+ setPreferredEditor: (input: string | null | {
64
+ preferredEditor: string | null;
65
+ }) => import("document-model").SetPreferredEditorAction;
63
66
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
64
67
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
65
68
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
package/dist/main.js CHANGED
File without changes
@@ -1 +1,40 @@
1
- export { type ManifestEntry, type SkillsManifest, type SyncResult, type SyncOptions, readManifest, diffSkills, syncExternalSkills, } from '@powerhousedao/ph-clint-dev/skills/sync';
1
+ import type { ExternalSkill } from '../spec/types.js';
2
+ /** On-disk manifest entry (what is currently installed). */
3
+ export interface ManifestEntry {
4
+ name: string;
5
+ githubUrl: string;
6
+ }
7
+ /** Persisted manifest — a simple JSON array. */
8
+ export type SkillsManifest = ManifestEntry[];
9
+ export interface SyncResult {
10
+ added: string[];
11
+ removed: string[];
12
+ unchanged: string[];
13
+ }
14
+ export interface SyncOptions {
15
+ /** Project root (CLI sub-tree when split layout). */
16
+ targetDir: string;
17
+ /** Desired state from the spec. */
18
+ desired: ExternalSkill[];
19
+ /** Optional log callback. */
20
+ log?: (msg: string) => void;
21
+ }
22
+ export declare function readManifest(targetDir: string): Promise<SkillsManifest>;
23
+ /**
24
+ * Compute the diff between desired (spec) and current (manifest) skills.
25
+ *
26
+ * Pure function — no I/O.
27
+ */
28
+ export declare function diffSkills(desired: ExternalSkill[], current: SkillsManifest): {
29
+ toAdd: ExternalSkill[];
30
+ toRemove: ManifestEntry[];
31
+ unchanged: string[];
32
+ };
33
+ /**
34
+ * Synchronise external skills on disk to match the spec.
35
+ *
36
+ * - Clones missing skills via `git clone --depth 1`.
37
+ * - Removes skills no longer in the spec.
38
+ * - Updates the `.skills-manifest.json`.
39
+ */
40
+ export declare function syncExternalSkills(opts: SyncOptions): Promise<SyncResult>;
@@ -1 +1,119 @@
1
- export { readManifest, diffSkills, syncExternalSkills, } from '@powerhousedao/ph-clint-dev/skills/sync';
1
+ /**
2
+ * External skills synchronisation.
3
+ *
4
+ * Reads the desired external skills from a `ClintProjectSpec`, diffs them
5
+ * against a `.skills-manifest.json` on disk, and runs `git clone` / `rm -rf`
6
+ * to reconcile. Each external skill ends up as a subdirectory of
7
+ * `prompts/skills-ext/<name>/` so the build-skills pipeline picks it up.
8
+ */
9
+ import { spawn } from 'node:child_process';
10
+ import fs from 'node:fs/promises';
11
+ import path from 'node:path';
12
+ const MANIFEST_FILE = '.skills-manifest.json';
13
+ const SKILLS_DIR = path.join('prompts', 'skills-ext');
14
+ function manifestPath(targetDir) {
15
+ return path.join(targetDir, SKILLS_DIR, MANIFEST_FILE);
16
+ }
17
+ export async function readManifest(targetDir) {
18
+ try {
19
+ const raw = await fs.readFile(manifestPath(targetDir), 'utf8');
20
+ return JSON.parse(raw);
21
+ }
22
+ catch {
23
+ return [];
24
+ }
25
+ }
26
+ async function writeManifest(targetDir, manifest) {
27
+ const file = manifestPath(targetDir);
28
+ await fs.mkdir(path.dirname(file), { recursive: true });
29
+ await fs.writeFile(file, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
30
+ }
31
+ function execGit(args, cwd) {
32
+ return new Promise((resolve, reject) => {
33
+ const proc = spawn('git', args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
34
+ let stderr = '';
35
+ if (proc.stderr) {
36
+ proc.stderr.on('data', (d) => {
37
+ stderr += d.toString();
38
+ });
39
+ }
40
+ proc.on('close', (code) => resolve({ code: code ?? 1, stderr }));
41
+ proc.on('error', (err) => reject(err));
42
+ });
43
+ }
44
+ /**
45
+ * Compute the diff between desired (spec) and current (manifest) skills.
46
+ *
47
+ * Pure function — no I/O.
48
+ */
49
+ export function diffSkills(desired, current) {
50
+ const desiredMap = new Map(desired.map((s) => [s.name, s]));
51
+ const currentMap = new Map(current.map((s) => [s.name, s]));
52
+ const toAdd = [];
53
+ const toRemove = [];
54
+ const unchanged = [];
55
+ for (const [name, skill] of desiredMap) {
56
+ const existing = currentMap.get(name);
57
+ if (!existing) {
58
+ toAdd.push(skill);
59
+ }
60
+ else if (existing.githubUrl !== skill.githubUrl) {
61
+ // URL changed — remove old, add new.
62
+ toRemove.push(existing);
63
+ toAdd.push(skill);
64
+ }
65
+ else {
66
+ unchanged.push(name);
67
+ }
68
+ }
69
+ for (const [name, entry] of currentMap) {
70
+ if (!desiredMap.has(name)) {
71
+ toRemove.push(entry);
72
+ }
73
+ }
74
+ return { toAdd, toRemove, unchanged };
75
+ }
76
+ /**
77
+ * Synchronise external skills on disk to match the spec.
78
+ *
79
+ * - Clones missing skills via `git clone --depth 1`.
80
+ * - Removes skills no longer in the spec.
81
+ * - Updates the `.skills-manifest.json`.
82
+ */
83
+ export async function syncExternalSkills(opts) {
84
+ const { targetDir, desired, log } = opts;
85
+ const skillsDir = path.join(targetDir, SKILLS_DIR);
86
+ await fs.mkdir(skillsDir, { recursive: true });
87
+ const current = await readManifest(targetDir);
88
+ const { toAdd, toRemove, unchanged } = diffSkills(desired, current);
89
+ const result = { added: [], removed: [], unchanged };
90
+ // Remove skills.
91
+ for (const entry of toRemove) {
92
+ const dir = path.join(skillsDir, entry.name);
93
+ log?.(`Removing skill "${entry.name}"…`);
94
+ await fs.rm(dir, { recursive: true, force: true });
95
+ result.removed.push(entry.name);
96
+ }
97
+ // Add skills.
98
+ for (const skill of toAdd) {
99
+ const dir = path.join(skillsDir, skill.name);
100
+ log?.(`Cloning skill "${skill.name}" from ${skill.githubUrl}…`);
101
+ // Ensure the target doesn't exist (re-add after URL change).
102
+ await fs.rm(dir, { recursive: true, force: true });
103
+ const { code, stderr } = await execGit(['clone', '--depth', '1', skill.githubUrl, skill.name], skillsDir);
104
+ if (code !== 0) {
105
+ log?.(`Warning: git clone failed for "${skill.name}": ${stderr.trim()}`);
106
+ continue;
107
+ }
108
+ // Remove .git dir — we don't want a nested repo.
109
+ await fs.rm(path.join(dir, '.git'), { recursive: true, force: true });
110
+ result.added.push(skill.name);
111
+ }
112
+ // Write updated manifest.
113
+ const newManifest = desired.map((s) => ({
114
+ name: s.name,
115
+ githubUrl: s.githubUrl,
116
+ }));
117
+ await writeManifest(targetDir, newManifest);
118
+ return result;
119
+ }
@@ -65,6 +65,9 @@ export declare const publishTrigger: import("@powerhousedao/ph-clint").Trigger<{
65
65
  setName: (name: string | {
66
66
  name: string;
67
67
  }) => import("document-model").SetNameAction;
68
+ setPreferredEditor: (input: string | null | {
69
+ preferredEditor: string | null;
70
+ }) => import("document-model").SetPreferredEditorAction;
68
71
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
69
72
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
70
73
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
@@ -69,6 +69,9 @@ export declare const specChangeTrigger: import("@powerhousedao/ph-clint").Trigge
69
69
  setName: (name: string | {
70
70
  name: string;
71
71
  }) => import("document-model").SetNameAction;
72
+ setPreferredEditor: (input: string | null | {
73
+ preferredEditor: string | null;
74
+ }) => import("document-model").SetPreferredEditorAction;
72
75
  undo: (count?: number, scope?: string) => import("document-model").UndoAction;
73
76
  redo: (count?: number, scope?: string) => import("document-model").RedoAction;
74
77
  prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powerhousedao/ph-clint-cli",
3
- "version": "0.1.0-dev.76",
3
+ "version": "0.1.0-dev.77",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -27,15 +27,15 @@
27
27
  "dependencies": {
28
28
  "@electric-sql/pglite": "0.3.15",
29
29
  "@mastra/core": "^1.22.0",
30
- "@mastra/libsql": "^1.7.4",
30
+ "@mastra/libsql": ">=1.7.4 <1.11.0",
31
31
  "@mastra/memory": "^1.13.1",
32
- "@powerhousedao/ph-clint": "^0.1.0-dev.76",
33
- "@powerhousedao/ph-clint-app": "^0.1.0-dev.76",
34
- "@powerhousedao/ph-clint-dev": "^0.1.0-dev.76",
35
- "@powerhousedao/reactor": "6.0.0-dev.216",
36
- "@powerhousedao/reactor-api": "6.0.0-dev.216",
37
- "@powerhousedao/shared": "6.0.0-dev.216",
38
- "document-model": "6.0.0-dev.216",
32
+ "@powerhousedao/ph-clint": "^0.1.0-dev.77",
33
+ "@powerhousedao/ph-clint-app": "^0.1.0-dev.77",
34
+ "@powerhousedao/ph-clint-dev": "^0.1.0-dev.77",
35
+ "@powerhousedao/reactor": "6.0.0-dev.257",
36
+ "@powerhousedao/reactor-api": "6.0.0-dev.257",
37
+ "@powerhousedao/shared": "6.0.0-dev.257",
38
+ "document-model": "6.0.0-dev.257",
39
39
  "kysely": "^0.27.0",
40
40
  "kysely-pglite-dialect": "^1.3.0",
41
41
  "zod": "^4.3.6"
@@ -1,8 +0,0 @@
1
- /**
2
- * Builds the root `publish.config.ts`.
3
- *
4
- * Split-layout: a lockstep group with both app and cli packages.
5
- * Single-layout: a single-package group at `.`.
6
- */
7
- import { type ClintProjectSpec } from '../../spec/types.js';
8
- export declare function buildPublishConfigTs(spec: ClintProjectSpec): string;
@@ -1,32 +0,0 @@
1
- /**
2
- * Builds the root `publish.config.ts`.
3
- *
4
- * Split-layout: a lockstep group with both app and cli packages.
5
- * Single-layout: a single-package group at `.`.
6
- */
7
- import { phAtLeast } from '../../spec/types.js';
8
- export function buildPublishConfigTs(spec) {
9
- const split = phAtLeast(spec.features.powerhouse, 'Reactor');
10
- // The publish pipeline appends the prerelease suffix (e.g. -dev.0), so we
11
- // only store the base semver (M.m.p) here.
12
- const baseVersion = spec.version.replace(/-.*$/, '');
13
- const packages = split
14
- ? `[
15
- { path: '${spec.name}-app', category: 'app' },
16
- { path: '${spec.name}-cli', category: 'cli' },
17
- ]`
18
- : `[
19
- { path: '.', category: 'cli' },
20
- ]`;
21
- return `// Publish config — loaded by ph-clint's publish pipeline.
22
- // definePublishConfig is an identity function; a plain export is equivalent.
23
- export default {
24
- groups: {
25
- '${spec.name}': {
26
- version: '${baseVersion}',
27
- packages: ${packages},
28
- },
29
- },
30
- };
31
- `;
32
- }
@@ -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 {};
@@ -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
- });
@@ -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>>;