@powerhousedao/ph-clint-cli 0.1.0-dev.86 → 0.1.0-dev.87

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 (64) hide show
  1. package/dist/codegen/actions.d.ts +46 -0
  2. package/dist/codegen/actions.js +424 -0
  3. package/dist/codegen/builders/agent-base-md.d.ts +5 -0
  4. package/dist/codegen/builders/agent-base-md.js +18 -0
  5. package/dist/codegen/builders/agent-ts.d.ts +9 -0
  6. package/dist/codegen/builders/agent-ts.js +124 -0
  7. package/dist/codegen/builders/app-index-ts.d.ts +11 -0
  8. package/dist/codegen/builders/app-index-ts.js +43 -0
  9. package/dist/codegen/builders/build-skills-ts.d.ts +4 -0
  10. package/dist/codegen/builders/build-skills-ts.js +37 -0
  11. package/dist/codegen/builders/cli-package-json.d.ts +8 -0
  12. package/dist/codegen/builders/cli-package-json.js +128 -0
  13. package/dist/codegen/builders/cli-ts.d.ts +7 -0
  14. package/dist/codegen/builders/cli-ts.js +170 -0
  15. package/dist/codegen/builders/config-ts.d.ts +8 -0
  16. package/dist/codegen/builders/config-ts.js +11 -0
  17. package/dist/codegen/builders/demo-agent-ts.d.ts +8 -0
  18. package/dist/codegen/builders/demo-agent-ts.js +50 -0
  19. package/dist/codegen/builders/eslint-config-js.d.ts +4 -0
  20. package/dist/codegen/builders/eslint-config-js.js +16 -0
  21. package/dist/codegen/builders/framework-gen-ts.d.ts +25 -0
  22. package/dist/codegen/builders/framework-gen-ts.js +114 -0
  23. package/dist/codegen/builders/framework-ts.d.ts +21 -0
  24. package/dist/codegen/builders/framework-ts.js +100 -0
  25. package/dist/codegen/builders/gitignore.d.ts +4 -0
  26. package/dist/codegen/builders/gitignore.js +18 -0
  27. package/dist/codegen/builders/index.d.ts +52 -0
  28. package/dist/codegen/builders/index.js +85 -0
  29. package/dist/codegen/builders/jest-config-js.d.ts +4 -0
  30. package/dist/codegen/builders/jest-config-js.js +19 -0
  31. package/dist/codegen/builders/main-ts.d.ts +5 -0
  32. package/dist/codegen/builders/main-ts.js +13 -0
  33. package/dist/codegen/builders/manifest-json.d.ts +6 -0
  34. package/dist/codegen/builders/manifest-json.js +31 -0
  35. package/dist/codegen/builders/mastra-index-ts.d.ts +11 -0
  36. package/dist/codegen/builders/mastra-index-ts.js +72 -0
  37. package/dist/codegen/builders/publish-config-js.d.ts +8 -0
  38. package/dist/codegen/builders/publish-config-js.js +33 -0
  39. package/dist/codegen/builders/readme-md.d.ts +5 -0
  40. package/dist/codegen/builders/readme-md.js +45 -0
  41. package/dist/codegen/builders/root-package-json.d.ts +10 -0
  42. package/dist/codegen/builders/root-package-json.js +39 -0
  43. package/dist/codegen/builders/smoke-test-ts.d.ts +2 -0
  44. package/dist/codegen/builders/smoke-test-ts.js +15 -0
  45. package/dist/codegen/builders/tsconfig-json.d.ts +4 -0
  46. package/dist/codegen/builders/tsconfig-json.js +22 -0
  47. package/dist/codegen/exec.d.ts +2 -0
  48. package/dist/codegen/exec.js +14 -0
  49. package/dist/codegen/generated.d.ts +17 -0
  50. package/dist/codegen/generated.js +49 -0
  51. package/dist/codegen/hashes.d.ts +6 -0
  52. package/dist/codegen/hashes.js +60 -0
  53. package/dist/codegen/markers.d.ts +36 -0
  54. package/dist/codegen/markers.js +86 -0
  55. package/dist/codegen/migrate/flat-to-split.d.ts +15 -0
  56. package/dist/codegen/migrate/flat-to-split.js +119 -0
  57. package/dist/codegen/scaffold.d.ts +72 -0
  58. package/dist/codegen/scaffold.js +150 -0
  59. package/dist/codegen/write.d.ts +6 -0
  60. package/dist/codegen/write.js +32 -0
  61. package/dist/commands/clint-project-init.d.ts +2 -0
  62. package/dist/skills/sync.d.ts +40 -0
  63. package/dist/skills/sync.js +119 -0
  64. package/package.json +21 -21
