@powerhousedao/ph-clint-cli 0.1.0-dev.23 → 0.1.0-dev.24
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 +22 -3
- package/dist/codegen/builders/agent-ts.js +6 -6
- package/dist/codegen/builders/cli-package-json.js +1 -0
- package/dist/codegen/builders/cli-ts.js +25 -9
- 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-ts.js +11 -6
- package/dist/codegen/builders/index.d.ts +2 -1
- package/dist/codegen/builders/index.js +8 -3
- package/dist/codegen/builders/mastra-index-ts.d.ts +2 -2
- package/dist/codegen/builders/mastra-index-ts.js +36 -14
- package/dist/gen/agent-profiles/PhClintDevAgent.md +13 -0
- 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/package.json +5 -4
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* rewritten by ph-clint-cli's generator when the project spec changes.
|
|
7
7
|
* Everything outside the markers is user-editable and preserved.
|
|
8
8
|
*/
|
|
9
|
+
import path from 'node:path';
|
|
9
10
|
import { defineCli, buildDefaultReactor } from '@powerhousedao/ph-clint';
|
|
11
|
+
import { z } from 'zod';
|
|
10
12
|
import { CLI_NAME, CLI_VERSION, CLI_ROOT } from './config.js';
|
|
11
13
|
import { configSchema, secretsSchema } from './framework.js';
|
|
12
14
|
// @clint:begin imports
|
|
@@ -39,9 +41,26 @@ export const cli = defineCli({
|
|
|
39
41
|
// @clint:end triggers
|
|
40
42
|
// @clint:begin prompts
|
|
41
43
|
prompts: {
|
|
42
|
-
artifacts: [],
|
|
43
|
-
agents: {
|
|
44
|
-
|
|
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
|
+
},
|
|
45
64
|
},
|
|
46
65
|
// @clint:end prompts
|
|
47
66
|
// @clint:begin events
|
|
@@ -51,9 +51,9 @@ function buildRealAgent(spec) {
|
|
|
51
51
|
const agentName = mastra.agentName;
|
|
52
52
|
const defaultModel = mastra.models.find(m => m.isDefault) ?? mastra.models[0];
|
|
53
53
|
const modelId = defaultModel?.id ?? 'anthropic/claude-sonnet-4-5';
|
|
54
|
-
const [provider] = modelId.split(
|
|
54
|
+
const [provider] = modelId.split(/[:/]/);
|
|
55
55
|
const { pkg, fn } = providerImport(provider);
|
|
56
|
-
const
|
|
56
|
+
const apiKeyField = `${provider}ApiKey`;
|
|
57
57
|
const lines = [];
|
|
58
58
|
lines.push("import { Agent } from '@mastra/core/agent';");
|
|
59
59
|
lines.push("import { MCPClient } from '@mastra/mcp';");
|
|
@@ -72,7 +72,7 @@ function buildRealAgent(spec) {
|
|
|
72
72
|
lines.push(' * agent as a ph-clint AgentProvider.');
|
|
73
73
|
lines.push(' */');
|
|
74
74
|
lines.push('export async function createAgent(ctx: AgentSetupContext<Config>): Promise<AgentProvider> {');
|
|
75
|
-
lines.push(` if (!ctx.config
|
|
75
|
+
lines.push(` if (!ctx.config.${apiKeyField}) return createDemoAgent();`);
|
|
76
76
|
lines.push('');
|
|
77
77
|
lines.push(' const m = createMastraHelpers(ctx);');
|
|
78
78
|
lines.push('');
|
|
@@ -80,9 +80,9 @@ function buildRealAgent(spec) {
|
|
|
80
80
|
lines.push(` id: '${agentId}',`);
|
|
81
81
|
lines.push(` name: '${agentName}',`);
|
|
82
82
|
lines.push(` instructions: m.getAgentInstructions('${agentId}'),`);
|
|
83
|
-
lines.push(
|
|
84
|
-
lines.push(
|
|
85
|
-
lines.push(
|
|
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
86
|
lines.push(' tools: async () => {');
|
|
87
87
|
lines.push(" ctx.context.log?.debug('[agent] tools callback invoked');");
|
|
88
88
|
lines.push(' const tools = await m.getTools({ MCPClient });');
|
|
@@ -52,6 +52,7 @@ export function buildCliPackageJson(spec) {
|
|
|
52
52
|
if (mastra.enabled) {
|
|
53
53
|
dependencies['@mastra/core'] = '^1.22.0';
|
|
54
54
|
dependencies['@mastra/libsql'] = '^1.7.4';
|
|
55
|
+
dependencies['@mastra/mcp'] = '^1.4.1';
|
|
55
56
|
dependencies['@mastra/memory'] = '^1.13.1';
|
|
56
57
|
}
|
|
57
58
|
if (phAtLeast(powerhouse, 'Reactor')) {
|
|
@@ -15,16 +15,19 @@ export function buildCliTs(spec) {
|
|
|
15
15
|
lines.push(' * markers are rewritten by ph-clint when the project spec changes.');
|
|
16
16
|
lines.push(' * Everything outside the markers is user-editable and preserved.');
|
|
17
17
|
lines.push(' */');
|
|
18
|
+
const needsRoot = phAtLeast(ph, 'Reactor') || mastra.enabled;
|
|
19
|
+
lines.push('// @clint:begin imports');
|
|
18
20
|
if (phAtLeast(ph, 'Reactor')) {
|
|
19
21
|
lines.push(`import { defineCli, buildDefaultReactor } from '@powerhousedao/ph-clint';`);
|
|
20
22
|
}
|
|
21
23
|
else {
|
|
22
24
|
lines.push(`import { defineCli } from '@powerhousedao/ph-clint';`);
|
|
23
25
|
}
|
|
24
|
-
|
|
26
|
+
if (needsRoot) {
|
|
27
|
+
lines.push("import path from 'node:path';");
|
|
28
|
+
}
|
|
29
|
+
lines.push(`import { CLI_NAME, CLI_VERSION${needsRoot ? ', CLI_ROOT' : ''} } from './config.js';`);
|
|
25
30
|
lines.push(`import { configSchema, secretsSchema } from './framework.js';`);
|
|
26
|
-
lines.push('');
|
|
27
|
-
lines.push('// @clint:begin imports');
|
|
28
31
|
if (phAtLeast(ph, 'Reactor')) {
|
|
29
32
|
lines.push(`import { documentModels } from '${getAppPackageName(spec)}';`);
|
|
30
33
|
}
|
|
@@ -62,15 +65,28 @@ export function buildCliTs(spec) {
|
|
|
62
65
|
lines.push('');
|
|
63
66
|
lines.push(' // @clint:begin prompts');
|
|
64
67
|
lines.push(' prompts: {');
|
|
65
|
-
|
|
66
|
-
|
|
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) {
|
|
67
75
|
lines.push(' agents: {');
|
|
68
76
|
lines.push(` '${mastra.agentId}': {`);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
lines.push(
|
|
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'],");
|
|
72
88
|
}
|
|
73
|
-
lines.push(' ],');
|
|
89
|
+
lines.push(' skills: [],');
|
|
74
90
|
lines.push(' },');
|
|
75
91
|
lines.push(' },');
|
|
76
92
|
}
|
|
@@ -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
|
+
}
|
|
@@ -42,25 +42,30 @@ export function buildFrameworkTs(spec) {
|
|
|
42
42
|
}
|
|
43
43
|
lines.push('');
|
|
44
44
|
lines.push('export const configSchema = z.object({');
|
|
45
|
+
lines.push(' // @clint:begin framework-config');
|
|
45
46
|
if (mastra.enabled) {
|
|
46
47
|
const defaultModel = mastra.models.find(m => m.isDefault)?.id ?? 'anthropic/claude-sonnet-4-5';
|
|
47
|
-
lines.push(` model: z.string().default('${defaultModel}').describe('LLM model to use'),`);
|
|
48
|
+
lines.push(` model: z.string().default('${defaultModel}').describe('LLM model to use'),`, ` agentLogging: z.boolean().default(false).describe('Enable agent conversation logging'),`);
|
|
48
49
|
}
|
|
49
|
-
//
|
|
50
|
-
// Override via switchboard.port / connect.port in configureReactor() if required.
|
|
51
|
-
lines.push(' // Add your own config fields here — this file survives regens.');
|
|
50
|
+
lines.push(' // @clint:end framework-config');
|
|
52
51
|
lines.push('});');
|
|
53
52
|
lines.push('');
|
|
54
53
|
lines.push('export const secretsSchema = z.object({');
|
|
54
|
+
lines.push(' // @clint:begin framework-secrets');
|
|
55
55
|
if (mastra.enabled) {
|
|
56
|
-
|
|
56
|
+
const providers = [...new Set(mastra.models.map(m => m.id.split(/[:/]/)[0]))];
|
|
57
|
+
for (const provider of providers) {
|
|
58
|
+
const field = `${provider}ApiKey`;
|
|
59
|
+
lines.push(` ${field}: z.string().optional().describe('${provider} API key'),`);
|
|
60
|
+
}
|
|
57
61
|
}
|
|
62
|
+
lines.push(' // @clint:end framework-secrets');
|
|
58
63
|
lines.push('});');
|
|
59
64
|
lines.push('');
|
|
60
65
|
lines.push('export type Config = z.infer<typeof configSchema> &');
|
|
61
66
|
lines.push(' z.infer<typeof secretsSchema>;');
|
|
62
67
|
lines.push('');
|
|
63
|
-
lines.push('const fullConfigSchema = configSchema.
|
|
68
|
+
lines.push('const fullConfigSchema = configSchema.extend(secretsSchema.shape);');
|
|
64
69
|
lines.push('');
|
|
65
70
|
if (hasGen) {
|
|
66
71
|
lines.push('export const {');
|
|
@@ -17,6 +17,7 @@ import { buildMastraIndexTs } from './mastra-index-ts.js';
|
|
|
17
17
|
import { buildBuildSkillsScript } from './build-skills-ts.js';
|
|
18
18
|
import { buildAgentBaseMd } from './agent-base-md.js';
|
|
19
19
|
import { buildAgentTs } from './agent-ts.js';
|
|
20
|
+
import { buildDemoAgentTs } from './demo-agent-ts.js';
|
|
20
21
|
import { buildFrameworkGenTs } from './framework-gen-ts.js';
|
|
21
22
|
import { buildFrameworkTs } from './framework-ts.js';
|
|
22
23
|
import { type ClintProjectSpec } from '../../spec/types.js';
|
|
@@ -42,7 +43,7 @@ export interface FileBuilder {
|
|
|
42
43
|
*/
|
|
43
44
|
export declare function getProfileFileBuilders(spec: ClintProjectSpec): FileBuilder[];
|
|
44
45
|
export declare const CLI_FILE_BUILDERS: FileBuilder[];
|
|
45
|
-
export { buildCliPackageJson, buildCliTs, buildConfigTs, buildMainTs, buildTsconfigJson, buildJestConfigJs, buildEslintConfigJs, buildGitignore, buildMastraIndexTs, buildBuildSkillsScript, buildAgentBaseMd, buildAgentTs, buildFrameworkGenTs, buildFrameworkTs, };
|
|
46
|
+
export { buildCliPackageJson, buildCliTs, buildConfigTs, buildMainTs, buildTsconfigJson, buildJestConfigJs, buildEslintConfigJs, buildGitignore, buildMastraIndexTs, buildBuildSkillsScript, buildAgentBaseMd, buildAgentTs, buildDemoAgentTs, buildFrameworkGenTs, buildFrameworkTs, };
|
|
46
47
|
export { buildRootPackageJson } from './root-package-json.js';
|
|
47
48
|
export { buildPublishConfigTs } from './publish-config-ts.js';
|
|
48
49
|
export { buildReadme } from './readme-md.js';
|
|
@@ -17,6 +17,7 @@ import { buildMastraIndexTs } from './mastra-index-ts.js';
|
|
|
17
17
|
import { buildBuildSkillsScript } from './build-skills-ts.js';
|
|
18
18
|
import { buildAgentBaseMd } from './agent-base-md.js';
|
|
19
19
|
import { buildAgentTs } from './agent-ts.js';
|
|
20
|
+
import { buildDemoAgentTs } from './demo-agent-ts.js';
|
|
20
21
|
import { buildFrameworkGenTs } from './framework-gen-ts.js';
|
|
21
22
|
import { buildFrameworkTs } from './framework-ts.js';
|
|
22
23
|
/**
|
|
@@ -41,8 +42,8 @@ export const CLI_FILE_BUILDERS = [
|
|
|
41
42
|
{ relativePath: 'src/main.ts', build: () => buildMainTs() },
|
|
42
43
|
{ relativePath: 'src/cli.ts', build: buildCliTs },
|
|
43
44
|
{ relativePath: 'src/config.ts', build: buildConfigTs },
|
|
44
|
-
// User-owned
|
|
45
|
-
{ relativePath: 'src/framework.ts', build: buildFrameworkTs
|
|
45
|
+
// User-owned outside markers; generated config/secrets inside markers.
|
|
46
|
+
{ relativePath: 'src/framework.ts', build: buildFrameworkTs },
|
|
46
47
|
// Machine-owned; regenerated on every run. Null when no document types.
|
|
47
48
|
{ relativePath: 'src/framework.gen.ts', build: buildFrameworkGenTs },
|
|
48
49
|
{ relativePath: 'src/mastra/index.ts', build: buildMastraIndexTs },
|
|
@@ -55,6 +56,10 @@ export const CLI_FILE_BUILDERS = [
|
|
|
55
56
|
relativePath: 'src/agents/agent.ts',
|
|
56
57
|
build: (spec) => (spec.features.mastra.enabled ? buildAgentTs(spec) : null),
|
|
57
58
|
},
|
|
59
|
+
{
|
|
60
|
+
relativePath: 'src/agents/demo-agent.ts',
|
|
61
|
+
build: buildDemoAgentTs,
|
|
62
|
+
},
|
|
58
63
|
// Gitkeep placeholders so directories are tracked in git when otherwise empty.
|
|
59
64
|
{ relativePath: 'src/commands/.gitkeep', build: () => '' },
|
|
60
65
|
{ relativePath: 'src/services/.gitkeep', build: () => '' },
|
|
@@ -70,7 +75,7 @@ export const CLI_FILE_BUILDERS = [
|
|
|
70
75
|
{ relativePath: 'prompts/skills-ext/.gitkeep', build: () => '' },
|
|
71
76
|
{ relativePath: 'tests/.gitkeep', build: () => '' },
|
|
72
77
|
];
|
|
73
|
-
export { buildCliPackageJson, buildCliTs, buildConfigTs, buildMainTs, buildTsconfigJson, buildJestConfigJs, buildEslintConfigJs, buildGitignore, buildMastraIndexTs, buildBuildSkillsScript, buildAgentBaseMd, buildAgentTs, buildFrameworkGenTs, buildFrameworkTs, };
|
|
78
|
+
export { buildCliPackageJson, buildCliTs, buildConfigTs, buildMainTs, buildTsconfigJson, buildJestConfigJs, buildEslintConfigJs, buildGitignore, buildMastraIndexTs, buildBuildSkillsScript, buildAgentBaseMd, buildAgentTs, buildDemoAgentTs, buildFrameworkGenTs, buildFrameworkTs, };
|
|
74
79
|
export { buildRootPackageJson } from './root-package-json.js';
|
|
75
80
|
export { buildPublishConfigTs } from './publish-config-ts.js';
|
|
76
81
|
export { buildReadme } from './readme-md.js';
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* When Mastra is off, emit a no-op placeholder so the directory still exists
|
|
5
5
|
* and `mastra dev` fails predictably rather than importing partial code.
|
|
6
6
|
*
|
|
7
|
-
* When Mastra is on with full agent config,
|
|
8
|
-
*
|
|
7
|
+
* When Mastra is on with full agent config, bootstrap the CLI and re-export
|
|
8
|
+
* the configured Mastra Agent via `cli.bootstrap()`.
|
|
9
9
|
*/
|
|
10
10
|
import { type ClintProjectSpec } from '../../spec/types.js';
|
|
11
11
|
export declare function buildMastraIndexTs(spec: ClintProjectSpec): string;
|
|
@@ -1,48 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive the `{PROVIDER}_API_KEY` env var name from a provider prefix
|
|
3
|
+
* (e.g. `anthropic` → `ANTHROPIC_API_KEY`).
|
|
4
|
+
*/
|
|
5
|
+
function getApiKeyEnvVar(provider) {
|
|
6
|
+
return `${provider.toUpperCase()}_API_KEY`;
|
|
7
|
+
}
|
|
1
8
|
export function buildMastraIndexTs(spec) {
|
|
2
9
|
const { mastra } = spec.features;
|
|
3
10
|
if (!mastra.enabled) {
|
|
4
11
|
return [
|
|
12
|
+
'// @clint:begin mastra-index',
|
|
5
13
|
'/**',
|
|
6
14
|
' * Mastra Studio entry point — placeholder. Enable the `mastra` feature to',
|
|
7
15
|
' * populate this file. Until then `mastra:*` scripts are effectively no-ops.',
|
|
8
16
|
' */',
|
|
9
|
-
'// @clint:begin mastra-index',
|
|
10
17
|
'export {};',
|
|
11
18
|
'// @clint:end mastra-index',
|
|
12
19
|
'',
|
|
13
20
|
].join('\n');
|
|
14
21
|
}
|
|
15
|
-
// Full agent config available — emit
|
|
22
|
+
// Full agent config available — emit bootstrap-based Mastra instance
|
|
16
23
|
if (mastra.agentId && mastra.models.length > 0) {
|
|
17
|
-
const
|
|
18
|
-
|
|
24
|
+
const providers = [...new Set(mastra.models.map(m => m.id.split(/[:/]/)[0]))];
|
|
25
|
+
const lines = [
|
|
26
|
+
'// @clint:begin mastra-index',
|
|
19
27
|
'/**',
|
|
20
28
|
' * Mastra Studio entry point for `mastra dev` / `mastra build` / `mastra start`.',
|
|
21
29
|
' *',
|
|
22
|
-
' *
|
|
30
|
+
' * Bootstraps the CLI to get the configured agent, then exports a Mastra',
|
|
31
|
+
' * instance for Studio integration.',
|
|
23
32
|
' */',
|
|
24
33
|
"import { Mastra } from '@mastra/core/mastra';",
|
|
25
|
-
"import { Agent } from '@mastra/core/agent';",
|
|
34
|
+
"import type { Agent } from '@mastra/core/agent';",
|
|
35
|
+
"import path from 'node:path';",
|
|
36
|
+
"import { cli } from '../cli.js';",
|
|
37
|
+
"import { CLI_ROOT } from '../config.js';",
|
|
26
38
|
'',
|
|
27
|
-
|
|
28
|
-
|
|
39
|
+
"// Under `mastra dev`, CLI_ROOT points to .mastra/ (bundler output).",
|
|
40
|
+
'// The actual project root is its parent.',
|
|
41
|
+
"const projectRoot = path.basename(CLI_ROOT) === '.mastra'",
|
|
42
|
+
' ? path.dirname(CLI_ROOT)',
|
|
43
|
+
' : CLI_ROOT;',
|
|
29
44
|
'',
|
|
30
|
-
'
|
|
31
|
-
` agents: { '${agentId}': agent },`,
|
|
32
|
-
'});',
|
|
33
|
-
'// @clint:end mastra-index',
|
|
45
|
+
'const rt = await cli.bootstrap({ workdir: projectRoot });',
|
|
34
46
|
'',
|
|
35
|
-
]
|
|
47
|
+
];
|
|
48
|
+
// API key env bridge for Studio
|
|
49
|
+
lines.push(`// Workaround: Mastra Studio checks process.env for API keys directly.`, `// Bridge the ph-clint resolved keys so Studio's provider detection works.`);
|
|
50
|
+
for (const provider of providers) {
|
|
51
|
+
const field = `${provider}ApiKey`;
|
|
52
|
+
const envVar = getApiKeyEnvVar(provider);
|
|
53
|
+
lines.push(`{`, ` const key = rt.config.${field} as string | undefined;`, ` if (key && !process.env.${envVar}) process.env.${envVar} = key;`, `}`);
|
|
54
|
+
}
|
|
55
|
+
lines.push('');
|
|
56
|
+
lines.push('const mastraAgent = await rt.mastraAgent as Agent | undefined;', '', 'export const mastra = new Mastra({', ' agents: mastraAgent ? { [mastraAgent.id]: mastraAgent } : {},', '});', '// @clint:end mastra-index', '');
|
|
57
|
+
return lines.join('\n');
|
|
36
58
|
}
|
|
37
59
|
// Mastra enabled but no full agent config yet — placeholder
|
|
38
60
|
return [
|
|
61
|
+
'// @clint:begin mastra-index',
|
|
39
62
|
'/**',
|
|
40
63
|
' * Mastra Studio entry point for `mastra dev` / `mastra build` / `mastra start`.',
|
|
41
64
|
' *',
|
|
42
65
|
" * Re-export a configured `@mastra/core` Mastra instance from here once you",
|
|
43
66
|
" * replace the demo createAgent shim with a real Mastra Agent.",
|
|
44
67
|
' */',
|
|
45
|
-
'// @clint:begin mastra-index',
|
|
46
68
|
'export {};',
|
|
47
69
|
'// @clint:end mastra-index',
|
|
48
70
|
'',
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Agent Base System Prompt
|
|
2
|
+
|
|
3
|
+
You are PhClintDevAgent, an agent available through the CLI.
|
|
4
|
+
|
|
5
|
+
## Capabilities
|
|
6
|
+
|
|
7
|
+
This base profile is a minimal placeholder. Extend it with project-specific
|
|
8
|
+
context, workflows, and domain knowledge. Additional sections listed in the
|
|
9
|
+
agent's `sections` array are concatenated after this file at build time.
|
|
10
|
+
|
|
11
|
+
See `examples/05-ph-rupert/prompts/agent-profiles/AgentBase.md` for a more
|
|
12
|
+
complete example covering Powerhouse document system fundamentals,
|
|
13
|
+
collaboration documents (inbox, WBS), and task management guidelines.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
## API Reference: CLI Setup
|
|
2
|
+
|
|
3
|
+
### `defineCli<TSchema, TSecrets>(options): Cli`
|
|
4
|
+
|
|
5
|
+
Factory function that creates a CLI from a declarative options object. Two generic type parameters:
|
|
6
|
+
|
|
7
|
+
- `TSchema extends z.ZodType` — config schema type (defaults to `Record<string, unknown>`)
|
|
8
|
+
- `TSecrets extends z.ZodType` — secrets schema type (defaults to `Record<string, unknown>`)
|
|
9
|
+
|
|
10
|
+
### `CliOptions<TSchema, TSecrets>` Interface
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
interface CliOptions<TSchema, TSecrets> {
|
|
14
|
+
name: string; // CLI name (kebab-case, used for config files and env var prefix)
|
|
15
|
+
version: string; // Semantic version (shown in --version)
|
|
16
|
+
root?: string; // Absolute path to package root (resolves sibling packages)
|
|
17
|
+
description: Resolvable<string, Config>; // Static string or function of ({ config, workdir })
|
|
18
|
+
commands: Command<any, any, any>[]; // Array of command definitions
|
|
19
|
+
configSchema?: TSchema; // Zod schema for user-facing config
|
|
20
|
+
secretsSchema?: TSecrets; // Zod schema for sensitive config (API keys, tokens)
|
|
21
|
+
interactive?: InteractiveConfig<Config>; // REPL configuration
|
|
22
|
+
triggers?: Trigger<any, any, any>[]; // Routine loop triggers
|
|
23
|
+
routine?: RoutineConfig; // Routine loop timing & project scanner
|
|
24
|
+
services?: ServiceDefinition<Config>[]; // Background service definitions
|
|
25
|
+
events?: Record<string, (data: any, log: Logger) => void>; // Event handlers
|
|
26
|
+
workdir?: string; // Implementation-level workdir override (hides --workdir flag)
|
|
27
|
+
configDefaults?: Record<string, unknown>; // Layer 5 config defaults
|
|
28
|
+
prompts?: PromptsConfig; // Agent skills & profiles
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### `InteractiveConfig<TConfig>` Interface
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
interface InteractiveConfig<TConfig> {
|
|
36
|
+
welcome: Resolvable<string, TConfig>; // Welcome message (static or dynamic)
|
|
37
|
+
outputWindow?: number; // Trailing output lines in REPL (default: 6)
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### `Resolvable<T, TConfig>` Type
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
type Resolvable<T, TConfig> = T | ((ctx: { workdir: string; config: TConfig }) => T);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Allows static values OR dynamic computation based on resolved workdir and config.
|
|
48
|
+
|
|
49
|
+
### `Cli` Object Interface
|
|
50
|
+
|
|
51
|
+
Methods available on the object returned by `defineCli()`:
|
|
52
|
+
|
|
53
|
+
| Method | Signature | Description |
|
|
54
|
+
|--------|-----------|-------------|
|
|
55
|
+
| `run` | `(argv: string[], options?: RunOptions) => Promise<void>` | Main entry point — parse args, dispatch command or start REPL |
|
|
56
|
+
| `bootstrap` | `(opts?: BootstrapOptions) => Promise<BootstrapResult>` | Initialize runtime without dispatch — for programmatic access |
|
|
57
|
+
| `execute` | `(commandId, args, context?) => Promise<unknown>` | Execute a command directly (programmatic use) |
|
|
58
|
+
| `parseArgs` | `(commandId, argv) => Record<string, unknown>` | Parse CLI argv for a specific command |
|
|
59
|
+
| `getCommand` | `(id: string) => Command \| undefined` | Look up a registered command |
|
|
60
|
+
| `listCommands` | `() => Command[]` | List all registered commands |
|
|
61
|
+
| `generateHelp` | `() => string` | Generate CLI help text |
|
|
62
|
+
| `generateCommandHelp` | `(commandId: string) => string` | Generate help for a specific command |
|
|
63
|
+
| `generateCompletion` | `(shell: string) => string` | Generate shell completion script (bash/zsh/fish) |
|
|
64
|
+
| `configEnvVars` | `() => ConfigEnvVar[]` | List config env var mappings |
|
|
65
|
+
| `getMetadata` | `() => CliMetadata` | JSON-serializable CLI metadata |
|
|
66
|
+
| `configureAgent` | `(loader: AgentLoader<any>) => void` | Set the agent factory (lazy-loaded) |
|
|
67
|
+
| `configureReactor` | `(config: ReactorConfiguration) => void` | Set the reactor configuration (lazy-loaded) |
|
|
68
|
+
|
|
69
|
+
Properties:
|
|
70
|
+
|
|
71
|
+
| Property | Type | Description |
|
|
72
|
+
|----------|------|-------------|
|
|
73
|
+
| `name` | `string` | CLI name |
|
|
74
|
+
| `version` | `string` | CLI version |
|
|
75
|
+
| `description` | `string` | CLI description |
|
|
76
|
+
| `hasAgent` | `boolean` | True when `configureAgent()` has been called |
|
|
77
|
+
| `hasReactor` | `boolean` | True when `configureReactor()` has been called |
|
|
78
|
+
|
|
79
|
+
### `RunOptions` Interface
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
interface RunOptions {
|
|
83
|
+
exit?: (code: number) => void; // Override process.exit (for testing)
|
|
84
|
+
stdout?: (message: string) => void; // Capture stdout
|
|
85
|
+
stderr?: (message: string) => void; // Capture stderr
|
|
86
|
+
interactiveInput?: AsyncIterable<string>; // Headless REPL input (for testing)
|
|
87
|
+
resume?: string; // Resume agent conversation by thread ID
|
|
88
|
+
workdir?: string; // Override workdir (for testing)
|
|
89
|
+
configFile?: string; // --config flag value
|
|
90
|
+
logLevel?: LogLevel; // Override log verbosity (default: 'info')
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `BootstrapOptions` & `BootstrapResult`
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
interface BootstrapOptions {
|
|
98
|
+
workdir?: string; // Explicit workdir (skips flag/cwd logic)
|
|
99
|
+
configFile?: string; // Config file override
|
|
100
|
+
logLevel?: LogLevel; // Log level (default: 'info')
|
|
101
|
+
stdout?: (text: string) => void;
|
|
102
|
+
stderr?: (text: string) => void;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface BootstrapResult {
|
|
106
|
+
workdir: string;
|
|
107
|
+
config: Record<string, unknown>;
|
|
108
|
+
context: CommandContext;
|
|
109
|
+
getAgent(): Promise<AgentProvider | undefined>;
|
|
110
|
+
get mastraAgent(): Promise<unknown | undefined>;
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Built-in Commands (Auto-Injected)
|
|
115
|
+
|
|
116
|
+
| Command ID | Condition | Purpose |
|
|
117
|
+
|-----------|-----------|---------|
|
|
118
|
+
| `cli-docs` | Always | Show CLI help (also usable as agent tool) |
|
|
119
|
+
| `config` | When `configSchema` provided | View/modify configuration settings |
|
|
120
|
+
| `{service-id}-start` | Per service definition | Start a background service |
|
|
121
|
+
| `{service-id}-stop` | Per service definition | Stop a running service |
|
|
122
|
+
| `{service-id}-restart` | Per service definition | Restart a service |
|
|
123
|
+
| `{service-id}-ps` | Per service definition | Show service status |
|
|
124
|
+
| `{service-id}-logs` | Per service definition | Tail service logs |
|
|
125
|
+
| `{service-id}-manage` | Per service definition | Interactive management (REPL only) |
|
|
126
|
+
| `{service-id}-ls` | Per service + projectScanner | List discovered projects |
|
|
127
|
+
|
|
128
|
+
### `readPackageInfo(importMetaUrl)`
|
|
129
|
+
|
|
130
|
+
Utility to read name and version from the nearest `package.json`:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { readPackageInfo } from '@powerhousedao/ph-clint';
|
|
134
|
+
const { name, version } = readPackageInfo(import.meta.url);
|
|
135
|
+
```
|