@powerhousedao/ph-clint-cli 0.1.0-dev.51 → 0.1.0-dev.52
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/codegen/actions.d.ts +1 -1
- package/dist/codegen/actions.js +6 -24
- package/dist/codegen/builders/app-index-ts.js +12 -2
- package/dist/codegen/builders/framework-gen-ts.d.ts +7 -1
- package/dist/codegen/builders/framework-gen-ts.js +56 -12
- package/dist/codegen/builders/index.d.ts +0 -1
- package/dist/codegen/builders/index.js +0 -1
- package/dist/codegen/exec.d.ts +0 -18
- package/dist/codegen/exec.js +0 -27
- package/dist/codegen/index.js +1 -12
- package/dist/codegen/scaffold.d.ts +6 -6
- package/dist/codegen/scaffold.js +18 -53
- package/dist/commands/clint-project-build.d.ts +6 -1
- package/dist/commands/clint-project-build.js +1 -1
- package/dist/commands/clint-project-init.d.ts +6 -1
- package/dist/commands/clint-project-init.js +1 -1
- package/dist/commands/clint-project-publish.d.ts +6 -1
- package/dist/commands/clint-project-publish.js +1 -1
- package/dist/commands/clint-project-regen.d.ts +6 -1
- package/dist/commands/clint-project-regen.js +1 -1
- package/dist/commands/clint-skills-sync.d.ts +6 -1
- package/dist/commands/clint-skills-sync.js +1 -1
- package/dist/framework.d.ts +1 -1
- package/dist/spec/types.d.ts +19 -0
- package/dist/spec/types.js +25 -0
- package/dist/triggers/publish-trigger.js +11 -47
- package/dist/triggers/spec-change.js +3 -1
- package/package.json +4 -4
|
@@ -30,7 +30,7 @@ export type PostGenAction = {
|
|
|
30
30
|
export type PostGenActionKind = PostGenAction['kind'];
|
|
31
31
|
export interface PostGenActionContext {
|
|
32
32
|
log: (msg: string) => void;
|
|
33
|
-
runProcess
|
|
33
|
+
runProcess: (command: string, opts?: Omit<ProcessRunOptions, 'onOutput'>) => Promise<{
|
|
34
34
|
success: boolean;
|
|
35
35
|
output: string;
|
|
36
36
|
}>;
|
package/dist/codegen/actions.js
CHANGED
|
@@ -389,20 +389,11 @@ async function executeAction(action, ctx) {
|
|
|
389
389
|
}
|
|
390
390
|
case 'app-install':
|
|
391
391
|
case 'cli-install': {
|
|
392
|
-
|
|
393
|
-
const result = await ctx.runProcess('pnpm install', {
|
|
394
|
-
cwd: action.dir,
|
|
395
|
-
timeout: 300_000,
|
|
396
|
-
});
|
|
397
|
-
return result.success;
|
|
398
|
-
}
|
|
399
|
-
// Fallback: direct spawn
|
|
400
|
-
const { runCommand } = await import('./exec.js');
|
|
401
|
-
const result = await runCommand('pnpm', ['install'], {
|
|
392
|
+
const result = await ctx.runProcess('pnpm install', {
|
|
402
393
|
cwd: action.dir,
|
|
403
|
-
|
|
394
|
+
timeout: 300_000,
|
|
404
395
|
});
|
|
405
|
-
return result.
|
|
396
|
+
return result.success;
|
|
406
397
|
}
|
|
407
398
|
case 'app-build':
|
|
408
399
|
case 'cli-build': {
|
|
@@ -420,20 +411,11 @@ async function executeAction(action, ctx) {
|
|
|
420
411
|
}
|
|
421
412
|
}
|
|
422
413
|
async function runBuild(dir, ctx) {
|
|
423
|
-
|
|
424
|
-
const result = await ctx.runProcess('pnpm build', {
|
|
425
|
-
cwd: dir,
|
|
426
|
-
timeout: 120_000,
|
|
427
|
-
});
|
|
428
|
-
return result.success;
|
|
429
|
-
}
|
|
430
|
-
// Fallback: direct spawn
|
|
431
|
-
const { runCommand } = await import('./exec.js');
|
|
432
|
-
const result = await runCommand('pnpm', ['build'], {
|
|
414
|
+
const result = await ctx.runProcess('pnpm build', {
|
|
433
415
|
cwd: dir,
|
|
434
|
-
|
|
416
|
+
timeout: 120_000,
|
|
435
417
|
});
|
|
436
|
-
return result.
|
|
418
|
+
return result.success;
|
|
437
419
|
}
|
|
438
420
|
function formatDuration(ms) {
|
|
439
421
|
if (ms < 1000)
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* own reactor package). External packages' document types are imported from
|
|
8
8
|
* their own npm packages, not from the app barrel.
|
|
9
9
|
*/
|
|
10
|
-
import { getAppPackageName, getDocumentTypeSlug, phAtLeast, } from '../../spec/types.js';
|
|
10
|
+
import { getAppPackageName, getDocumentTypeSlug, isDocTypeGlob, phAtLeast, } from '../../spec/types.js';
|
|
11
11
|
export function buildAppIndexTs(spec) {
|
|
12
12
|
if (!phAtLeast(spec.features.powerhouse, 'Reactor'))
|
|
13
13
|
return null;
|
|
@@ -16,12 +16,22 @@ export function buildAppIndexTs(spec) {
|
|
|
16
16
|
const docTypes = appEntry?.documentTypes ?? [];
|
|
17
17
|
if (docTypes.length === 0)
|
|
18
18
|
return null;
|
|
19
|
+
const hasGlobs = docTypes.some(isDocTypeGlob);
|
|
20
|
+
const explicits = docTypes.filter((dt) => !isDocTypeGlob(dt));
|
|
19
21
|
const lines = [];
|
|
20
22
|
lines.push('// THIS FILE IS GENERATED BY ph-clint-cli.');
|
|
21
23
|
lines.push('// Re-exports every registered document model from a single top-level');
|
|
22
24
|
lines.push('// entry so impl code can `import { ... } from \'{name}-app\'`.');
|
|
23
25
|
lines.push('');
|
|
24
|
-
|
|
26
|
+
if (hasGlobs) {
|
|
27
|
+
// Glob patterns can't enumerate slugs at codegen time — re-export
|
|
28
|
+
// from the Powerhouse-generated barrel which already re-exports all
|
|
29
|
+
// document models in the package.
|
|
30
|
+
lines.push("export * from './document-models/index.js';");
|
|
31
|
+
}
|
|
32
|
+
// Explicit entries still get per-slug re-exports (they may point at
|
|
33
|
+
// models not yet in the generated barrel during bootstrapping).
|
|
34
|
+
for (const docType of explicits) {
|
|
25
35
|
const slug = getDocumentTypeSlug(docType);
|
|
26
36
|
lines.push(`export * from './document-models/${slug}/index.js';`);
|
|
27
37
|
}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Builds `src/framework.gen.ts` — the fully machine-owned half of the
|
|
3
3
|
* typed-binding split. Regenerated on every `init` and `update`; holds the
|
|
4
|
-
* `defineRegistry([...]
|
|
4
|
+
* `defineRegistry([...])` call that describes which document models
|
|
5
5
|
* are bound into `framework.ts`'s typed factories.
|
|
6
6
|
*
|
|
7
7
|
* Iterates all packages' document types. The app package's modules are
|
|
8
8
|
* imported from the local `{name}-app` package; external packages' modules
|
|
9
9
|
* are imported from their npm package name.
|
|
10
10
|
*
|
|
11
|
+
* Document type entries may be explicit IDs (`powerhouse/ph-clint-project`)
|
|
12
|
+
* or glob patterns (`*/*`, `powerhouse/*`, `acme/doc-*`). Explicit IDs
|
|
13
|
+
* produce static named imports; glob patterns import the package's
|
|
14
|
+
* `documentModels` array and filter at runtime so newly-added document
|
|
15
|
+
* models are picked up without a codegen re-run.
|
|
16
|
+
*
|
|
11
17
|
* Emitted only when Powerhouse is enabled — flat-layout impls have no
|
|
12
18
|
* reactor package to import modules from and bind `createTypes` directly in
|
|
13
19
|
* `framework.ts`. When Powerhouse is on but no document types are declared,
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Builds `src/framework.gen.ts` — the fully machine-owned half of the
|
|
3
3
|
* typed-binding split. Regenerated on every `init` and `update`; holds the
|
|
4
|
-
* `defineRegistry([...]
|
|
4
|
+
* `defineRegistry([...])` call that describes which document models
|
|
5
5
|
* are bound into `framework.ts`'s typed factories.
|
|
6
6
|
*
|
|
7
7
|
* Iterates all packages' document types. The app package's modules are
|
|
8
8
|
* imported from the local `{name}-app` package; external packages' modules
|
|
9
9
|
* are imported from their npm package name.
|
|
10
10
|
*
|
|
11
|
+
* Document type entries may be explicit IDs (`powerhouse/ph-clint-project`)
|
|
12
|
+
* or glob patterns (`*/*`, `powerhouse/*`, `acme/doc-*`). Explicit IDs
|
|
13
|
+
* produce static named imports; glob patterns import the package's
|
|
14
|
+
* `documentModels` array and filter at runtime so newly-added document
|
|
15
|
+
* models are picked up without a codegen re-run.
|
|
16
|
+
*
|
|
11
17
|
* Emitted only when Powerhouse is enabled — flat-layout impls have no
|
|
12
18
|
* reactor package to import modules from and bind `createTypes` directly in
|
|
13
19
|
* `framework.ts`. When Powerhouse is on but no document types are declared,
|
|
@@ -15,28 +21,44 @@
|
|
|
15
21
|
* `import { registry } from './framework.gen.js'` keeps resolving across
|
|
16
22
|
* regens.
|
|
17
23
|
*/
|
|
18
|
-
import { getAppPackageName, getDocumentTypeModuleName, getDocumentTypeSlug, phAtLeast, } from '../../spec/types.js';
|
|
24
|
+
import { docTypeGlobToRegex, getAppPackageName, getDocumentTypeModuleName, getDocumentTypeSlug, isDocTypeGlob, phAtLeast, } from '../../spec/types.js';
|
|
19
25
|
export function buildFrameworkGenTs(spec) {
|
|
20
26
|
if (!phAtLeast(spec.features.powerhouse, 'Reactor'))
|
|
21
27
|
return null;
|
|
22
28
|
const appPkg = getAppPackageName(spec);
|
|
23
|
-
// Collect
|
|
24
|
-
//
|
|
25
|
-
// bare PascalCase names. External packages use the per-slug deep subpath
|
|
26
|
-
// (`<pkg>/document-models/<slug>`) so TypeScript can resolve internal
|
|
27
|
-
// types (e.g. PHState) from stable import paths for declaration emit.
|
|
29
|
+
// Collect entries across packages. Each package may contribute both
|
|
30
|
+
// explicit named imports and glob-based runtime filters.
|
|
28
31
|
const entries = [];
|
|
32
|
+
let globCounter = 0;
|
|
29
33
|
for (const pkg of spec.packages) {
|
|
30
34
|
const isApp = pkg.packageName === appPkg;
|
|
31
|
-
for (
|
|
35
|
+
// Collect glob patterns for this package (may be multiple).
|
|
36
|
+
const globs = pkg.documentTypes.filter(isDocTypeGlob);
|
|
37
|
+
const explicits = pkg.documentTypes.filter((dt) => !isDocTypeGlob(dt));
|
|
38
|
+
for (const docType of explicits) {
|
|
32
39
|
const slug = getDocumentTypeSlug(docType);
|
|
33
40
|
entries.push({
|
|
34
|
-
|
|
41
|
+
kind: 'explicit',
|
|
35
42
|
name: getDocumentTypeModuleName(docType),
|
|
36
43
|
importFrom: isApp ? appPkg : `${pkg.packageName}/document-models/${slug}`,
|
|
37
44
|
});
|
|
38
45
|
}
|
|
46
|
+
if (globs.length > 0) {
|
|
47
|
+
// Merge all globs for this package into a single regex alternation.
|
|
48
|
+
const combined = globs.length === 1
|
|
49
|
+
? docTypeGlobToRegex(globs[0])
|
|
50
|
+
: globs.map((g) => `(?:${docTypeGlobToRegex(g)})`).join('|');
|
|
51
|
+
const alias = globCounter === 0 ? 'globModels' : `globModels${globCounter}`;
|
|
52
|
+
globCounter++;
|
|
53
|
+
entries.push({
|
|
54
|
+
kind: 'glob',
|
|
55
|
+
modelsAlias: alias,
|
|
56
|
+
importFrom: isApp ? appPkg : pkg.packageName,
|
|
57
|
+
regexSource: combined,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
39
60
|
}
|
|
61
|
+
const hasGlobs = entries.some((e) => e.kind === 'glob');
|
|
40
62
|
const lines = [];
|
|
41
63
|
lines.push('/**');
|
|
42
64
|
lines.push(' * THIS FILE IS GENERATED BY ph-clint-cli. DO NOT EDIT.');
|
|
@@ -46,8 +68,14 @@ export function buildFrameworkGenTs(spec) {
|
|
|
46
68
|
lines.push(' * this file will be overwritten.');
|
|
47
69
|
lines.push(' */');
|
|
48
70
|
lines.push(`import { defineRegistry } from '@powerhousedao/ph-clint';`);
|
|
71
|
+
// Emit imports — named imports for explicit entries, documentModels for globs.
|
|
49
72
|
for (const e of entries) {
|
|
50
|
-
|
|
73
|
+
if (e.kind === 'explicit') {
|
|
74
|
+
lines.push(`import { ${e.name} } from '${e.importFrom}';`);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
lines.push(`import { documentModels as ${e.modelsAlias} } from '${e.importFrom}';`);
|
|
78
|
+
}
|
|
51
79
|
}
|
|
52
80
|
lines.push('');
|
|
53
81
|
lines.push('/**');
|
|
@@ -57,13 +85,29 @@ export function buildFrameworkGenTs(spec) {
|
|
|
57
85
|
if (entries.length === 0) {
|
|
58
86
|
lines.push('export const registry = defineRegistry([] as const);');
|
|
59
87
|
}
|
|
60
|
-
else {
|
|
88
|
+
else if (!hasGlobs) {
|
|
89
|
+
// Pure explicit — use `as const` for full type inference.
|
|
61
90
|
lines.push('export const registry = defineRegistry([');
|
|
62
91
|
for (const e of entries) {
|
|
63
|
-
|
|
92
|
+
if (e.kind === 'explicit') {
|
|
93
|
+
lines.push(` ${e.name},`);
|
|
94
|
+
}
|
|
64
95
|
}
|
|
65
96
|
lines.push('] as const);');
|
|
66
97
|
}
|
|
98
|
+
else {
|
|
99
|
+
// Mix of explicit + glob — runtime filter loses `as const` inference.
|
|
100
|
+
lines.push('export const registry = defineRegistry([');
|
|
101
|
+
for (const e of entries) {
|
|
102
|
+
if (e.kind === 'explicit') {
|
|
103
|
+
lines.push(` ${e.name},`);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
lines.push(` ...${e.modelsAlias}.filter((m) => /${e.regexSource}/.test(m.documentModel.global.id)),`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
lines.push(']);');
|
|
110
|
+
}
|
|
67
111
|
lines.push('');
|
|
68
112
|
lines.push('export type Registry = typeof registry;');
|
|
69
113
|
return lines.join('\n') + '\n';
|
|
@@ -49,4 +49,3 @@ export { buildCliPackageJson, buildCliTs, buildConfigTs, buildMainTs, buildTscon
|
|
|
49
49
|
export { buildRootPackageJson } from './root-package-json.js';
|
|
50
50
|
export { buildPublishConfigJs } from './publish-config-js.js';
|
|
51
51
|
export { buildReadme } from './readme-md.js';
|
|
52
|
-
export { buildAppIndexTs } from './app-index-ts.js';
|
|
@@ -82,4 +82,3 @@ export { buildCliPackageJson, buildCliTs, buildConfigTs, buildMainTs, buildTscon
|
|
|
82
82
|
export { buildRootPackageJson } from './root-package-json.js';
|
|
83
83
|
export { buildPublishConfigJs } from './publish-config-js.js';
|
|
84
84
|
export { buildReadme } from './readme-md.js';
|
|
85
|
-
export { buildAppIndexTs } from './app-index-ts.js';
|
package/dist/codegen/exec.d.ts
CHANGED
|
@@ -1,20 +1,2 @@
|
|
|
1
|
-
export interface RunCommandOptions {
|
|
2
|
-
cwd: string;
|
|
3
|
-
/** Override stdio; default `'inherit'`. Pass `'ignore'` for tests. */
|
|
4
|
-
stdio?: 'inherit' | 'ignore';
|
|
5
|
-
/** Extra env vars (merged with process.env). */
|
|
6
|
-
env?: Record<string, string>;
|
|
7
|
-
}
|
|
8
|
-
export interface RunCommandResult {
|
|
9
|
-
command: string;
|
|
10
|
-
args: string[];
|
|
11
|
-
cwd: string;
|
|
12
|
-
exitCode: number;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Run `command args` in `cwd`, forwarding stdio by default. Resolves to
|
|
16
|
-
* the exit code. Does NOT throw on non-zero — callers decide how to react.
|
|
17
|
-
*/
|
|
18
|
-
export declare function runCommand(command: string, args: string[], options: RunCommandOptions): Promise<RunCommandResult>;
|
|
19
1
|
/** Returns true if `command` is on PATH. */
|
|
20
2
|
export declare function hasCommandOnPath(command: string): Promise<boolean>;
|
package/dist/codegen/exec.js
CHANGED
|
@@ -1,34 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Small helpers for invoking external commands during code generation.
|
|
3
|
-
*
|
|
4
|
-
* We deliberately keep this separate from `ph-clint`'s process manager:
|
|
5
|
-
* here we need synchronous-feeling prompt-forwarding (stdio inherited) so
|
|
6
|
-
* the user can respond to interactive prompts from `ph init` or from a
|
|
7
|
-
* package manager.
|
|
8
3
|
*/
|
|
9
4
|
import { spawn } from 'node:child_process';
|
|
10
|
-
/**
|
|
11
|
-
* Run `command args` in `cwd`, forwarding stdio by default. Resolves to
|
|
12
|
-
* the exit code. Does NOT throw on non-zero — callers decide how to react.
|
|
13
|
-
*/
|
|
14
|
-
export async function runCommand(command, args, options) {
|
|
15
|
-
return new Promise((resolve, reject) => {
|
|
16
|
-
const child = spawn(command, args, {
|
|
17
|
-
cwd: options.cwd,
|
|
18
|
-
stdio: options.stdio ?? 'inherit',
|
|
19
|
-
env: options.env ? { ...process.env, ...options.env } : process.env,
|
|
20
|
-
});
|
|
21
|
-
child.once('error', reject);
|
|
22
|
-
child.once('close', (code) => {
|
|
23
|
-
resolve({
|
|
24
|
-
command,
|
|
25
|
-
args,
|
|
26
|
-
cwd: options.cwd,
|
|
27
|
-
exitCode: code ?? 0,
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
5
|
/** Returns true if `command` is on PATH. */
|
|
33
6
|
export async function hasCommandOnPath(command) {
|
|
34
7
|
return new Promise((resolve) => {
|
package/dist/codegen/index.js
CHANGED
|
@@ -35,7 +35,7 @@ import { hashContent, hashFile, readHashes, writeHashes, } from './hashes.js';
|
|
|
35
35
|
import { hasMarkers, spliceMarkerRegions } from './markers.js';
|
|
36
36
|
import { writeFileEnsuringDir, isDirEmptyEnough } from './write.js';
|
|
37
37
|
import { migrateFlatToSplit } from './migrate/flat-to-split.js';
|
|
38
|
-
import { CLI_FILE_BUILDERS, getProfileFileBuilders, buildReadme, buildRootPackageJson, buildPublishConfigJs,
|
|
38
|
+
import { CLI_FILE_BUILDERS, getProfileFileBuilders, buildReadme, buildRootPackageJson, buildPublishConfigJs, } from './builders/index.js';
|
|
39
39
|
import { collectPostGenActions, } from './actions.js';
|
|
40
40
|
import { readGeneratedState, writeGeneratedState, generatedStateFromSpec, } from './generated.js';
|
|
41
41
|
import { patchAppPackageName } from './scaffold.js';
|
|
@@ -135,17 +135,6 @@ function planFiles(spec, targetDir) {
|
|
|
135
135
|
absolutePath: appReadme,
|
|
136
136
|
content: buildAppReadmeContent(spec),
|
|
137
137
|
});
|
|
138
|
-
// Top-level barrel for the reactor package — lets impl code import from
|
|
139
|
-
// `{name}-app` instead of drilling into `document-models/<slug>/v1/gen`.
|
|
140
|
-
const appIndex = buildAppIndexTs(spec);
|
|
141
|
-
if (appIndex !== null) {
|
|
142
|
-
const appIndexAbs = path.join(appDir, 'index.ts');
|
|
143
|
-
planned.push({
|
|
144
|
-
relativePath: path.relative(targetDir, appIndexAbs),
|
|
145
|
-
absolutePath: appIndexAbs,
|
|
146
|
-
content: appIndex,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
138
|
}
|
|
150
139
|
return { planned, cliDir, appDir };
|
|
151
140
|
}
|
|
@@ -7,6 +7,7 @@ type RunProcess = (command: string, opts?: Omit<ProcessRunOptions, 'onOutput'>)
|
|
|
7
7
|
success: boolean;
|
|
8
8
|
output: string;
|
|
9
9
|
}>;
|
|
10
|
+
export type { RunProcess };
|
|
10
11
|
export interface PhInitOptions {
|
|
11
12
|
/** Absolute path to the project root. */
|
|
12
13
|
targetDir: string;
|
|
@@ -17,8 +18,8 @@ export interface PhInitOptions {
|
|
|
17
18
|
log?: (msg: string) => void;
|
|
18
19
|
/** Override `ph` binary name (for tests). */
|
|
19
20
|
binName?: string;
|
|
20
|
-
/** Subprocess runner —
|
|
21
|
-
runProcess
|
|
21
|
+
/** Subprocess runner — matches CommandContext.runProcess. */
|
|
22
|
+
runProcess: RunProcess;
|
|
22
23
|
/** Explicit Powerhouse version to pin `ph init` to (tag or semver). */
|
|
23
24
|
phVersion?: string;
|
|
24
25
|
}
|
|
@@ -52,7 +53,7 @@ export declare function runPhInstallPackages(options: {
|
|
|
52
53
|
appDir: string;
|
|
53
54
|
packages: string[];
|
|
54
55
|
log?: (msg: string) => void;
|
|
55
|
-
runProcess
|
|
56
|
+
runProcess: RunProcess;
|
|
56
57
|
}): Promise<boolean>;
|
|
57
58
|
export interface PnpmInstallOptions {
|
|
58
59
|
/** Directories to run `pnpm install` in, in order. */
|
|
@@ -60,8 +61,8 @@ export interface PnpmInstallOptions {
|
|
|
60
61
|
log?: (msg: string) => void;
|
|
61
62
|
/** Override `pnpm` binary name (for tests). */
|
|
62
63
|
binName?: string;
|
|
63
|
-
/** Subprocess runner —
|
|
64
|
-
runProcess
|
|
64
|
+
/** Subprocess runner — matches CommandContext.runProcess. */
|
|
65
|
+
runProcess: RunProcess;
|
|
65
66
|
}
|
|
66
67
|
export interface PnpmInstallResult {
|
|
67
68
|
ran: string[];
|
|
@@ -69,4 +70,3 @@ export interface PnpmInstallResult {
|
|
|
69
70
|
reason?: string;
|
|
70
71
|
}
|
|
71
72
|
export declare function runPnpmInstall(options: PnpmInstallOptions): Promise<PnpmInstallResult>;
|
|
72
|
-
export {};
|
package/dist/codegen/scaffold.js
CHANGED
|
@@ -60,30 +60,17 @@ export async function runPhInit(options) {
|
|
|
60
60
|
await fs.rm(options.appDir, { recursive: true, force: true });
|
|
61
61
|
const args = ['init', appFolder, ...versionArgs, '--pnpm'];
|
|
62
62
|
log(`Running \`${binName} init ${appFolder}\` (version: ${phVersion ?? 'auto'}) in ${options.targetDir} …`);
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (!result.success) {
|
|
71
|
-
log(`\`${binName} init\` failed. ` +
|
|
72
|
-
'You can re-run it manually after resolving the issue.');
|
|
73
|
-
}
|
|
74
|
-
// Patch scoped name
|
|
75
|
-
await patchScopedName(options, appFolder, log);
|
|
76
|
-
return { ran: true, exitCode };
|
|
77
|
-
}
|
|
78
|
-
// Fallback: direct spawn with stdio inherit (for backward compat / tests without context)
|
|
79
|
-
const { runCommand } = await import('./exec.js');
|
|
80
|
-
const result = await runCommand(binName, args, { cwd: options.targetDir, stdio: 'inherit' });
|
|
81
|
-
if (result.exitCode !== 0) {
|
|
82
|
-
log(`\`${binName} init\` exited with code ${result.exitCode}. ` +
|
|
63
|
+
const result = await options.runProcess(`${binName} ${args.join(' ')}`, {
|
|
64
|
+
cwd: options.targetDir,
|
|
65
|
+
timeout: 300_000,
|
|
66
|
+
});
|
|
67
|
+
const exitCode = result.success ? 0 : 1;
|
|
68
|
+
if (!result.success) {
|
|
69
|
+
log(`\`${binName} init\` failed. ` +
|
|
83
70
|
'You can re-run it manually after resolving the issue.');
|
|
84
71
|
}
|
|
85
72
|
await patchScopedName(options, appFolder, log);
|
|
86
|
-
return { ran: true, exitCode
|
|
73
|
+
return { ran: true, exitCode };
|
|
87
74
|
}
|
|
88
75
|
/**
|
|
89
76
|
* Patch the app `package.json` name to the scoped form (`@scope/name-app`).
|
|
@@ -132,19 +119,11 @@ export async function runPhInstallPackages(options) {
|
|
|
132
119
|
}
|
|
133
120
|
const args = ['install', ...packages, '--local', '--pnpm'];
|
|
134
121
|
log(`Running \`${binName} install ${packages.join(' ')} --local\` in ${path.basename(appDir)} …`);
|
|
135
|
-
|
|
136
|
-
const result = await runProcess(`${binName} ${args.join(' ')}`, {
|
|
137
|
-
cwd: appDir,
|
|
138
|
-
timeout: 300_000,
|
|
139
|
-
});
|
|
140
|
-
return result.success;
|
|
141
|
-
}
|
|
142
|
-
const { runCommand } = await import('./exec.js');
|
|
143
|
-
const result = await runCommand(binName, args, {
|
|
122
|
+
const result = await runProcess(`${binName} ${args.join(' ')}`, {
|
|
144
123
|
cwd: appDir,
|
|
145
|
-
|
|
124
|
+
timeout: 300_000,
|
|
146
125
|
});
|
|
147
|
-
return result.
|
|
126
|
+
return result.success;
|
|
148
127
|
}
|
|
149
128
|
export async function runPnpmInstall(options) {
|
|
150
129
|
const log = options.log ?? (() => { });
|
|
@@ -157,27 +136,13 @@ export async function runPnpmInstall(options) {
|
|
|
157
136
|
const ran = [];
|
|
158
137
|
for (const dir of options.dirs) {
|
|
159
138
|
log(`Running \`${binName} install\` in ${dir} …`);
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
log(`\`${binName} install\` failed in ${dir}. ` +
|
|
168
|
-
'Retry manually once the underlying issue is resolved.');
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
const { runCommand } = await import('./exec.js');
|
|
173
|
-
const result = await runCommand(binName, ['install'], {
|
|
174
|
-
cwd: dir,
|
|
175
|
-
stdio: 'inherit',
|
|
176
|
-
});
|
|
177
|
-
if (result.exitCode !== 0) {
|
|
178
|
-
log(`\`${binName} install\` exited with code ${result.exitCode} in ${dir}. ` +
|
|
179
|
-
'Retry manually once the underlying issue is resolved.');
|
|
180
|
-
}
|
|
139
|
+
const result = await options.runProcess(`${binName} install`, {
|
|
140
|
+
cwd: dir,
|
|
141
|
+
timeout: 300_000,
|
|
142
|
+
});
|
|
143
|
+
if (!result.success) {
|
|
144
|
+
log(`\`${binName} install\` failed in ${dir}. ` +
|
|
145
|
+
'Retry manually once the underlying issue is resolved.');
|
|
181
146
|
}
|
|
182
147
|
ran.push(dir);
|
|
183
148
|
}
|
|
@@ -4,4 +4,9 @@ export declare const build: import("@powerhousedao/ph-clint").Command<z.ZodObjec
|
|
|
4
4
|
verbose: z.ZodDefault<z.ZodBoolean>;
|
|
5
5
|
}, z.core.$strip>, {
|
|
6
6
|
text: string;
|
|
7
|
-
},
|
|
7
|
+
}, {
|
|
8
|
+
model: string;
|
|
9
|
+
devServicePort: number;
|
|
10
|
+
phVersion: string;
|
|
11
|
+
apiKey?: string | undefined;
|
|
12
|
+
}, import("@powerhousedao/ph-clint").InferRegistry<readonly [import("document-model").DocumentModelModule<import("@powerhousedao/ph-clint-app").PhClintProjectPHState>]>>;
|
|
@@ -78,5 +78,10 @@ export declare const init: import("@powerhousedao/ph-clint").Command<z.ZodObject
|
|
|
78
78
|
};
|
|
79
79
|
fileCount: number;
|
|
80
80
|
};
|
|
81
|
-
},
|
|
81
|
+
}, {
|
|
82
|
+
model: string;
|
|
83
|
+
devServicePort: number;
|
|
84
|
+
phVersion: string;
|
|
85
|
+
apiKey?: string | undefined;
|
|
86
|
+
}, import("@powerhousedao/ph-clint").InferRegistry<readonly [import("document-model").DocumentModelModule<import("@powerhousedao/ph-clint-app").PhClintProjectPHState>]>>;
|
|
82
87
|
export {};
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* 8. Print next-steps guidance.
|
|
13
13
|
*/
|
|
14
14
|
import path from 'node:path';
|
|
15
|
-
import { defineCommand } from '
|
|
15
|
+
import { defineCommand } from '../framework.js';
|
|
16
16
|
import { z } from 'zod';
|
|
17
17
|
import { clintProjectSpecSchema, } from '../spec/types.js';
|
|
18
18
|
import { generateProject } from '../codegen/index.js';
|
|
@@ -13,4 +13,9 @@ export declare const clintProjectPublish: import("@powerhousedao/ph-clint").Comm
|
|
|
13
13
|
}, z.core.$strip>, {
|
|
14
14
|
text: string;
|
|
15
15
|
data: import("@powerhousedao/ph-clint-dev/publish").PublishResult;
|
|
16
|
-
},
|
|
16
|
+
}, {
|
|
17
|
+
model: string;
|
|
18
|
+
devServicePort: number;
|
|
19
|
+
phVersion: string;
|
|
20
|
+
apiKey?: string | undefined;
|
|
21
|
+
}, import("@powerhousedao/ph-clint").InferRegistry<readonly [import("document-model").DocumentModelModule<import("@powerhousedao/ph-clint-app").PhClintProjectPHState>]>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { defineCommand } from '
|
|
2
|
+
import { defineCommand } from '../framework.js';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { resolvePublishPlan, buildPackages, publishPackages, } from '@powerhousedao/ph-clint-dev/publish';
|
|
5
5
|
const inputSchema = z.object({
|
|
@@ -15,4 +15,9 @@ export declare const regen: import("@powerhousedao/ph-clint").Command<z.ZodObjec
|
|
|
15
15
|
migrated: boolean;
|
|
16
16
|
warnings: string[];
|
|
17
17
|
};
|
|
18
|
-
},
|
|
18
|
+
}, {
|
|
19
|
+
model: string;
|
|
20
|
+
devServicePort: number;
|
|
21
|
+
phVersion: string;
|
|
22
|
+
apiKey?: string | undefined;
|
|
23
|
+
}, import("@powerhousedao/ph-clint").InferRegistry<readonly [import("document-model").DocumentModelModule<import("@powerhousedao/ph-clint-app").PhClintProjectPHState>]>>;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* migration fires first.
|
|
8
8
|
*/
|
|
9
9
|
import path from 'node:path';
|
|
10
|
-
import { defineCommand } from '
|
|
10
|
+
import { defineCommand } from '../framework.js';
|
|
11
11
|
import { z } from 'zod';
|
|
12
12
|
import { readProjectSpec } from '../spec/file.js';
|
|
13
13
|
import { generateProject } from '../codegen/index.js';
|
|
@@ -7,4 +7,9 @@ export declare const skillsSync: import("@powerhousedao/ph-clint").Command<z.Zod
|
|
|
7
7
|
} | {
|
|
8
8
|
text: string;
|
|
9
9
|
data: import("../skills/sync.js").SyncResult;
|
|
10
|
-
},
|
|
10
|
+
}, {
|
|
11
|
+
model: string;
|
|
12
|
+
devServicePort: number;
|
|
13
|
+
phVersion: string;
|
|
14
|
+
apiKey?: string | undefined;
|
|
15
|
+
}, import("@powerhousedao/ph-clint").InferRegistry<readonly [import("document-model").DocumentModelModule<import("@powerhousedao/ph-clint-app").PhClintProjectPHState>]>>;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* longer referenced, and updates `.skills-manifest.json`.
|
|
5
5
|
*/
|
|
6
6
|
import path from 'node:path';
|
|
7
|
-
import { defineCommand } from '
|
|
7
|
+
import { defineCommand } from '../framework.js';
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
import { readProjectSpec } from '../spec/file.js';
|
|
10
10
|
import { syncExternalSkills } from '../skills/sync.js';
|
package/dist/framework.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export declare const defineCommand: <TInput extends z.ZodType, TOutput = unknown
|
|
|
36
36
|
devServicePort: number;
|
|
37
37
|
phVersion: string;
|
|
38
38
|
apiKey?: string | undefined;
|
|
39
|
-
}
|
|
39
|
+
}, import("@powerhousedao/ph-clint").InferRegistry<readonly [import("document-model").DocumentModelModule<import("@powerhousedao/ph-clint-app").PhClintProjectPHState>]>>, defineTrigger: <TState = Record<string, unknown>>(options: import("@powerhousedao/ph-clint").TriggerOptions<TState, {
|
|
40
40
|
model: string;
|
|
41
41
|
devServicePort: number;
|
|
42
42
|
phVersion: string;
|
package/dist/spec/types.d.ts
CHANGED
|
@@ -143,3 +143,22 @@ export declare function getDocumentTypeSlug(documentType: string): string;
|
|
|
143
143
|
* it needs both for the import and the `defineRegistry` entry.
|
|
144
144
|
*/
|
|
145
145
|
export declare function getDocumentTypeModuleName(documentType: string): string;
|
|
146
|
+
/**
|
|
147
|
+
* Returns true when a documentType entry contains glob wildcards (`*`).
|
|
148
|
+
* Glob entries like `*/*`, `powerhouse/*`, or `powerhouse/doc-*` are spec
|
|
149
|
+
* shorthand meaning "all matching document types from this package" and
|
|
150
|
+
* must be resolved at runtime rather than emitted as static imports.
|
|
151
|
+
*/
|
|
152
|
+
export declare function isDocTypeGlob(documentType: string): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Convert a documentType glob pattern to a regex source string suitable
|
|
155
|
+
* for embedding in a `/pattern/` literal. Each `*` matches any non-`/`
|
|
156
|
+
* characters. Forward slashes are escaped so the output is safe inside
|
|
157
|
+
* `/.../`.
|
|
158
|
+
*
|
|
159
|
+
* Examples:
|
|
160
|
+
* `*/*` → `^[^\/]*\/[^\/]*$` (any org, any name)
|
|
161
|
+
* `powerhouse/*` → `^powerhouse\/[^\/]*$`
|
|
162
|
+
* `powerhouse/doc-*` → `^powerhouse\/doc-[^\/]*$`
|
|
163
|
+
*/
|
|
164
|
+
export declare function docTypeGlobToRegex(pattern: string): string;
|
package/dist/spec/types.js
CHANGED
|
@@ -182,3 +182,28 @@ export function getDocumentTypeModuleName(documentType) {
|
|
|
182
182
|
.map((s) => s[0].toUpperCase() + s.slice(1))
|
|
183
183
|
.join('');
|
|
184
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Returns true when a documentType entry contains glob wildcards (`*`).
|
|
187
|
+
* Glob entries like `*/*`, `powerhouse/*`, or `powerhouse/doc-*` are spec
|
|
188
|
+
* shorthand meaning "all matching document types from this package" and
|
|
189
|
+
* must be resolved at runtime rather than emitted as static imports.
|
|
190
|
+
*/
|
|
191
|
+
export function isDocTypeGlob(documentType) {
|
|
192
|
+
return documentType.includes('*');
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Convert a documentType glob pattern to a regex source string suitable
|
|
196
|
+
* for embedding in a `/pattern/` literal. Each `*` matches any non-`/`
|
|
197
|
+
* characters. Forward slashes are escaped so the output is safe inside
|
|
198
|
+
* `/.../`.
|
|
199
|
+
*
|
|
200
|
+
* Examples:
|
|
201
|
+
* `*/*` → `^[^\/]*\/[^\/]*$` (any org, any name)
|
|
202
|
+
* `powerhouse/*` → `^powerhouse\/[^\/]*$`
|
|
203
|
+
* `powerhouse/doc-*` → `^powerhouse\/doc-[^\/]*$`
|
|
204
|
+
*/
|
|
205
|
+
export function docTypeGlobToRegex(pattern) {
|
|
206
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\\/]/g, '\\$&');
|
|
207
|
+
const withWildcards = escaped.replace(/\*/g, '[^\\/]*');
|
|
208
|
+
return `^${withWildcards}$`;
|
|
209
|
+
}
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
* b. Runs `ph-clint clint-project-publish --tag <tag>`.
|
|
19
19
|
* c. Dispatches SET_PUBLISH_STATUS({ id, status: "Succeeded"|"Failed" }).
|
|
20
20
|
*/
|
|
21
|
-
import { spawn } from 'node:child_process';
|
|
22
21
|
import path from 'node:path';
|
|
23
22
|
import { scanProjects, getProjectMapping } from '@powerhousedao/ph-clint';
|
|
24
23
|
import { setPublishStatus } from '@powerhousedao/ph-clint-app';
|
|
@@ -27,37 +26,6 @@ import { specFromDocumentState } from '../spec/from-document.js';
|
|
|
27
26
|
import { clintProject } from '../services/clint-project.js';
|
|
28
27
|
const DOCUMENT_TYPE = 'powerhouse/ph-clint-project';
|
|
29
28
|
const TAG = '[publish]';
|
|
30
|
-
/** Run a shell command and return stdout. Rejects on non-zero exit. */
|
|
31
|
-
function exec(cmd, args, cwd, onLog) {
|
|
32
|
-
return new Promise((resolve, reject) => {
|
|
33
|
-
const proc = spawn(cmd, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
34
|
-
const out = [];
|
|
35
|
-
const err = [];
|
|
36
|
-
proc.stdout?.on('data', (d) => {
|
|
37
|
-
const s = d.toString();
|
|
38
|
-
out.push(s);
|
|
39
|
-
if (onLog)
|
|
40
|
-
for (const line of s.split('\n'))
|
|
41
|
-
if (line.trim())
|
|
42
|
-
onLog(line.trim());
|
|
43
|
-
});
|
|
44
|
-
proc.stderr?.on('data', (d) => {
|
|
45
|
-
const s = d.toString();
|
|
46
|
-
err.push(s);
|
|
47
|
-
if (onLog)
|
|
48
|
-
for (const line of s.split('\n'))
|
|
49
|
-
if (line.trim())
|
|
50
|
-
onLog(line.trim());
|
|
51
|
-
});
|
|
52
|
-
proc.on('error', reject);
|
|
53
|
-
proc.on('close', (code) => {
|
|
54
|
-
if (code === 0)
|
|
55
|
-
resolve(out.join(''));
|
|
56
|
-
else
|
|
57
|
-
reject(new Error(`${cmd} ${args.join(' ')} exited ${code}\n${err.join('')}`));
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
29
|
/** Map document model PublishTag values to CLI --tag values. */
|
|
62
30
|
export function tagToCli(tag) {
|
|
63
31
|
switch (tag) {
|
|
@@ -107,6 +75,7 @@ export const publishTrigger = createDocumentChangeTrigger({
|
|
|
107
75
|
continue;
|
|
108
76
|
}
|
|
109
77
|
log?.info(`${TAG} found pending ${record.tag} publish for doc ${doc.header.id} (id=${record.id}, version=${record.version})`);
|
|
78
|
+
const { runProcess, stdout } = ctx.context;
|
|
110
79
|
return {
|
|
111
80
|
type: 'function',
|
|
112
81
|
params: {
|
|
@@ -122,25 +91,20 @@ export const publishTrigger = createDocumentChangeTrigger({
|
|
|
122
91
|
setPublishStatus({ id: record.id, status: 'InProgress' }),
|
|
123
92
|
]);
|
|
124
93
|
// Install dependencies in the generated project before publishing.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
94
|
+
stdout(`${TAG} running pnpm install in ${workdir}\n`);
|
|
95
|
+
const installResult = await runProcess('pnpm install', {
|
|
96
|
+
cwd: workdir,
|
|
97
|
+
timeout: 300_000,
|
|
98
|
+
});
|
|
99
|
+
if (!installResult.success) {
|
|
100
|
+
log?.error(`${TAG} pnpm install failed in ${workdir}`);
|
|
131
101
|
}
|
|
132
102
|
// Run the publish command.
|
|
133
103
|
let success = false;
|
|
134
104
|
try {
|
|
135
|
-
|
|
105
|
+
stdout(`${TAG} invoking clint-project-publish --tag ${cliTag}\n`);
|
|
136
106
|
const { clintProjectPublish } = await import('../commands/clint-project-publish.js');
|
|
137
|
-
const result = await clintProjectPublish.execute({ tag: cliTag, dryRun: false, skipBuild: false, skipGitCheck: true, verbose: false },
|
|
138
|
-
// @ts-expect-error — minimal context; publish uses workdir + stdout.
|
|
139
|
-
{
|
|
140
|
-
workdir,
|
|
141
|
-
stdout: (msg) => log?.info(`${TAG} ${msg}`),
|
|
142
|
-
log,
|
|
143
|
-
});
|
|
107
|
+
const result = await clintProjectPublish.execute({ tag: cliTag, dryRun: false, skipBuild: false, skipGitCheck: true, verbose: false }, ctx.commandContext);
|
|
144
108
|
success = !result.text.includes('failed');
|
|
145
109
|
}
|
|
146
110
|
catch (err) {
|
|
@@ -148,7 +112,7 @@ export const publishTrigger = createDocumentChangeTrigger({
|
|
|
148
112
|
}
|
|
149
113
|
// Update status.
|
|
150
114
|
const finalStatus = success ? 'Succeeded' : 'Failed';
|
|
151
|
-
|
|
115
|
+
stdout(`${TAG} marking record ${record.id} as ${finalStatus}\n`);
|
|
152
116
|
await reactor.client.execute(doc.header.id, 'main', [
|
|
153
117
|
setPublishStatus({
|
|
154
118
|
id: record.id,
|
|
@@ -187,8 +187,10 @@ export const specChangeTrigger = createDocumentChangeTrigger({
|
|
|
187
187
|
log.warn(`${TAG} ${w}`);
|
|
188
188
|
}
|
|
189
189
|
// Run post-generation actions (ph-init, install, build, skills-sync).
|
|
190
|
+
// Route through ctx.context.stdout so output flows through
|
|
191
|
+
// routine.onOutput → service log buffer → ServicePanel.
|
|
190
192
|
await runPostGenActions(result.pendingActions, {
|
|
191
|
-
log: (msg) =>
|
|
193
|
+
log: (msg) => ctx.context.stdout(`${TAG} ${msg}\n`),
|
|
192
194
|
runProcess: ctx.context.runProcess,
|
|
193
195
|
});
|
|
194
196
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerhousedao/ph-clint-cli",
|
|
3
|
-
"version": "0.1.0-dev.
|
|
3
|
+
"version": "0.1.0-dev.52",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"@mastra/core": "^1.22.0",
|
|
30
30
|
"@mastra/libsql": "^1.7.4",
|
|
31
31
|
"@mastra/memory": "^1.13.1",
|
|
32
|
-
"@powerhousedao/ph-clint": "^0.1.0-dev.
|
|
33
|
-
"@powerhousedao/ph-clint-app": "^0.1.0-dev.
|
|
34
|
-
"@powerhousedao/ph-clint-dev": "^0.1.0-dev.
|
|
32
|
+
"@powerhousedao/ph-clint": "^0.1.0-dev.52",
|
|
33
|
+
"@powerhousedao/ph-clint-app": "^0.1.0-dev.52",
|
|
34
|
+
"@powerhousedao/ph-clint-dev": "^0.1.0-dev.52",
|
|
35
35
|
"@powerhousedao/reactor": "6.0.0-dev.170",
|
|
36
36
|
"@powerhousedao/reactor-api": "6.0.0-dev.170",
|
|
37
37
|
"@powerhousedao/shared": "6.0.0-dev.170",
|