@@ -0,0 +1,43 @@
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
+ * Only re-exports document types belonging to the app package (the project's
7
+ * own reactor package). External packages' document types are imported from
8
+ * their own npm packages, not from the app barrel.
9
+ */
10
+ import { getAppPackageName, getDocumentTypeSlug, isDocTypeGlob, phAtLeast, } from '../../spec/types.js';
11
+ export function buildAppIndexTs(spec) {
12
+ if (!phAtLeast(spec.features.powerhouse, 'Reactor'))
13
+ return null;
14
+ const lines = [];
15
+ // Standard Powerhouse reactor-package barrel — matches what `ph init`
16
+ // generates. Required by main.tsx (Connect) and cli.ts imports.
17
+ lines.push('// THIS FILE IS GENERATED BY ph-clint-cli.');
18
+ lines.push("import type { Manifest } from 'document-model';");
19
+ lines.push("import manifestJson from './powerhouse.manifest.json' with { type: 'json' };");
20
+ lines.push("export { documentModels } from './document-models/document-models.js';");
21
+ lines.push("export { upgradeManifests } from './document-models/upgrade-manifests.js';");
22
+ lines.push("export { editors } from './editors/editors.js';");
23
+ lines.push("export { processorFactory } from './processors/factory.js';");
24
+ lines.push('export const manifest: Manifest = manifestJson;');
25
+ // Per-document-type re-exports so impl code can import from
26
+ // '{name}-app' instead of drilling into deep paths.
27
+ const appPkg = getAppPackageName(spec);
28
+ const appEntry = spec.packages.find((p) => p.packageName === appPkg);
29
+ const docTypes = appEntry?.documentTypes ?? [];
30
+ if (docTypes.length > 0) {
31
+ const hasGlobs = docTypes.some(isDocTypeGlob);
32
+ const explicits = docTypes.filter((dt) => !isDocTypeGlob(dt));
33
+ lines.push('');
34
+ if (hasGlobs) {
35
+ lines.push("export * from './document-models/index.js';");
36
+ }
37
+ for (const docType of explicits) {
38
+ const slug = getDocumentTypeSlug(docType);
39
+ lines.push(`export * from './document-models/${slug}/index.js';`);
40
+ }
41
+ }
42
+ return lines.join('\n') + '\n';
43
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Builds `scripts/build-skills.ts` — the build-time skill compiler.
3
+ */
4
+ export declare function buildBuildSkillsScript(): string;
@@ -0,0 +1,37 @@
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
+ }
@@ -0,0 +1,8 @@
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;
@@ -0,0 +1,128 @@
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 { getAppDirName, getAppPackageName, getBinName, getPackageName, phAtLeast, } from '../../spec/types.js';
8
+ import { CLI_VERSION } from '../../config.js';
9
+ import { getPhVersion } from '../scaffold.js';
10
+ /**
11
+ * Derive a semver range from the running ph-clint-cli version that respects
12
+ * the dev / staging / production channel boundary. This is the version range
13
+ * emitted into *scaffolded* projects' package.json for @powerhousedao/ph-clint
14
+ * and @powerhousedao/ph-clint-dev dependencies.
15
+ *
16
+ * CLI_VERSION is the version of ph-clint-cli itself (read from its own
17
+ * package.json at startup). Since all framework packages share a lockstep
18
+ * version, this is also the correct base for the dependency range.
19
+ *
20
+ * Examples:
21
+ * "0.1.0" → "^0.1.0" (production — stable only)
22
+ * "0.1.0-staging.2" → "^0.1.0-staging.0" (staging + stable)
23
+ * "0.1.0-dev.4" → "^0.1.0-dev.0" (dev + staging + stable)
24
+ *
25
+ * This works because semver orders prereleases alphabetically:
26
+ * dev.N < staging.N < release. A caret range starting at dev.0 naturally
27
+ * upgrades through staging to production.
28
+ */
29
+ function phClintRange(version) {
30
+ const match = /^(\d+\.\d+\.\d+)(?:-([a-z]+)\.\d+)?/.exec(version);
31
+ if (!match)
32
+ return `^${version}`;
33
+ const base = match[1];
34
+ const channel = match[2]; // "dev", "staging", or undefined
35
+ // For prerelease channels, pin exact version. Caret ranges like ^0.1.0-dev.0
36
+ // resolve to `latest` dist-tag (0.1.0-dev.0) instead of the highest match,
37
+ // causing "export not found" errors when the scaffolding CLI is newer.
38
+ return channel ? version : `^${base}`;
39
+ }
40
+ /** Version range for @powerhousedao/ph-clint{,-dev} deps in scaffolded projects. */
41
+ const PH_CLINT_VERSION = phClintRange(CLI_VERSION);
42
+ const POWERHOUSE_VERSION_FALLBACK = '6.0.0-dev.170';
43
+ let _powerhouseVersion;
44
+ function getPowerhouseVersion() {
45
+ if (_powerhouseVersion === undefined) {
46
+ _powerhouseVersion = getPhVersion('ph') ?? POWERHOUSE_VERSION_FALLBACK;
47
+ }
48
+ return _powerhouseVersion;
49
+ }
50
+ export function buildCliPackageJson(spec) {
51
+ const { mastra, powerhouse } = spec.features;
52
+ const pkgName = getPackageName(spec);
53
+ const bin = getBinName(spec);
54
+ const dependencies = {
55
+ '@powerhousedao/ph-clint': PH_CLINT_VERSION,
56
+ zod: '^4.3.6',
57
+ };
58
+ if (mastra.enabled) {
59
+ dependencies['@mastra/core'] = '^1.22.0';
60
+ dependencies['@mastra/libsql'] = '^1.7.4';
61
+ dependencies['@mastra/mcp'] = '^1.4.1';
62
+ dependencies['@mastra/memory'] = '^1.13.1';
63
+ }
64
+ if (phAtLeast(powerhouse, 'Reactor')) {
65
+ const appPkg = getAppPackageName(spec);
66
+ const appDir = getAppDirName(spec);
67
+ dependencies[appPkg] = `file:../${appDir}`;
68
+ dependencies['@powerhousedao/reactor'] = getPowerhouseVersion();
69
+ dependencies['@powerhousedao/reactor-api'] = getPowerhouseVersion();
70
+ dependencies['@powerhousedao/shared'] = getPowerhouseVersion();
71
+ dependencies['document-model'] = getPowerhouseVersion();
72
+ // External reactor packages (non-app) as versioned dependencies.
73
+ // Compare bare names (without scope) so that a spec entry with
74
+ // packageName "foo-app" still matches the scoped "@scope/foo-app".
75
+ const appBare = appPkg.replace(/^@[^/]+\//, '');
76
+ for (const pkg of spec.packages) {
77
+ const pkgBare = pkg.packageName.replace(/^@[^/]+\//, '');
78
+ if (pkgBare === appBare)
79
+ continue;
80
+ dependencies[pkg.packageName] = 'latest';
81
+ }
82
+ }
83
+ const scripts = {
84
+ 'build:skills': 'tsx scripts/build-skills.ts',
85
+ 'build:manifest': 'build-manifest',
86
+ build: 'pnpm build:skills && tsc && pnpm build:manifest',
87
+ dev: 'tsx src/main.ts',
88
+ start: 'node dist/main.js',
89
+ test: "NODE_OPTIONS='--experimental-vm-modules' jest --detectOpenHandles",
90
+ lint: 'eslint src',
91
+ };
92
+ if (mastra.enabled) {
93
+ scripts['mastra:dev'] = 'mastra dev';
94
+ scripts['mastra:build'] = 'mastra build';
95
+ scripts['mastra:start'] = 'mastra start';
96
+ }
97
+ // Single-layout: publish scripts live in the CLI package.json (which IS the
98
+ // root). Split-layout gets these from root-package-json.ts instead.
99
+ if (!phAtLeast(powerhouse, 'Reactor')) {
100
+ scripts['publish:dev'] = 'ph-publish dev -c ./publish.config.js';
101
+ scripts['publish:staging'] = 'ph-publish staging -c ./publish.config.js';
102
+ scripts['publish:production'] = 'ph-publish production -c ./publish.config.js';
103
+ }
104
+ const pkg = {
105
+ name: pkgName,
106
+ version: spec.version,
107
+ publishConfig: { access: 'public' },
108
+ type: 'module',
109
+ };
110
+ if (spec.description)
111
+ pkg.description = spec.description;
112
+ pkg.bin = { [bin]: './dist/main.js' };
113
+ pkg.files = ['dist'];
114
+ pkg.scripts = scripts;
115
+ pkg.dependencies = dependencies;
116
+ pkg.devDependencies = {
117
+ '@jest/globals': '^30.2.0',
118
+ '@types/node': '^25.5.2',
119
+ jest: '^30.2.0',
120
+ '@powerhousedao/ph-clint-dev': PH_CLINT_VERSION,
121
+ 'ts-jest': '^29.4.6',
122
+ tsx: '^4.19.0',
123
+ typescript: '^6.0.2',
124
+ 'typescript-eslint': '^8.33.0',
125
+ };
126
+ pkg.engines = { node: '>=22.13.0' };
127
+ return JSON.stringify(pkg, null, 2) + '\n';
128
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Builds `src/cli.ts` — the defineCli() call with feature blocks guarded by
3
+ * `@clint:begin`/`@clint:end` markers so the code generator can patch
4
+ * specific regions on subsequent runs (delta mode — future phase).
5
+ */
6
+ import { type ClintProjectSpec } from '../../spec/types.js';
7
+ export declare function buildCliTs(spec: ClintProjectSpec): string;
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Builds `src/cli.ts` — the defineCli() call with feature blocks guarded by
3
+ * `@clint:begin`/`@clint:end` markers so the code generator can patch
4
+ * specific regions on subsequent runs (delta mode — future phase).
5
+ */
6
+ import { getAppPackageName, phAtLeast } from '../../spec/types.js';
7
+ /** External packages that have document types (not the app package). */
8
+ function getExternalPackages(spec) {
9
+ const appPkg = getAppPackageName(spec);
10
+ return spec.packages.filter((p) => p.packageName !== appPkg && p.documentTypes.length > 0);
11
+ }
12
+ export function buildCliTs(spec) {
13
+ const { mastra, routine, powerhouse } = spec.features;
14
+ const ph = powerhouse;
15
+ const lines = [];
16
+ lines.push('/**');
17
+ lines.push(' * CLI definition.');
18
+ lines.push(' *');
19
+ lines.push(' * Generated by ph-clint. Regions bracketed by @clint:begin/@clint:end');
20
+ lines.push(' * markers are rewritten by ph-clint when the project spec changes.');
21
+ lines.push(' * Everything outside the markers is user-editable and preserved.');
22
+ lines.push(' */');
23
+ const needsRoot = phAtLeast(ph, 'Reactor') || mastra.enabled;
24
+ lines.push('// @clint:begin imports');
25
+ const phClintImports = ['defineCli'];
26
+ if (phAtLeast(ph, 'Reactor'))
27
+ phClintImports.push('buildDefaultReactor');
28
+ // proxy has no additional imports
29
+ lines.push(`import { ${phClintImports.join(', ')} } from '@powerhousedao/ph-clint';`);
30
+ if (needsRoot) {
31
+ lines.push("import path from 'node:path';");
32
+ }
33
+ lines.push(`import { CLI_NAME, CLI_VERSION${needsRoot ? ', CLI_ROOT' : ''} } from './config.js';`);
34
+ lines.push(`import { configSchema, secretsSchema } from './framework.js';`);
35
+ if (phAtLeast(ph, 'Reactor')) {
36
+ lines.push(`import { documentModels } from '${getAppPackageName(spec)}';`);
37
+ const extPkgs = getExternalPackages(spec);
38
+ for (let i = 0; i < extPkgs.length; i++) {
39
+ const alias = extPkgs.length === 1 ? 'extModels' : `extModels${i}`;
40
+ lines.push(`import { documentModels as ${alias} } from '${extPkgs[i].packageName}';`);
41
+ }
42
+ }
43
+ if (mastra.enabled) {
44
+ lines.push(`import { createAgent } from './agents/agent.js';`);
45
+ }
46
+ if (mastra.enabled && mastra.common?.enableChat) {
47
+ lines.push(`import { chatSessionWatchTrigger } from '@powerhousedao/clint-common/chat';`);
48
+ }
49
+ lines.push('// @clint:end imports');
50
+ lines.push('');
51
+ lines.push('export const cli = defineCli({');
52
+ lines.push(' name: CLI_NAME,');
53
+ lines.push(' version: CLI_VERSION,');
54
+ lines.push(' // @clint:begin root');
55
+ if (phAtLeast(ph, 'Reactor')) {
56
+ lines.push(' root: CLI_ROOT,');
57
+ }
58
+ lines.push(' // @clint:end root');
59
+ lines.push(' description: `${CLI_NAME} v${CLI_VERSION}`,');
60
+ lines.push(' configSchema,');
61
+ lines.push(' secretsSchema,');
62
+ lines.push('');
63
+ lines.push(' // @clint:begin commands');
64
+ lines.push(' commands: [],');
65
+ lines.push(' // @clint:end commands');
66
+ lines.push('');
67
+ lines.push(' // @clint:begin services');
68
+ lines.push(' services: [],');
69
+ lines.push(' // @clint:end services');
70
+ lines.push('');
71
+ lines.push(' // @clint:begin triggers');
72
+ if (mastra.enabled && mastra.common?.enableChat) {
73
+ lines.push(' triggers: [chatSessionWatchTrigger],');
74
+ }
75
+ else {
76
+ lines.push(' triggers: [],');
77
+ }
78
+ lines.push(' // @clint:end triggers');
79
+ lines.push('');
80
+ lines.push(' // @clint:begin prompts');
81
+ lines.push(' prompts: {');
82
+ if (mastra.enabled) {
83
+ lines.push(" artifacts: [path.join(CLI_ROOT, 'gen', 'skills'), path.join(CLI_ROOT, 'dist', 'gen', 'skills')],");
84
+ }
85
+ else {
86
+ lines.push(' artifacts: [],');
87
+ }
88
+ if (mastra.enabled && mastra.agentId) {
89
+ lines.push(' agents: {');
90
+ lines.push(` '${mastra.agentId}': {`);
91
+ if (mastra.profiles.length > 0) {
92
+ lines.push(` name: '${mastra.profiles[0].id}',`);
93
+ lines.push(' sections: [');
94
+ for (const p of mastra.profiles) {
95
+ lines.push(` '${p.id}.md',`);
96
+ }
97
+ lines.push(' ],');
98
+ }
99
+ else {
100
+ lines.push(" name: 'AgentBase',");
101
+ lines.push(" sections: ['AgentBase.md'],");
102
+ }
103
+ lines.push(' skills: [],');
104
+ lines.push(' },');
105
+ lines.push(' },');
106
+ }
107
+ else {
108
+ lines.push(' agents: {},');
109
+ }
110
+ lines.push(' skills: {},');
111
+ lines.push(' },');
112
+ lines.push(' // @clint:end prompts');
113
+ lines.push('');
114
+ lines.push(' // @clint:begin events');
115
+ lines.push(' events: {},');
116
+ lines.push(' // @clint:end events');
117
+ lines.push('');
118
+ lines.push(' // @clint:begin proxy');
119
+ if (spec.deployment.proxyEnabled) {
120
+ lines.push(' proxyEnabled: true,');
121
+ }
122
+ lines.push(' // @clint:end proxy');
123
+ lines.push('');
124
+ lines.push(' // @clint:begin interactive');
125
+ lines.push(' interactive: {');
126
+ lines.push(` welcome: ({ workdir }) =>`);
127
+ lines.push(' [');
128
+ lines.push(' `${CLI_NAME} v${CLI_VERSION}`,');
129
+ lines.push(' `Workdir: ${workdir}`,');
130
+ lines.push(" '',");
131
+ if (mastra.enabled) {
132
+ lines.push(" 'Type a message to talk to the agent, or / for commands.',");
133
+ }
134
+ else {
135
+ lines.push(" 'Type / for commands or /cli-docs for help.',");
136
+ }
137
+ lines.push(" ].join('\\n'),");
138
+ lines.push(' },');
139
+ lines.push(' // @clint:end interactive');
140
+ lines.push('});');
141
+ lines.push('');
142
+ lines.push('// @clint:begin reactor');
143
+ if (phAtLeast(ph, 'Reactor')) {
144
+ lines.push('cli.configureReactor({');
145
+ lines.push(' create: (ctx) =>');
146
+ lines.push(' buildDefaultReactor(ctx, {');
147
+ const extPkgs = getExternalPackages(spec);
148
+ if (extPkgs.length === 0) {
149
+ lines.push(' documentModels,');
150
+ }
151
+ else {
152
+ const aliases = extPkgs.map((_, i) => extPkgs.length === 1 ? 'extModels' : `extModels${i}`);
153
+ lines.push(` documentModels: [...documentModels, ${aliases.map(a => `...${a}`).join(', ')}],`);
154
+ }
155
+ lines.push(` drive: { name: '${spec.name}' },`);
156
+ lines.push(' subscriptions: {},');
157
+ lines.push(' }),');
158
+ lines.push(` switchboard: { enabled: ${String(phAtLeast(ph, 'Switchboard'))} },`);
159
+ lines.push(` connect: { enabled: ${String(phAtLeast(ph, 'Connect'))} },`);
160
+ lines.push('});');
161
+ }
162
+ lines.push('// @clint:end reactor');
163
+ lines.push('');
164
+ lines.push('// @clint:begin mastra');
165
+ if (mastra.enabled) {
166
+ lines.push('cli.configureAgent(createAgent);');
167
+ }
168
+ lines.push('// @clint:end mastra');
169
+ return lines.join('\n') + '\n';
170
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Builds `src/config.ts` — CLI identity constants (name, version, project
3
+ * root path). The Zod `configSchema` / `secretsSchema` are emitted by
4
+ * `buildFrameworkTs` into `src/framework.ts` (user-owned, init-only) so users
5
+ * can extend them without fighting the generator.
6
+ */
7
+ import { type ClintProjectSpec } from '../../spec/types.js';
8
+ export declare function buildConfigTs(_spec: ClintProjectSpec): string;
@@ -0,0 +1,11 @@
1
+ export function buildConfigTs(_spec) {
2
+ const lines = [];
3
+ lines.push(`import { readPackageInfo } from '@powerhousedao/ph-clint';`);
4
+ lines.push('');
5
+ lines.push('const pkg = readPackageInfo(import.meta.url);');
6
+ lines.push('');
7
+ lines.push('export const CLI_ROOT = pkg.root;');
8
+ lines.push(`export const CLI_NAME = pkg.name.replace(/-cli$/, '');`);
9
+ lines.push('export const CLI_VERSION = pkg.version;');
10
+ return lines.join('\n') + '\n';
11
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Builds `src/agents/demo-agent.ts` — a deterministic echo agent fallback.
3
+ *
4
+ * Generated when `features.mastra.enabled` with full agent config so the real
5
+ * agent factory can fall back to demo mode when no API key is configured.
6
+ */
7
+ import { type ClintProjectSpec } from '../../spec/types.js';
8
+ export declare function buildDemoAgentTs(spec: ClintProjectSpec): string | null;
@@ -0,0 +1,50 @@
1
+ export function buildDemoAgentTs(spec) {
2
+ const { mastra } = spec.features;
3
+ // Only needed alongside the real agent (which imports it)
4
+ if (!mastra.enabled || !mastra.agentId || mastra.models.length === 0)
5
+ return null;
6
+ const agentId = mastra.agentId;
7
+ const agentName = mastra.agentName ?? agentId;
8
+ const agentDescription = mastra.agentDescription;
9
+ const agentImage = mastra.agentImage;
10
+ return [
11
+ "import type { AgentProvider, StreamChunk } from '@powerhousedao/ph-clint';",
12
+ '',
13
+ '/**',
14
+ ' * Demo agent — deterministic echo responses without an API key.',
15
+ ' *',
16
+ ' * Echoes user prompts with conversation tracking per thread.',
17
+ ' */',
18
+ 'export function createDemoAgent(): AgentProvider {',
19
+ ' const conversations = new Map<string, string[]>();',
20
+ '',
21
+ ' return {',
22
+ ` id: '${agentId}',`,
23
+ ` name: '${agentName}',`,
24
+ ...(agentDescription ? [` description: ${JSON.stringify(agentDescription)},`] : []),
25
+ ...(agentImage ? [` image: ${JSON.stringify(agentImage)},`] : []),
26
+ ' async *stream(prompt, opts) {',
27
+ " const threadId = opts?.threadId ?? 'default';",
28
+ ' if (!conversations.has(threadId)) {',
29
+ ' conversations.set(threadId, []);',
30
+ ' }',
31
+ ' const history = conversations.get(threadId)!;',
32
+ ' history.push(prompt);',
33
+ '',
34
+ ' const turnCount = history.length;',
35
+ ' if (turnCount > 1) {',
36
+ ' yield {',
37
+ " type: 'text-delta',",
38
+ ' text: `I understand you\'re continuing our conversation (turn ${turnCount}). `,',
39
+ ' } satisfies StreamChunk;',
40
+ ' }',
41
+ ' yield {',
42
+ " type: 'text-delta',",
43
+ ' text: `You said: "${prompt}". I\'m the demo agent — set an API key for real LLM responses.`,',
44
+ ' } satisfies StreamChunk;',
45
+ ' },',
46
+ ' };',
47
+ '}',
48
+ '',
49
+ ].join('\n');
50
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Builds `eslint.config.js` for the CLI — minimal TypeScript-ESLint config.
3
+ */
4
+ export declare function buildEslintConfigJs(): string;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Builds `eslint.config.js` for the CLI — minimal TypeScript-ESLint config.
3
+ */
4
+ export function buildEslintConfigJs() {
5
+ return [
6
+ '// @clint:begin eslint',
7
+ "import tseslint from 'typescript-eslint';",
8
+ '',
9
+ 'export default tseslint.config(',
10
+ ' tseslint.configs.recommended,',
11
+ " { ignores: ['dist/', 'gen/', 'coverage/'] },",
12
+ ');',
13
+ '// @clint:end eslint',
14
+ '',
15
+ ].join('\n');
16
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Builds `src/framework.gen.ts` — the fully machine-owned half of the
3
+ * typed-binding split. Regenerated on every `init` and `update`; holds the
4
+ * `defineRegistry([...])` call that describes which document models
5
+ * are bound into `framework.ts`'s typed factories.
6
+ *
7
+ * Iterates all packages' document types. The app package's modules are
8
+ * imported from the local `{name}-app` package; external packages' modules
9
+ * are imported from their npm package name.
10
+ *
11
+ * Document type entries may be explicit IDs (`powerhouse/ph-clint-project`)
12
+ * or glob patterns (`*​/*`, `powerhouse/*`, `acme/doc-*`). Explicit IDs
13
+ * produce static named imports; glob patterns import the package's
14
+ * `documentModels` array and filter at runtime so newly-added document
15
+ * models are picked up without a codegen re-run.
16
+ *
17
+ * Emitted only when Powerhouse is enabled — flat-layout impls have no
18
+ * reactor package to import modules from and bind `createTypes` directly in
19
+ * `framework.ts`. When Powerhouse is on but no document types are declared,
20
+ * we still emit this file with an empty `defineRegistry([])` so impl code's
21
+ * `import { registry } from './framework.gen.js'` keeps resolving across
22
+ * regens.
23
+ */
24
+ import { type ClintProjectSpec } from '../../spec/types.js';
25
+ export declare function buildFrameworkGenTs(spec: ClintProjectSpec): string | null;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Builds `src/framework.gen.ts` — the fully machine-owned half of the
3
+ * typed-binding split. Regenerated on every `init` and `update`; holds the
4
+ * `defineRegistry([...])` call that describes which document models
5
+ * are bound into `framework.ts`'s typed factories.
6
+ *
7
+ * Iterates all packages' document types. The app package's modules are
8
+ * imported from the local `{name}-app` package; external packages' modules
9
+ * are imported from their npm package name.
10
+ *
11
+ * Document type entries may be explicit IDs (`powerhouse/ph-clint-project`)
12
+ * or glob patterns (`*​/*`, `powerhouse/*`, `acme/doc-*`). Explicit IDs
13
+ * produce static named imports; glob patterns import the package's
14
+ * `documentModels` array and filter at runtime so newly-added document
15
+ * models are picked up without a codegen re-run.
16
+ *
17
+ * Emitted only when Powerhouse is enabled — flat-layout impls have no
18
+ * reactor package to import modules from and bind `createTypes` directly in
19
+ * `framework.ts`. When Powerhouse is on but no document types are declared,
20
+ * we still emit this file with an empty `defineRegistry([])` so impl code's
21
+ * `import { registry } from './framework.gen.js'` keeps resolving across
22
+ * regens.
23
+ */
24
+ import { docTypeGlobToRegex, getAppPackageName, getDocumentTypeModuleName, getDocumentTypeSlug, isDocTypeGlob, phAtLeast, } from '../../spec/types.js';
25
+ export function buildFrameworkGenTs(spec) {
26
+ if (!phAtLeast(spec.features.powerhouse, 'Reactor'))
27
+ return null;
28
+ const appPkg = getAppPackageName(spec);
29
+ // Collect entries across packages. Each package may contribute both
30
+ // explicit named imports and glob-based runtime filters.
31
+ const entries = [];
32
+ let globCounter = 0;
33
+ for (const pkg of spec.packages) {
34
+ const isApp = pkg.packageName === appPkg;
35
+ // Collect glob patterns for this package (may be multiple).
36
+ const globs = pkg.documentTypes.filter(isDocTypeGlob);
37
+ const explicits = pkg.documentTypes.filter((dt) => !isDocTypeGlob(dt));
38
+ for (const docType of explicits) {
39
+ const slug = getDocumentTypeSlug(docType);
40
+ entries.push({
41
+ kind: 'explicit',
42
+ name: getDocumentTypeModuleName(docType),
43
+ importFrom: isApp ? appPkg : `${pkg.packageName}/document-models/${slug}`,
44
+ });
45
+ }
46
+ if (globs.length > 0) {
47
+ // Merge all globs for this package into a single regex alternation.
48
+ const combined = globs.length === 1
49
+ ? docTypeGlobToRegex(globs[0])
50
+ : globs.map((g) => `(?:${docTypeGlobToRegex(g)})`).join('|');
51
+ const alias = globCounter === 0 ? 'globModels' : `globModels${globCounter}`;
52
+ globCounter++;
53
+ entries.push({
54
+ kind: 'glob',
55
+ modelsAlias: alias,
56
+ importFrom: isApp ? appPkg : pkg.packageName,
57
+ regexSource: combined,
58
+ });
59
+ }
60
+ }
61
+ const hasGlobs = entries.some((e) => e.kind === 'glob');
62
+ const lines = [];
63
+ lines.push('/**');
64
+ lines.push(' * THIS FILE IS GENERATED BY ph-clint-cli. DO NOT EDIT.');
65
+ lines.push(' *');
66
+ lines.push(' * Regenerated on every `ph-clint clint-project-regen` and on every spec-change');
67
+ lines.push(' * tick. Put custom bindings in `framework.ts`, not here — edits to');
68
+ lines.push(' * this file will be overwritten.');
69
+ lines.push(' */');
70
+ lines.push(`import { defineRegistry } from '@powerhousedao/ph-clint';`);
71
+ // Emit imports — named imports for explicit entries, documentModels for globs.
72
+ for (const e of entries) {
73
+ if (e.kind === 'explicit') {
74
+ lines.push(`import { ${e.name} } from '${e.importFrom}';`);
75
+ }
76
+ else {
77
+ lines.push(`import { documentModels as ${e.modelsAlias} } from '${e.importFrom}';`);
78
+ }
79
+ }
80
+ lines.push('');
81
+ lines.push('/**');
82
+ lines.push(' * Typed document registry derived from the reactor package\'s document models.');
83
+ lines.push(' * Regenerated whenever the spec\'s packages or document types change.');
84
+ lines.push(' */');
85
+ if (entries.length === 0) {
86
+ lines.push('export const registry = defineRegistry([] as const);');
87
+ }
88
+ else if (!hasGlobs) {
89
+ // Pure explicit — use `as const` for full type inference.
90
+ lines.push('export const registry = defineRegistry([');
91
+ for (const e of entries) {
92
+ if (e.kind === 'explicit') {
93
+ lines.push(` ${e.name},`);
94
+ }
95
+ }
96
+ lines.push('] as const);');
97
+ }
98
+ else {
99
+ // Mix of explicit + glob — runtime filter loses `as const` inference.
100
+ lines.push('export const registry = defineRegistry([');
101
+ for (const e of entries) {
102
+ if (e.kind === 'explicit') {
103
+ lines.push(` ${e.name},`);
104
+ }
105
+ else {
106
+ lines.push(` ...${e.modelsAlias}.filter((m) => /${e.regexSource}/.test(m.documentModel.global.id)),`);
107
+ }
108
+ }
109
+ lines.push(']);');
110
+ }
111
+ lines.push('');
112
+ lines.push('export type Registry = typeof registry;');
113
+ return lines.join('\n') + '\n';
114
+ }