@powerhousedao/ph-clint-cli 0.1.0-dev.8 → 0.1.0-dev.80
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 +52 -10
- package/dist/codegen/actions.d.ts +46 -0
- package/dist/codegen/actions.js +424 -0
- package/dist/codegen/builders/agent-ts.d.ts +4 -4
- package/dist/codegen/builders/agent-ts.js +92 -2
- package/dist/codegen/builders/app-index-ts.d.ts +3 -10
- package/dist/codegen/builders/app-index-ts.js +30 -20
- package/dist/codegen/builders/cli-package-json.js +46 -14
- package/dist/codegen/builders/cli-ts.js +87 -49
- package/dist/codegen/builders/config-ts.d.ts +1 -1
- package/dist/codegen/builders/config-ts.js +2 -8
- package/dist/codegen/builders/demo-agent-ts.d.ts +8 -0
- package/dist/codegen/builders/demo-agent-ts.js +50 -0
- package/dist/codegen/builders/eslint-config-js.d.ts +1 -1
- package/dist/codegen/builders/eslint-config-js.js +7 -4
- package/dist/codegen/builders/framework-gen-ts.d.ts +11 -6
- package/dist/codegen/builders/framework-gen-ts.js +73 -21
- package/dist/codegen/builders/framework-ts.js +33 -7
- package/dist/codegen/builders/index.d.ts +10 -2
- package/dist/codegen/builders/index.js +30 -6
- package/dist/codegen/builders/manifest-json.d.ts +6 -0
- package/dist/codegen/builders/manifest-json.js +31 -0
- package/dist/codegen/builders/mastra-index-ts.d.ts +3 -0
- package/dist/codegen/builders/mastra-index-ts.js +47 -5
- package/dist/codegen/builders/publish-config-js.d.ts +8 -0
- package/dist/codegen/builders/publish-config-js.js +33 -0
- package/dist/codegen/builders/readme-md.js +7 -6
- package/dist/codegen/builders/root-package-json.js +11 -12
- package/dist/codegen/builders/smoke-test-ts.d.ts +2 -0
- package/dist/codegen/builders/smoke-test-ts.js +15 -0
- package/dist/codegen/exec.d.ts +0 -18
- package/dist/codegen/exec.js +0 -27
- package/dist/codegen/generated.d.ts +17 -0
- package/dist/codegen/generated.js +49 -0
- package/dist/codegen/index.d.ts +8 -36
- package/dist/codegen/index.js +6 -293
- package/dist/codegen/scaffold.d.ts +41 -3
- package/dist/codegen/scaffold.js +106 -16
- package/dist/commands/clint-project-build.d.ts +77 -1
- package/dist/commands/clint-project-build.js +11 -28
- package/dist/commands/clint-project-init.d.ts +128 -10
- package/dist/commands/clint-project-init.js +72 -47
- package/dist/commands/clint-project-publish.d.ts +78 -1
- package/dist/commands/clint-project-publish.js +6 -4
- package/dist/commands/clint-project-regen.d.ts +77 -1
- package/dist/commands/clint-project-regen.js +26 -2
- package/dist/commands/clint-skills-sync.d.ts +86 -0
- package/dist/commands/clint-skills-sync.js +56 -0
- package/dist/framework.d.ts +322 -60
- package/dist/framework.gen.d.ts +50 -10
- package/dist/framework.js +1 -5
- package/{prompts/agent-profiles/AgentBase.md → dist/gen/agent-profiles/PhClintDevAgent.md} +1 -1
- package/dist/gen/skills/cli-setup/.cli-docs.md +135 -0
- package/dist/gen/skills/cli-setup/SKILL.md +125 -0
- package/dist/gen/skills/cli-setup/references/00.assess-cli-needs.md +53 -0
- package/dist/gen/skills/cli-setup/references/01.define-config-schema.md +78 -0
- package/dist/gen/skills/cli-setup/references/02.wire-cli.md +141 -0
- package/dist/gen/skills/cli-setup/references/03.add-entrypoint.md +128 -0
- package/dist/gen/skills/cli-setup/references/expected-outcome.md +3 -0
- package/dist/gen/skills/command-definition/.cli-docs.md +84 -0
- package/dist/gen/skills/command-definition/SKILL.md +99 -0
- package/dist/gen/skills/command-definition/references/00.assess-requirements.md +58 -0
- package/dist/gen/skills/command-definition/references/01.define-schema.md +72 -0
- package/dist/gen/skills/command-definition/references/02.implement-execute.md +118 -0
- package/dist/gen/skills/command-definition/references/03.add-prompting.md +54 -0
- package/dist/gen/skills/command-definition/references/expected-outcome.md +3 -0
- package/dist/gen/skills/service-definition/.cli-docs.md +214 -0
- package/dist/gen/skills/service-definition/SKILL.md +148 -0
- package/dist/gen/skills/service-definition/references/00.assess-service.md +69 -0
- package/dist/gen/skills/service-definition/references/01.define-service.md +166 -0
- package/dist/gen/skills/service-definition/references/02.add-preflight.md +132 -0
- package/dist/gen/skills/service-definition/references/03.add-project-scanner.md +82 -0
- package/dist/gen/skills/service-definition/references/04.wire-events.md +120 -0
- package/dist/gen/skills/service-definition/references/expected-outcome.md +3 -0
- package/dist/main.js +0 -0
- package/dist/services/clint-project.js +21 -0
- package/dist/skills/sync.d.ts +40 -0
- package/dist/skills/sync.js +119 -0
- package/dist/spec/ensure-document.d.ts +17 -0
- package/dist/spec/ensure-document.js +56 -0
- package/dist/spec/file.d.ts +1 -4
- package/dist/spec/file.js +1 -34
- package/dist/spec/from-document.d.ts +4 -1
- package/dist/spec/from-document.js +4 -16
- package/dist/spec/types.d.ts +1 -62
- package/dist/spec/types.js +1 -112
- package/dist/triggers/publish-trigger.d.ts +81 -0
- package/dist/triggers/publish-trigger.js +137 -0
- package/dist/triggers/spec-change.d.ts +60 -18
- package/dist/triggers/spec-change.js +154 -101
- package/package.json +13 -18
- package/dist/codegen/builders/publish-config-ts.d.ts +0 -6
- package/dist/codegen/builders/publish-config-ts.js +0 -18
- package/dist/commands/init.d.ts +0 -57
- package/dist/commands/init.js +0 -168
- package/dist/commands/regen.d.ts +0 -18
- package/dist/commands/regen.js +0 -68
- package/prompts/skills-ext/.gitkeep +0 -0
- package/prompts/skills-tpl/.gitkeep +0 -0
|
@@ -1,5 +1,20 @@
|
|
|
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 mastra = spec.features.mastra;
|
|
16
|
+
const id = mastra.agentId ?? spec.name;
|
|
17
|
+
const name = mastra.agentName ?? id;
|
|
3
18
|
return [
|
|
4
19
|
"import type { AgentProvider, AgentSetupContext, StreamChunk } from '@powerhousedao/ph-clint';",
|
|
5
20
|
"import type { Config } from '../framework.js';",
|
|
@@ -11,6 +26,7 @@ export function buildAgentTs(spec) {
|
|
|
11
26
|
'function createDemoAgent(): AgentProvider {',
|
|
12
27
|
' return {',
|
|
13
28
|
` id: '${id}',`,
|
|
29
|
+
` name: '${name}',`,
|
|
14
30
|
' async *stream(prompt) {',
|
|
15
31
|
' yield {',
|
|
16
32
|
" type: 'text-delta',",
|
|
@@ -32,3 +48,77 @@ export function buildAgentTs(spec) {
|
|
|
32
48
|
'',
|
|
33
49
|
].join('\n');
|
|
34
50
|
}
|
|
51
|
+
function buildRealAgent(spec) {
|
|
52
|
+
const mastra = spec.features.mastra;
|
|
53
|
+
const agentId = mastra.agentId;
|
|
54
|
+
const agentName = mastra.agentName;
|
|
55
|
+
const defaultModel = mastra.models.find(m => m.isDefault) ?? mastra.models[0];
|
|
56
|
+
const modelId = defaultModel?.id ?? 'anthropic/claude-sonnet-4-5';
|
|
57
|
+
const [provider] = modelId.split(/[:/]/);
|
|
58
|
+
const { pkg, fn } = providerImport(provider);
|
|
59
|
+
const apiKeyField = `${provider}ApiKey`;
|
|
60
|
+
const lines = [];
|
|
61
|
+
lines.push("import { Agent } from '@mastra/core/agent';");
|
|
62
|
+
lines.push("import { MCPClient } from '@mastra/mcp';");
|
|
63
|
+
lines.push("import { createMastraHelpers } from '@powerhousedao/ph-clint/mastra';");
|
|
64
|
+
lines.push("import { createWorkdirStore } from '@powerhousedao/ph-clint';");
|
|
65
|
+
lines.push("import type { AgentSetupContext, AgentProvider } from '@powerhousedao/ph-clint';");
|
|
66
|
+
lines.push("import type { WrapAgentOptions } from '@powerhousedao/ph-clint/mastra';");
|
|
67
|
+
lines.push("import { CLI_NAME } from '../config.js';");
|
|
68
|
+
lines.push("import type { Config } from '../framework.js';");
|
|
69
|
+
lines.push("import { createDemoAgent } from './demo-agent.js';");
|
|
70
|
+
lines.push('');
|
|
71
|
+
lines.push('/**');
|
|
72
|
+
lines.push(' * Agent factory for the CLI.');
|
|
73
|
+
lines.push(' *');
|
|
74
|
+
lines.push(' * Returns a demo agent when no API key is configured, or wraps the full');
|
|
75
|
+
lines.push(' * agent as a ph-clint AgentProvider.');
|
|
76
|
+
lines.push(' */');
|
|
77
|
+
lines.push('export async function createAgent(ctx: AgentSetupContext<Config>): Promise<AgentProvider> {');
|
|
78
|
+
lines.push(` if (!ctx.config.${apiKeyField}) return createDemoAgent();`);
|
|
79
|
+
lines.push('');
|
|
80
|
+
lines.push(' const m = createMastraHelpers(ctx);');
|
|
81
|
+
lines.push('');
|
|
82
|
+
lines.push(' const agent = new Agent({');
|
|
83
|
+
lines.push(` id: '${agentId}',`);
|
|
84
|
+
lines.push(` name: '${agentName}',`);
|
|
85
|
+
lines.push(` instructions: m.getAgentInstructions('${agentId}'),`);
|
|
86
|
+
lines.push(` model: ctx.config.${apiKeyField}`);
|
|
87
|
+
lines.push(` ? { id: ctx.config.model as \`\${string}/\${string}\`, apiKey: ctx.config.${apiKeyField} }`);
|
|
88
|
+
lines.push(` : (ctx.config.model as \`\${string}/\${string}\`),`);
|
|
89
|
+
lines.push(' tools: async () => {');
|
|
90
|
+
lines.push(" ctx.context.log?.debug('[agent] tools callback invoked');");
|
|
91
|
+
lines.push(' const tools = await m.getTools({ MCPClient });');
|
|
92
|
+
lines.push(" ctx.context.log?.debug(`[agent] tools resolved: ${Object.keys(tools).length} tools`);");
|
|
93
|
+
lines.push(' return tools;');
|
|
94
|
+
lines.push(' },');
|
|
95
|
+
lines.push(' workspace: await m.createWorkspace(),');
|
|
96
|
+
lines.push(' memory: await m.createMemory(),');
|
|
97
|
+
lines.push(' });');
|
|
98
|
+
lines.push('');
|
|
99
|
+
lines.push(' const store = createWorkdirStore(ctx.workdir, CLI_NAME);');
|
|
100
|
+
lines.push(' const wrapOpts: WrapAgentOptions = {');
|
|
101
|
+
lines.push(' maxSteps: 80,');
|
|
102
|
+
lines.push(' enableLogging: ctx.config.agentLogging,');
|
|
103
|
+
lines.push(" logDirectory: store.getStoreFolder('logs'),");
|
|
104
|
+
lines.push(' cacheControl: true,');
|
|
105
|
+
if (mastra.agentDescription) {
|
|
106
|
+
lines.push(` description: ${JSON.stringify(mastra.agentDescription)},`);
|
|
107
|
+
}
|
|
108
|
+
if (mastra.agentImage) {
|
|
109
|
+
lines.push(` image: ${JSON.stringify(mastra.agentImage)},`);
|
|
110
|
+
}
|
|
111
|
+
lines.push(' };');
|
|
112
|
+
lines.push(' return m.wrapAgent(agent, wrapOpts);');
|
|
113
|
+
lines.push('}');
|
|
114
|
+
lines.push('');
|
|
115
|
+
return lines.join('\n');
|
|
116
|
+
}
|
|
117
|
+
export function buildAgentTs(spec) {
|
|
118
|
+
const mastra = spec.features.mastra;
|
|
119
|
+
// Generate real agent when we have full config, demo otherwise
|
|
120
|
+
if (mastra.agentId && mastra.models.length > 0) {
|
|
121
|
+
return buildRealAgent(spec);
|
|
122
|
+
}
|
|
123
|
+
return buildDemoAgent(spec);
|
|
124
|
+
}
|
|
@@ -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,31 +3,41 @@
|
|
|
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, isDocTypeGlob, phAtLeast, } from '../../spec/types.js';
|
|
18
11
|
export function buildAppIndexTs(spec) {
|
|
19
|
-
if (!spec.features.powerhouse
|
|
20
|
-
return null;
|
|
21
|
-
if (spec.documentTypes.length === 0)
|
|
12
|
+
if (!phAtLeast(spec.features.powerhouse, 'Reactor'))
|
|
22
13
|
return null;
|
|
23
14
|
const lines = [];
|
|
15
|
+
// Standard Powerhouse reactor-package barrel — matches what `ph init`
|
|
16
|
+
// generates. Required by main.tsx (Connect) and cli.ts imports.
|
|
24
17
|
lines.push('// THIS FILE IS GENERATED BY ph-clint-cli.');
|
|
25
|
-
lines.push(
|
|
26
|
-
lines.push(
|
|
27
|
-
lines.push('');
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
+
}
|
|
31
41
|
}
|
|
32
42
|
return lines.join('\n') + '\n';
|
|
33
43
|
}
|
|
@@ -4,8 +4,9 @@
|
|
|
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';
|
|
7
|
+
import { getAppDirName, getAppPackageName, getBinName, getPackageName, phAtLeast, } from '../../spec/types.js';
|
|
8
8
|
import { CLI_VERSION } from '../../config.js';
|
|
9
|
+
import { getPhVersion } from '../scaffold.js';
|
|
9
10
|
/**
|
|
10
11
|
* Derive a semver range from the running ph-clint-cli version that respects
|
|
11
12
|
* the dev / staging / production channel boundary. This is the version range
|
|
@@ -31,16 +32,24 @@ function phClintRange(version) {
|
|
|
31
32
|
return `^${version}`;
|
|
32
33
|
const base = match[1];
|
|
33
34
|
const channel = match[2]; // "dev", "staging", or undefined
|
|
34
|
-
|
|
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}`;
|
|
35
39
|
}
|
|
36
40
|
/** Version range for @powerhousedao/ph-clint{,-dev} deps in scaffolded projects. */
|
|
37
41
|
const PH_CLINT_VERSION = phClintRange(CLI_VERSION);
|
|
38
|
-
const
|
|
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
|
+
}
|
|
39
50
|
export function buildCliPackageJson(spec) {
|
|
40
51
|
const { mastra, powerhouse } = spec.features;
|
|
41
|
-
const pkgName =
|
|
42
|
-
? `${getPackageName(spec)}-cli`
|
|
43
|
-
: getPackageName(spec);
|
|
52
|
+
const pkgName = getPackageName(spec);
|
|
44
53
|
const bin = getBinName(spec);
|
|
45
54
|
const dependencies = {
|
|
46
55
|
'@powerhousedao/ph-clint': PH_CLINT_VERSION,
|
|
@@ -49,18 +58,32 @@ export function buildCliPackageJson(spec) {
|
|
|
49
58
|
if (mastra.enabled) {
|
|
50
59
|
dependencies['@mastra/core'] = '^1.22.0';
|
|
51
60
|
dependencies['@mastra/libsql'] = '^1.7.4';
|
|
61
|
+
dependencies['@mastra/mcp'] = '^1.4.1';
|
|
52
62
|
dependencies['@mastra/memory'] = '^1.13.1';
|
|
53
63
|
}
|
|
54
|
-
if (powerhouse
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
dependencies[
|
|
58
|
-
dependencies['@powerhousedao/
|
|
59
|
-
dependencies['
|
|
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
|
+
}
|
|
60
82
|
}
|
|
61
83
|
const scripts = {
|
|
62
84
|
'build:skills': 'tsx scripts/build-skills.ts',
|
|
63
|
-
build:
|
|
85
|
+
'build:manifest': 'build-manifest',
|
|
86
|
+
build: 'pnpm build:skills && tsc && pnpm build:manifest',
|
|
64
87
|
dev: 'tsx src/main.ts',
|
|
65
88
|
start: 'node dist/main.js',
|
|
66
89
|
test: "NODE_OPTIONS='--experimental-vm-modules' jest --detectOpenHandles",
|
|
@@ -71,15 +94,23 @@ export function buildCliPackageJson(spec) {
|
|
|
71
94
|
scripts['mastra:build'] = 'mastra build';
|
|
72
95
|
scripts['mastra:start'] = 'mastra start';
|
|
73
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
|
+
}
|
|
74
104
|
const pkg = {
|
|
75
105
|
name: pkgName,
|
|
76
106
|
version: spec.version,
|
|
77
|
-
|
|
107
|
+
publishConfig: { access: 'public' },
|
|
78
108
|
type: 'module',
|
|
79
109
|
};
|
|
80
110
|
if (spec.description)
|
|
81
111
|
pkg.description = spec.description;
|
|
82
112
|
pkg.bin = { [bin]: './dist/main.js' };
|
|
113
|
+
pkg.files = ['dist'];
|
|
83
114
|
pkg.scripts = scripts;
|
|
84
115
|
pkg.dependencies = dependencies;
|
|
85
116
|
pkg.devDependencies = {
|
|
@@ -90,6 +121,7 @@ export function buildCliPackageJson(spec) {
|
|
|
90
121
|
'ts-jest': '^29.4.6',
|
|
91
122
|
tsx: '^4.19.0',
|
|
92
123
|
typescript: '^6.0.2',
|
|
124
|
+
'typescript-eslint': '^8.33.0',
|
|
93
125
|
};
|
|
94
126
|
pkg.engines = { node: '>=22.13.0' };
|
|
95
127
|
return JSON.stringify(pkg, null, 2) + '\n';
|
|
@@ -1,5 +1,17 @@
|
|
|
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
|
+
}
|
|
1
12
|
export function buildCliTs(spec) {
|
|
2
13
|
const { mastra, routine, powerhouse } = spec.features;
|
|
14
|
+
const ph = powerhouse;
|
|
3
15
|
const lines = [];
|
|
4
16
|
lines.push('/**');
|
|
5
17
|
lines.push(' * CLI definition.');
|
|
@@ -8,40 +20,42 @@ export function buildCliTs(spec) {
|
|
|
8
20
|
lines.push(' * markers are rewritten by ph-clint when the project spec changes.');
|
|
9
21
|
lines.push(' * Everything outside the markers is user-editable and preserved.');
|
|
10
22
|
lines.push(' */');
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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';");
|
|
18
32
|
}
|
|
19
|
-
lines.push(`import { CLI_NAME, CLI_VERSION${
|
|
33
|
+
lines.push(`import { CLI_NAME, CLI_VERSION${needsRoot ? ', CLI_ROOT' : ''} } from './config.js';`);
|
|
20
34
|
lines.push(`import { configSchema, secretsSchema } from './framework.js';`);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
+
}
|
|
25
42
|
}
|
|
26
43
|
if (mastra.enabled) {
|
|
27
44
|
lines.push(`import { createAgent } from './agents/agent.js';`);
|
|
28
45
|
}
|
|
46
|
+
if (mastra.enabled && mastra.common?.enableChat) {
|
|
47
|
+
lines.push(`import { chatSessionWatchTrigger } from '@powerhousedao/clint-common/chat';`);
|
|
48
|
+
}
|
|
29
49
|
lines.push('// @clint:end imports');
|
|
30
50
|
lines.push('');
|
|
31
|
-
if (powerhouse.enabled) {
|
|
32
|
-
lines.push(`const appDir = path.resolve(CLI_ROOT, '../${spec.name}-app');`);
|
|
33
|
-
lines.push('');
|
|
34
|
-
if (powerhouse.connect) {
|
|
35
|
-
lines.push('function resolveConnectAssets(dir: string): string | undefined {');
|
|
36
|
-
lines.push(" const assetsDir = path.join(dir, 'dist', 'connect');");
|
|
37
|
-
lines.push(" return existsSync(path.join(assetsDir, 'index.html')) ? assetsDir : undefined;");
|
|
38
|
-
lines.push('}');
|
|
39
|
-
lines.push('');
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
51
|
lines.push('export const cli = defineCli({');
|
|
43
52
|
lines.push(' name: CLI_NAME,');
|
|
44
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');
|
|
45
59
|
lines.push(' description: `${CLI_NAME} v${CLI_VERSION}`,');
|
|
46
60
|
lines.push(' configSchema,');
|
|
47
61
|
lines.push(' secretsSchema,');
|
|
@@ -55,8 +69,8 @@ export function buildCliTs(spec) {
|
|
|
55
69
|
lines.push(' // @clint:end services');
|
|
56
70
|
lines.push('');
|
|
57
71
|
lines.push(' // @clint:begin triggers');
|
|
58
|
-
if (
|
|
59
|
-
lines.push(' triggers: [],');
|
|
72
|
+
if (mastra.enabled && mastra.common?.enableChat) {
|
|
73
|
+
lines.push(' triggers: [chatSessionWatchTrigger],');
|
|
60
74
|
}
|
|
61
75
|
else {
|
|
62
76
|
lines.push(' triggers: [],');
|
|
@@ -65,8 +79,34 @@ export function buildCliTs(spec) {
|
|
|
65
79
|
lines.push('');
|
|
66
80
|
lines.push(' // @clint:begin prompts');
|
|
67
81
|
lines.push(' prompts: {');
|
|
68
|
-
|
|
69
|
-
|
|
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
|
+
}
|
|
70
110
|
lines.push(' skills: {},');
|
|
71
111
|
lines.push(' },');
|
|
72
112
|
lines.push(' // @clint:end prompts');
|
|
@@ -75,29 +115,24 @@ export function buildCliTs(spec) {
|
|
|
75
115
|
lines.push(' events: {},');
|
|
76
116
|
lines.push(' // @clint:end events');
|
|
77
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('');
|
|
78
124
|
lines.push(' // @clint:begin interactive');
|
|
79
125
|
lines.push(' interactive: {');
|
|
80
|
-
|
|
81
|
-
if (powerhouse.enabled && (powerhouse.switchboard || powerhouse.connect)) {
|
|
82
|
-
ctxArgs.push('config');
|
|
83
|
-
}
|
|
84
|
-
ctxArgs.push('workdir');
|
|
85
|
-
lines.push(` welcome: ({ ${ctxArgs.join(', ')} }) =>`);
|
|
126
|
+
lines.push(` welcome: ({ workdir }) =>`);
|
|
86
127
|
lines.push(' [');
|
|
87
128
|
lines.push(' `${CLI_NAME} v${CLI_VERSION}`,');
|
|
88
129
|
lines.push(' `Workdir: ${workdir}`,');
|
|
89
|
-
if (powerhouse.enabled && powerhouse.switchboard) {
|
|
90
|
-
lines.push(' `Switchboard: http://localhost:${config.switchboardPort}`,');
|
|
91
|
-
}
|
|
92
|
-
if (powerhouse.enabled && powerhouse.connect) {
|
|
93
|
-
lines.push(' `Connect: http://localhost:${config.connectPort}`,');
|
|
94
|
-
}
|
|
95
130
|
lines.push(" '',");
|
|
96
131
|
if (mastra.enabled) {
|
|
97
|
-
lines.push(" 'Type a message to talk to the agent, or /
|
|
132
|
+
lines.push(" 'Type a message to talk to the agent, or / for commands.',");
|
|
98
133
|
}
|
|
99
134
|
else {
|
|
100
|
-
lines.push(" 'Type /
|
|
135
|
+
lines.push(" 'Type / for commands or /cli-docs for help.',");
|
|
101
136
|
}
|
|
102
137
|
lines.push(" ].join('\\n'),");
|
|
103
138
|
lines.push(' },');
|
|
@@ -105,20 +140,23 @@ export function buildCliTs(spec) {
|
|
|
105
140
|
lines.push('});');
|
|
106
141
|
lines.push('');
|
|
107
142
|
lines.push('// @clint:begin reactor');
|
|
108
|
-
if (
|
|
143
|
+
if (phAtLeast(ph, 'Reactor')) {
|
|
109
144
|
lines.push('cli.configureReactor({');
|
|
110
145
|
lines.push(' create: (ctx) =>');
|
|
111
146
|
lines.push(' buildDefaultReactor(ctx, {');
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
lines.push(` switchboard: { enabled: ${String(powerhouse.switchboard)} },`);
|
|
116
|
-
if (powerhouse.connect) {
|
|
117
|
-
lines.push(` connect: { enabled: true, workdir: appDir, assetsDir: resolveConnectAssets(appDir) },`);
|
|
147
|
+
const extPkgs = getExternalPackages(spec);
|
|
148
|
+
if (extPkgs.length === 0) {
|
|
149
|
+
lines.push(' documentModels,');
|
|
118
150
|
}
|
|
119
151
|
else {
|
|
120
|
-
|
|
152
|
+
const aliases = extPkgs.map((_, i) => extPkgs.length === 1 ? 'extModels' : `extModels${i}`);
|
|
153
|
+
lines.push(` documentModels: [...documentModels, ${aliases.map(a => `...${a}`).join(', ')}],`);
|
|
121
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'))} },`);
|
|
122
160
|
lines.push('});');
|
|
123
161
|
}
|
|
124
162
|
lines.push('// @clint:end reactor');
|
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
export function buildConfigTs(
|
|
2
|
-
const hasCustomBin = !!spec.bin;
|
|
1
|
+
export function buildConfigTs(_spec) {
|
|
3
2
|
const lines = [];
|
|
4
3
|
lines.push(`import { readPackageInfo } from '@powerhousedao/ph-clint';`);
|
|
5
4
|
lines.push('');
|
|
6
5
|
lines.push('const pkg = readPackageInfo(import.meta.url);');
|
|
7
6
|
lines.push('');
|
|
8
7
|
lines.push('export const CLI_ROOT = pkg.root;');
|
|
9
|
-
|
|
10
|
-
lines.push(`export const CLI_NAME = '${spec.bin}';`);
|
|
11
|
-
}
|
|
12
|
-
else {
|
|
13
|
-
lines.push(`export const CLI_NAME = pkg.name.replace(/-cli$/, '');`);
|
|
14
|
-
}
|
|
8
|
+
lines.push(`export const CLI_NAME = pkg.name.replace(/-cli$/, '');`);
|
|
15
9
|
lines.push('export const CLI_VERSION = pkg.version;');
|
|
16
10
|
return lines.join('\n') + '\n';
|
|
17
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
|
+
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Builds `eslint.config.js` for the CLI —
|
|
2
|
+
* Builds `eslint.config.js` for the CLI — minimal TypeScript-ESLint config.
|
|
3
3
|
*/
|
|
4
4
|
export function buildEslintConfigJs() {
|
|
5
5
|
return [
|
|
6
6
|
'// @clint:begin eslint',
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
'export default
|
|
7
|
+
"import tseslint from 'typescript-eslint';",
|
|
8
|
+
'',
|
|
9
|
+
'export default tseslint.config(',
|
|
10
|
+
' tseslint.configs.recommended,',
|
|
11
|
+
" { ignores: ['dist/', 'gen/', 'coverage/'] },",
|
|
12
|
+
');',
|
|
10
13
|
'// @clint:end eslint',
|
|
11
14
|
'',
|
|
12
15
|
].join('\n');
|