@powerhousedao/ph-clint-cli 0.1.0-dev.3 → 0.1.0-dev.30
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 +31 -12
- package/dist/codegen/builders/agent-ts.d.ts +4 -4
- package/dist/codegen/builders/agent-ts.js +83 -2
- package/dist/codegen/builders/app-index-ts.d.ts +3 -10
- package/dist/codegen/builders/app-index-ts.js +10 -14
- package/dist/codegen/builders/cli-package-json.js +48 -8
- package/dist/codegen/builders/cli-ts.js +63 -22
- package/dist/codegen/builders/config-ts.js +11 -15
- package/dist/codegen/builders/demo-agent-ts.d.ts +8 -0
- package/dist/codegen/builders/demo-agent-ts.js +44 -0
- package/dist/codegen/builders/framework-gen-ts.d.ts +4 -5
- package/dist/codegen/builders/framework-gen-ts.js +22 -19
- package/dist/codegen/builders/framework-ts.js +33 -7
- package/dist/codegen/builders/index.d.ts +9 -1
- package/dist/codegen/builders/index.js +28 -4
- 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-ts.d.ts +6 -0
- package/dist/codegen/builders/publish-config-ts.js +21 -0
- package/dist/codegen/builders/readme-md.js +8 -7
- package/dist/codegen/builders/root-package-json.d.ts +3 -0
- package/dist/codegen/builders/root-package-json.js +24 -11
- package/dist/codegen/index.js +26 -12
- package/dist/codegen/scaffold.d.ts +21 -3
- package/dist/codegen/scaffold.js +90 -16
- package/dist/commands/clint-project-build.js +10 -27
- package/dist/commands/clint-project-init.d.ts +30 -6
- package/dist/commands/clint-project-init.js +45 -9
- package/dist/commands/clint-project-publish.d.ts +1 -0
- package/dist/commands/clint-project-publish.js +5 -3
- package/dist/commands/clint-project-regen.js +2 -2
- package/dist/commands/clint-skills-sync.d.ts +10 -0
- package/dist/commands/clint-skills-sync.js +56 -0
- package/dist/config.d.ts +3 -5
- package/dist/config.js +5 -7
- package/dist/framework.d.ts +5 -169
- package/dist/framework.gen.d.ts +1 -32
- package/dist/framework.gen.js +1 -1
- package/dist/framework.js +0 -4
- 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/services/clint-project.js +21 -0
- package/dist/skills/sync.d.ts +40 -0
- package/dist/skills/sync.js +119 -0
- package/dist/spec/from-document.d.ts +4 -1
- package/dist/spec/from-document.js +18 -8
- package/dist/spec/types.d.ts +85 -6
- package/dist/spec/types.js +90 -23
- package/dist/triggers/publish-trigger.d.ts +10 -0
- package/dist/triggers/publish-trigger.js +169 -0
- package/dist/triggers/spec-change.d.ts +5 -34
- package/dist/triggers/spec-change.js +175 -99
- package/package.json +7 -7
- package/prompts/skills-ext/.gitkeep +0 -0
- package/prompts/skills-tpl/.gitkeep +0 -0
package/dist/cli.js
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* Everything outside the markers is user-editable and preserved.
|
|
8
8
|
*/
|
|
9
9
|
import path from 'node:path';
|
|
10
|
-
import { fileURLToPath } from 'node:url';
|
|
11
10
|
import { defineCli, buildDefaultReactor } from '@powerhousedao/ph-clint';
|
|
12
|
-
import {
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import { CLI_NAME, CLI_VERSION, CLI_ROOT } from './config.js';
|
|
13
13
|
import { configSchema, secretsSchema } from './framework.js';
|
|
14
14
|
// @clint:begin imports
|
|
15
15
|
import { documentModels } from '@powerhousedao/ph-clint-app';
|
|
@@ -19,31 +19,48 @@ import { regen } from './commands/clint-project-regen.js';
|
|
|
19
19
|
import { build } from './commands/clint-project-build.js';
|
|
20
20
|
import { clintProjectPublish } from './commands/clint-project-publish.js';
|
|
21
21
|
import { clintProject } from './services/clint-project.js';
|
|
22
|
+
import { skillsSync } from './commands/clint-skills-sync.js';
|
|
22
23
|
import { specChangeTrigger } from './triggers/spec-change.js';
|
|
24
|
+
import { publishTrigger } from './triggers/publish-trigger.js';
|
|
23
25
|
// @clint:end imports
|
|
24
|
-
// Connect (ph connect) must run inside the Reactor Package (ph-clint-app).
|
|
25
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
26
|
-
const appDir = path.resolve(__dirname, '../../ph-clint-app');
|
|
27
26
|
export const cli = defineCli({
|
|
28
27
|
name: CLI_NAME,
|
|
29
28
|
version: CLI_VERSION,
|
|
29
|
+
root: CLI_ROOT,
|
|
30
30
|
description: `${CLI_NAME} v${CLI_VERSION} — scaffold and maintain ph-clint implementation projects`,
|
|
31
31
|
configSchema,
|
|
32
32
|
secretsSchema,
|
|
33
33
|
// @clint:begin commands
|
|
34
|
-
commands: [init, regen, build, clintProjectPublish],
|
|
34
|
+
commands: [init, regen, build, clintProjectPublish, skillsSync],
|
|
35
35
|
// @clint:end commands
|
|
36
36
|
// @clint:begin services
|
|
37
37
|
services: [clintProject],
|
|
38
38
|
// @clint:end services
|
|
39
39
|
// @clint:begin triggers
|
|
40
|
-
triggers: [specChangeTrigger],
|
|
40
|
+
triggers: [specChangeTrigger, publishTrigger],
|
|
41
41
|
// @clint:end triggers
|
|
42
42
|
// @clint:begin prompts
|
|
43
43
|
prompts: {
|
|
44
|
-
|
|
45
|
-
agents: {
|
|
46
|
-
|
|
44
|
+
artifacts: [path.join(CLI_ROOT, 'gen', 'skills'), path.join(CLI_ROOT, 'dist', 'gen', 'skills')],
|
|
45
|
+
agents: {
|
|
46
|
+
'ph-clint-dev-agent': {
|
|
47
|
+
name: 'PhClintDevAgent',
|
|
48
|
+
sections: ['AgentBase.md'],
|
|
49
|
+
skills: ['command-definition'],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
skills: {
|
|
53
|
+
'command-definition': {
|
|
54
|
+
description: 'Define commands with Zod schemas, execute functions, return values, and parameter prompting',
|
|
55
|
+
inputSchema: z.object({
|
|
56
|
+
mode: z
|
|
57
|
+
.enum(['expert', 'discovery', 'one-shot'])
|
|
58
|
+
.default('expert')
|
|
59
|
+
.describe('Expert: align design decisions with the developer. Discovery: explain concepts step by step. One-shot: make all decisions autonomously'),
|
|
60
|
+
}),
|
|
61
|
+
instructionTemplate: 'Use your {{skillId}} skill in {{mode}} mode for: {{prompt}}',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
47
64
|
},
|
|
48
65
|
// @clint:end prompts
|
|
49
66
|
// @clint:begin events
|
|
@@ -70,11 +87,13 @@ export const cli = defineCli({
|
|
|
70
87
|
cli.configureReactor({
|
|
71
88
|
create: (ctx) => buildDefaultReactor(ctx, {
|
|
72
89
|
documentModels,
|
|
73
|
-
|
|
90
|
+
drives: [
|
|
91
|
+
{ name: 'Clint Folders', role: 'personal' },
|
|
92
|
+
],
|
|
74
93
|
subscriptions: { documentTypes: ['powerhouse/ph-clint-project'] },
|
|
75
94
|
}),
|
|
76
95
|
switchboard: { enabled: true },
|
|
77
|
-
connect: { enabled: true
|
|
96
|
+
connect: { enabled: true },
|
|
78
97
|
});
|
|
79
98
|
// @clint:end reactor
|
|
80
99
|
// @clint:begin mastra
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Builds `src/agents/agent.ts` — a
|
|
2
|
+
* Builds `src/agents/agent.ts` — a Mastra agent factory.
|
|
3
3
|
*
|
|
4
|
-
* Emitted only when `features.mastra.enabled`.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Emitted only when `features.mastra.enabled`. When the spec includes agent
|
|
5
|
+
* config (agentId, models, profiles), generates a real `@mastra/core` Agent.
|
|
6
|
+
* Otherwise falls back to a deterministic echo-style demo provider.
|
|
7
7
|
*/
|
|
8
8
|
import { type ClintProjectSpec } from '../../spec/types.js';
|
|
9
9
|
export declare function buildAgentTs(spec: ClintProjectSpec): string;
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/** Map provider prefix to AI SDK package. */
|
|
2
|
+
function providerImport(provider) {
|
|
3
|
+
switch (provider) {
|
|
4
|
+
case 'anthropic':
|
|
5
|
+
return { pkg: '@ai-sdk/anthropic', fn: 'anthropic' };
|
|
6
|
+
case 'openai':
|
|
7
|
+
return { pkg: '@ai-sdk/openai', fn: 'openai' };
|
|
8
|
+
case 'google':
|
|
9
|
+
return { pkg: '@ai-sdk/google', fn: 'google' };
|
|
10
|
+
default:
|
|
11
|
+
return { pkg: `@ai-sdk/${provider}`, fn: provider };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function buildDemoAgent(spec) {
|
|
15
|
+
const id = spec.features.mastra.agentId ?? spec.name;
|
|
3
16
|
return [
|
|
4
17
|
"import type { AgentProvider, AgentSetupContext, StreamChunk } from '@powerhousedao/ph-clint';",
|
|
5
18
|
"import type { Config } from '../framework.js';",
|
|
@@ -32,3 +45,71 @@ export function buildAgentTs(spec) {
|
|
|
32
45
|
'',
|
|
33
46
|
].join('\n');
|
|
34
47
|
}
|
|
48
|
+
function buildRealAgent(spec) {
|
|
49
|
+
const mastra = spec.features.mastra;
|
|
50
|
+
const agentId = mastra.agentId;
|
|
51
|
+
const agentName = mastra.agentName;
|
|
52
|
+
const defaultModel = mastra.models.find(m => m.isDefault) ?? mastra.models[0];
|
|
53
|
+
const modelId = defaultModel?.id ?? 'anthropic/claude-sonnet-4-5';
|
|
54
|
+
const [provider] = modelId.split(/[:/]/);
|
|
55
|
+
const { pkg, fn } = providerImport(provider);
|
|
56
|
+
const apiKeyField = `${provider}ApiKey`;
|
|
57
|
+
const lines = [];
|
|
58
|
+
lines.push("import { Agent } from '@mastra/core/agent';");
|
|
59
|
+
lines.push("import { MCPClient } from '@mastra/mcp';");
|
|
60
|
+
lines.push("import { createMastraHelpers } from '@powerhousedao/ph-clint/mastra';");
|
|
61
|
+
lines.push("import { createWorkdirStore } from '@powerhousedao/ph-clint';");
|
|
62
|
+
lines.push("import type { AgentSetupContext, AgentProvider } from '@powerhousedao/ph-clint';");
|
|
63
|
+
lines.push("import type { WrapAgentOptions } from '@powerhousedao/ph-clint/mastra';");
|
|
64
|
+
lines.push("import { CLI_NAME } from '../config.js';");
|
|
65
|
+
lines.push("import type { Config } from '../framework.js';");
|
|
66
|
+
lines.push("import { createDemoAgent } from './demo-agent.js';");
|
|
67
|
+
lines.push('');
|
|
68
|
+
lines.push('/**');
|
|
69
|
+
lines.push(' * Agent factory for the CLI.');
|
|
70
|
+
lines.push(' *');
|
|
71
|
+
lines.push(' * Returns a demo agent when no API key is configured, or wraps the full');
|
|
72
|
+
lines.push(' * agent as a ph-clint AgentProvider.');
|
|
73
|
+
lines.push(' */');
|
|
74
|
+
lines.push('export async function createAgent(ctx: AgentSetupContext<Config>): Promise<AgentProvider> {');
|
|
75
|
+
lines.push(` if (!ctx.config.${apiKeyField}) return createDemoAgent();`);
|
|
76
|
+
lines.push('');
|
|
77
|
+
lines.push(' const m = createMastraHelpers(ctx);');
|
|
78
|
+
lines.push('');
|
|
79
|
+
lines.push(' const agent = new Agent({');
|
|
80
|
+
lines.push(` id: '${agentId}',`);
|
|
81
|
+
lines.push(` name: '${agentName}',`);
|
|
82
|
+
lines.push(` instructions: m.getAgentInstructions('${agentId}'),`);
|
|
83
|
+
lines.push(` model: ctx.config.${apiKeyField}`);
|
|
84
|
+
lines.push(` ? { id: ctx.config.model as \`\${string}/\${string}\`, apiKey: ctx.config.${apiKeyField} }`);
|
|
85
|
+
lines.push(` : (ctx.config.model as \`\${string}/\${string}\`),`);
|
|
86
|
+
lines.push(' tools: async () => {');
|
|
87
|
+
lines.push(" ctx.context.log?.debug('[agent] tools callback invoked');");
|
|
88
|
+
lines.push(' const tools = await m.getTools({ MCPClient });');
|
|
89
|
+
lines.push(" ctx.context.log?.debug(`[agent] tools resolved: ${Object.keys(tools).length} tools`);");
|
|
90
|
+
lines.push(' return tools;');
|
|
91
|
+
lines.push(' },');
|
|
92
|
+
lines.push(' workspace: await m.createWorkspace(),');
|
|
93
|
+
lines.push(' memory: await m.createMemory(),');
|
|
94
|
+
lines.push(' });');
|
|
95
|
+
lines.push('');
|
|
96
|
+
lines.push(' const store = createWorkdirStore(ctx.workdir, CLI_NAME);');
|
|
97
|
+
lines.push(' const wrapOpts: WrapAgentOptions = {');
|
|
98
|
+
lines.push(' maxSteps: 80,');
|
|
99
|
+
lines.push(' enableLogging: ctx.config.agentLogging,');
|
|
100
|
+
lines.push(" logDirectory: store.getStoreFolder('logs'),");
|
|
101
|
+
lines.push(' cacheControl: true,');
|
|
102
|
+
lines.push(' };');
|
|
103
|
+
lines.push(' return m.wrapAgent(agent, wrapOpts);');
|
|
104
|
+
lines.push('}');
|
|
105
|
+
lines.push('');
|
|
106
|
+
return lines.join('\n');
|
|
107
|
+
}
|
|
108
|
+
export function buildAgentTs(spec) {
|
|
109
|
+
const mastra = spec.features.mastra;
|
|
110
|
+
// Generate real agent when we have full config, demo otherwise
|
|
111
|
+
if (mastra.agentId && mastra.models.length > 0) {
|
|
112
|
+
return buildRealAgent(spec);
|
|
113
|
+
}
|
|
114
|
+
return buildDemoAgent(spec);
|
|
115
|
+
}
|
|
@@ -3,16 +3,9 @@
|
|
|
3
3
|
* reactor package. Impl code imports from `'{name}-app'` instead of drilling
|
|
4
4
|
* into `'{name}-app/document-models/<slug>/v1/gen/...'`.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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).
|
|
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.
|
|
16
9
|
*/
|
|
17
10
|
import { type ClintProjectSpec } from '../../spec/types.js';
|
|
18
11
|
export declare function buildAppIndexTs(spec: ClintProjectSpec): string | null;
|
|
@@ -3,29 +3,25 @@
|
|
|
3
3
|
* reactor package. Impl code imports from `'{name}-app'` instead of drilling
|
|
4
4
|
* into `'{name}-app/document-models/<slug>/v1/gen/...'`.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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).
|
|
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.
|
|
16
9
|
*/
|
|
17
|
-
import { getDocumentTypeSlug, } from '../../spec/types.js';
|
|
10
|
+
import { getAppPackageName, getDocumentTypeSlug, phAtLeast, } from '../../spec/types.js';
|
|
18
11
|
export function buildAppIndexTs(spec) {
|
|
19
|
-
if (!spec.features.powerhouse
|
|
12
|
+
if (!phAtLeast(spec.features.powerhouse, 'Reactor'))
|
|
20
13
|
return null;
|
|
21
|
-
|
|
14
|
+
const appPkg = getAppPackageName(spec);
|
|
15
|
+
const appEntry = spec.packages.find((p) => p.packageName === appPkg);
|
|
16
|
+
const docTypes = appEntry?.documentTypes ?? [];
|
|
17
|
+
if (docTypes.length === 0)
|
|
22
18
|
return null;
|
|
23
19
|
const lines = [];
|
|
24
20
|
lines.push('// THIS FILE IS GENERATED BY ph-clint-cli.');
|
|
25
21
|
lines.push('// Re-exports every registered document model from a single top-level');
|
|
26
22
|
lines.push('// entry so impl code can `import { ... } from \'{name}-app\'`.');
|
|
27
23
|
lines.push('');
|
|
28
|
-
for (const docType of
|
|
24
|
+
for (const docType of docTypes) {
|
|
29
25
|
const slug = getDocumentTypeSlug(docType);
|
|
30
26
|
lines.push(`export * from './document-models/${slug}/index.js';`);
|
|
31
27
|
}
|
|
@@ -4,13 +4,44 @@
|
|
|
4
4
|
* When `features.powerhouse.enabled`, this file lives at
|
|
5
5
|
* `{root}/{name}-cli/package.json`. Otherwise at `{root}/package.json`.
|
|
6
6
|
*/
|
|
7
|
-
import { getBinName, getPackageName, } from '../../spec/types.js';
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
import { getAppDirName, getAppPackageName, getBinName, getPackageName, phAtLeast, } 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
|
+
// For prerelease channels, pin exact version. Caret ranges like ^0.1.0-dev.0
|
|
35
|
+
// resolve to `latest` dist-tag (0.1.0-dev.0) instead of the highest match,
|
|
36
|
+
// causing "export not found" errors when the scaffolding CLI is newer.
|
|
37
|
+
return channel ? version : `^${base}`;
|
|
38
|
+
}
|
|
39
|
+
/** Version range for @powerhousedao/ph-clint{,-dev} deps in scaffolded projects. */
|
|
40
|
+
const PH_CLINT_VERSION = phClintRange(CLI_VERSION);
|
|
10
41
|
const POWERHOUSE_VERSION = '6.0.0-dev.170';
|
|
11
42
|
export function buildCliPackageJson(spec) {
|
|
12
43
|
const { mastra, powerhouse } = spec.features;
|
|
13
|
-
const pkgName = powerhouse
|
|
44
|
+
const pkgName = phAtLeast(powerhouse, 'Reactor')
|
|
14
45
|
? `${getPackageName(spec)}-cli`
|
|
15
46
|
: getPackageName(spec);
|
|
16
47
|
const bin = getBinName(spec);
|
|
@@ -21,14 +52,23 @@ export function buildCliPackageJson(spec) {
|
|
|
21
52
|
if (mastra.enabled) {
|
|
22
53
|
dependencies['@mastra/core'] = '^1.22.0';
|
|
23
54
|
dependencies['@mastra/libsql'] = '^1.7.4';
|
|
55
|
+
dependencies['@mastra/mcp'] = '^1.4.1';
|
|
24
56
|
dependencies['@mastra/memory'] = '^1.13.1';
|
|
25
57
|
}
|
|
26
|
-
if (powerhouse
|
|
27
|
-
|
|
58
|
+
if (phAtLeast(powerhouse, 'Reactor')) {
|
|
59
|
+
const appPkg = getAppPackageName(spec);
|
|
60
|
+
const appDir = getAppDirName(spec);
|
|
61
|
+
dependencies[appPkg] = `file:../${appDir}`;
|
|
28
62
|
dependencies['@powerhousedao/reactor'] = POWERHOUSE_VERSION;
|
|
29
63
|
dependencies['@powerhousedao/reactor-api'] = POWERHOUSE_VERSION;
|
|
30
64
|
dependencies['@powerhousedao/shared'] = POWERHOUSE_VERSION;
|
|
31
65
|
dependencies['document-model'] = POWERHOUSE_VERSION;
|
|
66
|
+
// External reactor packages (non-app) as versioned dependencies.
|
|
67
|
+
for (const pkg of spec.packages) {
|
|
68
|
+
if (pkg.packageName !== appPkg) {
|
|
69
|
+
dependencies[pkg.packageName] = 'latest';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
32
72
|
}
|
|
33
73
|
const scripts = {
|
|
34
74
|
'build:skills': 'tsx scripts/build-skills.ts',
|
|
@@ -43,16 +83,16 @@ export function buildCliPackageJson(spec) {
|
|
|
43
83
|
scripts['mastra:build'] = 'mastra build';
|
|
44
84
|
scripts['mastra:start'] = 'mastra start';
|
|
45
85
|
}
|
|
46
|
-
scripts['publish:npm'] = 'pnpm build && pnpm publish --no-git-checks';
|
|
47
86
|
const pkg = {
|
|
48
87
|
name: pkgName,
|
|
49
88
|
version: spec.version,
|
|
50
|
-
|
|
89
|
+
publishConfig: { access: 'public' },
|
|
51
90
|
type: 'module',
|
|
52
91
|
};
|
|
53
92
|
if (spec.description)
|
|
54
93
|
pkg.description = spec.description;
|
|
55
94
|
pkg.bin = { [bin]: './dist/main.js' };
|
|
95
|
+
pkg.files = ['dist'];
|
|
56
96
|
pkg.scripts = scripts;
|
|
57
97
|
pkg.dependencies = dependencies;
|
|
58
98
|
pkg.devDependencies = {
|
|
@@ -1,5 +1,12 @@
|
|
|
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';
|
|
1
7
|
export function buildCliTs(spec) {
|
|
2
8
|
const { mastra, routine, powerhouse } = spec.features;
|
|
9
|
+
const ph = powerhouse;
|
|
3
10
|
const lines = [];
|
|
4
11
|
lines.push('/**');
|
|
5
12
|
lines.push(' * CLI definition.');
|
|
@@ -8,34 +15,33 @@ export function buildCliTs(spec) {
|
|
|
8
15
|
lines.push(' * markers are rewritten by ph-clint when the project spec changes.');
|
|
9
16
|
lines.push(' * Everything outside the markers is user-editable and preserved.');
|
|
10
17
|
lines.push(' */');
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
const needsRoot = phAtLeast(ph, 'Reactor') || mastra.enabled;
|
|
19
|
+
lines.push('// @clint:begin imports');
|
|
20
|
+
const phClintImports = ['defineCli'];
|
|
21
|
+
if (phAtLeast(ph, 'Reactor'))
|
|
22
|
+
phClintImports.push('buildDefaultReactor');
|
|
23
|
+
if (spec.deployment.serviceAnnouncement)
|
|
24
|
+
phClintImports.push('vetraGraphqlAnnounce');
|
|
25
|
+
lines.push(`import { ${phClintImports.join(', ')} } from '@powerhousedao/ph-clint';`);
|
|
26
|
+
if (needsRoot) {
|
|
27
|
+
lines.push("import path from 'node:path';");
|
|
18
28
|
}
|
|
19
|
-
lines.push(`import { CLI_NAME, CLI_VERSION } from './config.js';`);
|
|
29
|
+
lines.push(`import { CLI_NAME, CLI_VERSION${needsRoot ? ', CLI_ROOT' : ''} } from './config.js';`);
|
|
20
30
|
lines.push(`import { configSchema, secretsSchema } from './framework.js';`);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (powerhouse.enabled) {
|
|
24
|
-
lines.push(`import { documentModels } from '${spec.name}-app';`);
|
|
31
|
+
if (phAtLeast(ph, 'Reactor')) {
|
|
32
|
+
lines.push(`import { documentModels } from '${getAppPackageName(spec)}';`);
|
|
25
33
|
}
|
|
26
34
|
if (mastra.enabled) {
|
|
27
35
|
lines.push(`import { createAgent } from './agents/agent.js';`);
|
|
28
36
|
}
|
|
29
37
|
lines.push('// @clint:end imports');
|
|
30
38
|
lines.push('');
|
|
31
|
-
if (powerhouse.enabled) {
|
|
32
|
-
lines.push(`const __dirname = path.dirname(fileURLToPath(import.meta.url));`);
|
|
33
|
-
lines.push(`const appDir = path.resolve(__dirname, '../../${spec.name}-app');`);
|
|
34
|
-
lines.push('');
|
|
35
|
-
}
|
|
36
39
|
lines.push('export const cli = defineCli({');
|
|
37
40
|
lines.push(' name: CLI_NAME,');
|
|
38
41
|
lines.push(' version: CLI_VERSION,');
|
|
42
|
+
if (phAtLeast(ph, 'Reactor')) {
|
|
43
|
+
lines.push(' root: CLI_ROOT,');
|
|
44
|
+
}
|
|
39
45
|
lines.push(' description: `${CLI_NAME} v${CLI_VERSION}`,');
|
|
40
46
|
lines.push(' configSchema,');
|
|
41
47
|
lines.push(' secretsSchema,');
|
|
@@ -59,8 +65,34 @@ export function buildCliTs(spec) {
|
|
|
59
65
|
lines.push('');
|
|
60
66
|
lines.push(' // @clint:begin prompts');
|
|
61
67
|
lines.push(' prompts: {');
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
if (mastra.enabled) {
|
|
69
|
+
lines.push(" artifacts: [path.join(CLI_ROOT, 'gen', 'skills'), path.join(CLI_ROOT, 'dist', 'gen', 'skills')],");
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
lines.push(' artifacts: [],');
|
|
73
|
+
}
|
|
74
|
+
if (mastra.enabled && mastra.agentId) {
|
|
75
|
+
lines.push(' agents: {');
|
|
76
|
+
lines.push(` '${mastra.agentId}': {`);
|
|
77
|
+
if (mastra.profiles.length > 0) {
|
|
78
|
+
lines.push(` name: '${mastra.profiles[0].id}',`);
|
|
79
|
+
lines.push(' sections: [');
|
|
80
|
+
for (const p of mastra.profiles) {
|
|
81
|
+
lines.push(` '${p.id}.md',`);
|
|
82
|
+
}
|
|
83
|
+
lines.push(' ],');
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
lines.push(" name: 'AgentBase',");
|
|
87
|
+
lines.push(" sections: ['AgentBase.md'],");
|
|
88
|
+
}
|
|
89
|
+
lines.push(' skills: [],');
|
|
90
|
+
lines.push(' },');
|
|
91
|
+
lines.push(' },');
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
lines.push(' agents: {},');
|
|
95
|
+
}
|
|
64
96
|
lines.push(' skills: {},');
|
|
65
97
|
lines.push(' },');
|
|
66
98
|
lines.push(' // @clint:end prompts');
|
|
@@ -69,6 +101,15 @@ export function buildCliTs(spec) {
|
|
|
69
101
|
lines.push(' events: {},');
|
|
70
102
|
lines.push(' // @clint:end events');
|
|
71
103
|
lines.push('');
|
|
104
|
+
lines.push(' // @clint:begin serviceAnnouncement');
|
|
105
|
+
if (spec.deployment.serviceAnnouncement) {
|
|
106
|
+
lines.push(' serviceAnnouncement: {');
|
|
107
|
+
lines.push(' enabled: true,');
|
|
108
|
+
lines.push(' announce: (payload, ctx) => vetraGraphqlAnnounce(payload, ctx),');
|
|
109
|
+
lines.push(' },');
|
|
110
|
+
}
|
|
111
|
+
lines.push(' // @clint:end serviceAnnouncement');
|
|
112
|
+
lines.push('');
|
|
72
113
|
lines.push(' // @clint:begin interactive');
|
|
73
114
|
lines.push(' interactive: {');
|
|
74
115
|
lines.push(` welcome: ({ workdir }) =>`);
|
|
@@ -88,15 +129,15 @@ export function buildCliTs(spec) {
|
|
|
88
129
|
lines.push('});');
|
|
89
130
|
lines.push('');
|
|
90
131
|
lines.push('// @clint:begin reactor');
|
|
91
|
-
if (
|
|
132
|
+
if (phAtLeast(ph, 'Reactor')) {
|
|
92
133
|
lines.push('cli.configureReactor({');
|
|
93
134
|
lines.push(' create: (ctx) =>');
|
|
94
135
|
lines.push(' buildDefaultReactor(ctx, {');
|
|
95
136
|
lines.push(' documentModels,');
|
|
96
137
|
lines.push(` drive: { name: '${spec.name}' },`);
|
|
97
138
|
lines.push(' }),');
|
|
98
|
-
lines.push(` switchboard: { enabled: ${String(
|
|
99
|
-
lines.push(` connect: { enabled: ${String(
|
|
139
|
+
lines.push(` switchboard: { enabled: ${String(phAtLeast(ph, 'Switchboard'))} },`);
|
|
140
|
+
lines.push(` connect: { enabled: ${String(phAtLeast(ph, 'Connect'))} },`);
|
|
100
141
|
lines.push('});');
|
|
101
142
|
}
|
|
102
143
|
lines.push('// @clint:end reactor');
|
|
@@ -1,21 +1,17 @@
|
|
|
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 { getBinName, } from '../../spec/types.js';
|
|
8
1
|
export function buildConfigTs(spec) {
|
|
9
|
-
const
|
|
2
|
+
const hasCustomBin = !!spec.bin;
|
|
10
3
|
const lines = [];
|
|
11
|
-
lines.push(`import
|
|
12
|
-
lines.push(`import { fileURLToPath } from 'node:url';`);
|
|
4
|
+
lines.push(`import { readPackageInfo } from '@powerhousedao/ph-clint';`);
|
|
13
5
|
lines.push('');
|
|
14
|
-
lines.push('
|
|
15
|
-
lines.push(`export const CLI_NAME = '${cliName}';`);
|
|
16
|
-
lines.push(`export const CLI_VERSION = '${spec.version}';`);
|
|
6
|
+
lines.push('const pkg = readPackageInfo(import.meta.url);');
|
|
17
7
|
lines.push('');
|
|
18
|
-
lines.push('
|
|
19
|
-
|
|
8
|
+
lines.push('export const CLI_ROOT = pkg.root;');
|
|
9
|
+
if (hasCustomBin) {
|
|
10
|
+
lines.push(`export const CLI_NAME = '${spec.bin}';`);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
lines.push(`export const CLI_NAME = pkg.name.replace(/-cli$/, '');`);
|
|
14
|
+
}
|
|
15
|
+
lines.push('export const CLI_VERSION = pkg.version;');
|
|
20
16
|
return lines.join('\n') + '\n';
|
|
21
17
|
}
|
|
@@ -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,44 @@
|
|
|
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
|
+
return [
|
|
8
|
+
"import type { AgentProvider, StreamChunk } from '@powerhousedao/ph-clint';",
|
|
9
|
+
'',
|
|
10
|
+
'/**',
|
|
11
|
+
' * Demo agent — deterministic echo responses without an API key.',
|
|
12
|
+
' *',
|
|
13
|
+
' * Echoes user prompts with conversation tracking per thread.',
|
|
14
|
+
' */',
|
|
15
|
+
'export function createDemoAgent(): AgentProvider {',
|
|
16
|
+
' const conversations = new Map<string, string[]>();',
|
|
17
|
+
'',
|
|
18
|
+
' return {',
|
|
19
|
+
` id: '${agentId}',`,
|
|
20
|
+
' async *stream(prompt, opts) {',
|
|
21
|
+
" const threadId = opts?.threadId ?? 'default';",
|
|
22
|
+
' if (!conversations.has(threadId)) {',
|
|
23
|
+
' conversations.set(threadId, []);',
|
|
24
|
+
' }',
|
|
25
|
+
' const history = conversations.get(threadId)!;',
|
|
26
|
+
' history.push(prompt);',
|
|
27
|
+
'',
|
|
28
|
+
' const turnCount = history.length;',
|
|
29
|
+
' if (turnCount > 1) {',
|
|
30
|
+
' yield {',
|
|
31
|
+
" type: 'text-delta',",
|
|
32
|
+
' text: `I understand you\'re continuing our conversation (turn ${turnCount}). `,',
|
|
33
|
+
' } satisfies StreamChunk;',
|
|
34
|
+
' }',
|
|
35
|
+
' yield {',
|
|
36
|
+
" type: 'text-delta',",
|
|
37
|
+
' text: `You said: "${prompt}". I\'m the demo agent — set an API key for real LLM responses.`,',
|
|
38
|
+
' } satisfies StreamChunk;',
|
|
39
|
+
' },',
|
|
40
|
+
' };',
|
|
41
|
+
'}',
|
|
42
|
+
'',
|
|
43
|
+
].join('\n');
|
|
44
|
+
}
|
|
@@ -4,14 +4,13 @@
|
|
|
4
4
|
* `defineRegistry([...] as const)` call that describes which document models
|
|
5
5
|
* are bound into `framework.ts`'s typed factories.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* cycle between the two files.
|
|
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.
|
|
11
10
|
*
|
|
12
11
|
* Emitted only when Powerhouse is enabled — flat-layout impls have no
|
|
13
12
|
* reactor package to import modules from and bind `createTypes` directly in
|
|
14
|
-
* `framework.ts`. When Powerhouse is on but no
|
|
13
|
+
* `framework.ts`. When Powerhouse is on but no document types are declared,
|
|
15
14
|
* we still emit this file with an empty `defineRegistry([])` so impl code's
|
|
16
15
|
* `import { registry } from './framework.gen.js'` keeps resolving across
|
|
17
16
|
* regens.
|