@powerhousedao/ph-clint-cli 0.1.0-dev.94 → 0.1.0-dev.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/package.json +21 -21
  2. package/dist/codegen/actions.d.ts +0 -46
  3. package/dist/codegen/actions.js +0 -424
  4. package/dist/codegen/builders/agent-base-md.d.ts +0 -5
  5. package/dist/codegen/builders/agent-base-md.js +0 -18
  6. package/dist/codegen/builders/agent-ts.d.ts +0 -9
  7. package/dist/codegen/builders/agent-ts.js +0 -124
  8. package/dist/codegen/builders/app-index-ts.d.ts +0 -11
  9. package/dist/codegen/builders/app-index-ts.js +0 -43
  10. package/dist/codegen/builders/build-skills-ts.d.ts +0 -4
  11. package/dist/codegen/builders/build-skills-ts.js +0 -37
  12. package/dist/codegen/builders/cli-package-json.d.ts +0 -8
  13. package/dist/codegen/builders/cli-package-json.js +0 -128
  14. package/dist/codegen/builders/cli-ts.d.ts +0 -7
  15. package/dist/codegen/builders/cli-ts.js +0 -170
  16. package/dist/codegen/builders/config-ts.d.ts +0 -8
  17. package/dist/codegen/builders/config-ts.js +0 -11
  18. package/dist/codegen/builders/demo-agent-ts.d.ts +0 -8
  19. package/dist/codegen/builders/demo-agent-ts.js +0 -50
  20. package/dist/codegen/builders/eslint-config-js.d.ts +0 -4
  21. package/dist/codegen/builders/eslint-config-js.js +0 -16
  22. package/dist/codegen/builders/framework-gen-ts.d.ts +0 -25
  23. package/dist/codegen/builders/framework-gen-ts.js +0 -114
  24. package/dist/codegen/builders/framework-ts.d.ts +0 -21
  25. package/dist/codegen/builders/framework-ts.js +0 -100
  26. package/dist/codegen/builders/gitignore.d.ts +0 -4
  27. package/dist/codegen/builders/gitignore.js +0 -18
  28. package/dist/codegen/builders/index.d.ts +0 -52
  29. package/dist/codegen/builders/index.js +0 -85
  30. package/dist/codegen/builders/jest-config-js.d.ts +0 -4
  31. package/dist/codegen/builders/jest-config-js.js +0 -19
  32. package/dist/codegen/builders/main-ts.d.ts +0 -5
  33. package/dist/codegen/builders/main-ts.js +0 -13
  34. package/dist/codegen/builders/manifest-json.d.ts +0 -6
  35. package/dist/codegen/builders/manifest-json.js +0 -31
  36. package/dist/codegen/builders/mastra-index-ts.d.ts +0 -11
  37. package/dist/codegen/builders/mastra-index-ts.js +0 -72
  38. package/dist/codegen/builders/publish-config-js.d.ts +0 -8
  39. package/dist/codegen/builders/publish-config-js.js +0 -33
  40. package/dist/codegen/builders/readme-md.d.ts +0 -5
  41. package/dist/codegen/builders/readme-md.js +0 -45
  42. package/dist/codegen/builders/root-package-json.d.ts +0 -10
  43. package/dist/codegen/builders/root-package-json.js +0 -39
  44. package/dist/codegen/builders/smoke-test-ts.d.ts +0 -2
  45. package/dist/codegen/builders/smoke-test-ts.js +0 -15
  46. package/dist/codegen/builders/tsconfig-json.d.ts +0 -4
  47. package/dist/codegen/builders/tsconfig-json.js +0 -22
  48. package/dist/codegen/exec.d.ts +0 -2
  49. package/dist/codegen/exec.js +0 -14
  50. package/dist/codegen/generated.d.ts +0 -17
  51. package/dist/codegen/generated.js +0 -49
  52. package/dist/codegen/hashes.d.ts +0 -6
  53. package/dist/codegen/hashes.js +0 -60
  54. package/dist/codegen/markers.d.ts +0 -36
  55. package/dist/codegen/markers.js +0 -86
  56. package/dist/codegen/migrate/flat-to-split.d.ts +0 -15
  57. package/dist/codegen/migrate/flat-to-split.js +0 -119
  58. package/dist/codegen/scaffold.d.ts +0 -72
  59. package/dist/codegen/scaffold.js +0 -150
  60. package/dist/codegen/write.d.ts +0 -6
  61. package/dist/codegen/write.js +0 -32
  62. package/dist/skills/sync.d.ts +0 -40
  63. package/dist/skills/sync.js +0 -119
@@ -1,150 +0,0 @@
1
- /**
2
- * Post-generation side-effects: invoke `ph init` to fill in the reactor
3
- * package skeleton, and run `pnpm install` in the relevant sub-projects.
4
- *
5
- * Both steps are opt-out (flags on the init command) and both tolerate
6
- * missing binaries — they never fail the init flow, only emit warnings.
7
- */
8
- import fs from 'node:fs/promises';
9
- import path from 'node:path';
10
- import { execFileSync } from 'node:child_process';
11
- import { hasCommandOnPath } from './exec.js';
12
- /**
13
- * Detect the installed `ph` CLI version by parsing `ph --version` output.
14
- * Returns the version string (e.g. '6.0.0-dev.194') or undefined if
15
- * detection fails.
16
- */
17
- export function getPhVersion(binName) {
18
- try {
19
- const output = execFileSync(binName, ['--version'], {
20
- encoding: 'utf-8',
21
- timeout: 5_000,
22
- });
23
- const match = output.match(/PH CMD version:\s*(\S+)/);
24
- return match?.[1];
25
- }
26
- catch {
27
- return undefined;
28
- }
29
- }
30
- export async function runPhInit(options) {
31
- const log = options.log ?? (() => { });
32
- const binName = options.binName ?? 'ph';
33
- const appFolder = path.basename(options.appDir);
34
- // Guard: never re-init an already-initialized app directory.
35
- try {
36
- await fs.access(path.join(options.appDir, 'package.json'));
37
- log(`App directory ${appFolder} already initialized — skipping ph init.`);
38
- return { ran: false, reason: 'already-initialized' };
39
- }
40
- catch {
41
- // No package.json — proceed with init.
42
- }
43
- if (!(await hasCommandOnPath(binName))) {
44
- log(`Skipping \`${binName} init\` — \`${binName}\` is not on PATH. ` +
45
- `Install @powerhousedao/ph-cli and re-run manually inside ${appFolder}/.`);
46
- return { ran: false, reason: 'ph-not-on-path' };
47
- }
48
- // Pin ph init to the same version as the installed ph CLI, so the
49
- // generated app uses matching Powerhouse packages.
50
- const phVersion = options.phVersion ?? getPhVersion(binName);
51
- const tags = ['dev', 'staging', 'latest'];
52
- const versionArgs = phVersion
53
- ? tags.includes(phVersion)
54
- ? [`--${phVersion}`]
55
- : ['--version', phVersion]
56
- : ['--dev']; // fallback if detection fails
57
- // `ph init {name}` creates a fresh directory beside the cwd. Our generator
58
- // placed a `.gitkeep` + README.md placeholder there; clear it out so
59
- // ph init has a blank slate to work with.
60
- await fs.rm(options.appDir, { recursive: true, force: true });
61
- const args = ['init', appFolder, ...versionArgs, '--pnpm'];
62
- log(`Running \`${binName} init ${appFolder}\` (version: ${phVersion ?? 'auto'}) in ${options.targetDir} …`);
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. ` +
70
- 'You can re-run it manually after resolving the issue.');
71
- }
72
- await patchScopedName(options, appFolder, log);
73
- return { ran: true, exitCode };
74
- }
75
- /**
76
- * Patch the app `package.json` name to the scoped form (`@scope/name-app`).
77
- * Called after `ph init` and after name/scope renames.
78
- *
79
- * Returns `true` if the file was actually changed.
80
- */
81
- export async function patchAppPackageName(appDir, spec, log) {
82
- const appFolder = path.basename(appDir);
83
- const scopedName = spec.scope
84
- ? `${spec.scope}/${appFolder}`
85
- : appFolder;
86
- const appPkgJsonPath = path.join(appDir, 'package.json');
87
- try {
88
- const raw = await fs.readFile(appPkgJsonPath, 'utf8');
89
- const pkg = JSON.parse(raw);
90
- if (pkg.name !== scopedName) {
91
- pkg.name = scopedName;
92
- if (spec.scope) {
93
- pkg.publishConfig = { access: 'public' };
94
- }
95
- await fs.writeFile(appPkgJsonPath, JSON.stringify(pkg, null, 2) + '\n');
96
- log?.(`Patched app package name to ${scopedName}`);
97
- return true;
98
- }
99
- return false;
100
- }
101
- catch (err) {
102
- log?.(`Warning: could not patch app package name: ${err instanceof Error ? err.message : String(err)}`);
103
- return false;
104
- }
105
- }
106
- async function patchScopedName(options, _appFolder, log) {
107
- await patchAppPackageName(options.appDir, options.spec, log);
108
- }
109
- /**
110
- * Run `ph install <packages> --local --pnpm` in the app directory to register
111
- * external packages in `powerhouse.config.json`.
112
- */
113
- export async function runPhInstallPackages(options) {
114
- const { appDir, packages, log = () => { }, runProcess } = options;
115
- const binName = 'ph';
116
- if (!(await hasCommandOnPath(binName))) {
117
- log(`Skipping — \`${binName}\` is not on PATH.`);
118
- return false;
119
- }
120
- const args = ['install', ...packages, '--local', '--pnpm'];
121
- log(`Running \`${binName} install ${packages.join(' ')} --local\` in ${path.basename(appDir)} …`);
122
- const result = await runProcess(`${binName} ${args.join(' ')}`, {
123
- cwd: appDir,
124
- timeout: 300_000,
125
- });
126
- return result.success;
127
- }
128
- export async function runPnpmInstall(options) {
129
- const log = options.log ?? (() => { });
130
- const binName = options.binName ?? 'pnpm';
131
- if (!(await hasCommandOnPath(binName))) {
132
- log(`Skipping \`${binName} install\` — \`${binName}\` is not on PATH. ` +
133
- 'Install pnpm and re-run manually.');
134
- return { ran: [], skipped: options.dirs, reason: 'pnpm-not-on-path' };
135
- }
136
- const ran = [];
137
- for (const dir of options.dirs) {
138
- log(`Running \`${binName} install\` in ${dir} …`);
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.');
146
- }
147
- ran.push(dir);
148
- }
149
- return { ran, skipped: [] };
150
- }
@@ -1,6 +0,0 @@
1
- export declare function writeFileEnsuringDir(filePath: string, content: string): Promise<void>;
2
- /**
3
- * Returns true if the directory doesn't exist or only contains ignorable
4
- * entries (`.git`, `.DS_Store`, `.ph/ph-clint-cli/project-spec.json`).
5
- */
6
- export declare function isDirEmptyEnough(dir: string): Promise<boolean>;
@@ -1,32 +0,0 @@
1
- /**
2
- * Low-level file-writing helpers for the code generator.
3
- */
4
- import fs from 'node:fs/promises';
5
- import path from 'node:path';
6
- export async function writeFileEnsuringDir(filePath, content) {
7
- await fs.mkdir(path.dirname(filePath), { recursive: true });
8
- await fs.writeFile(filePath, content, 'utf8');
9
- }
10
- function isEnoent(err) {
11
- return (!!err &&
12
- typeof err === 'object' &&
13
- 'code' in err &&
14
- err.code === 'ENOENT');
15
- }
16
- /**
17
- * Returns true if the directory doesn't exist or only contains ignorable
18
- * entries (`.git`, `.DS_Store`, `.ph/ph-clint-cli/project-spec.json`).
19
- */
20
- export async function isDirEmptyEnough(dir) {
21
- let entries;
22
- try {
23
- entries = await fs.readdir(dir);
24
- }
25
- catch (err) {
26
- if (isEnoent(err))
27
- return true;
28
- throw err;
29
- }
30
- const ignorable = new Set(['.git', '.DS_Store', '.ph']);
31
- return entries.every((entry) => ignorable.has(entry));
32
- }
@@ -1,40 +0,0 @@
1
- import type { ExternalSkill } from '../spec/types.js';
2
- /** On-disk manifest entry (what is currently installed). */
3
- export interface ManifestEntry {
4
- name: string;
5
- githubUrl: string;
6
- }
7
- /** Persisted manifest — a simple JSON array. */
8
- export type SkillsManifest = ManifestEntry[];
9
- export interface SyncResult {
10
- added: string[];
11
- removed: string[];
12
- unchanged: string[];
13
- }
14
- export interface SyncOptions {
15
- /** Project root (CLI sub-tree when split layout). */
16
- targetDir: string;
17
- /** Desired state from the spec. */
18
- desired: ExternalSkill[];
19
- /** Optional log callback. */
20
- log?: (msg: string) => void;
21
- }
22
- export declare function readManifest(targetDir: string): Promise<SkillsManifest>;
23
- /**
24
- * Compute the diff between desired (spec) and current (manifest) skills.
25
- *
26
- * Pure function — no I/O.
27
- */
28
- export declare function diffSkills(desired: ExternalSkill[], current: SkillsManifest): {
29
- toAdd: ExternalSkill[];
30
- toRemove: ManifestEntry[];
31
- unchanged: string[];
32
- };
33
- /**
34
- * Synchronise external skills on disk to match the spec.
35
- *
36
- * - Clones missing skills via `git clone --depth 1`.
37
- * - Removes skills no longer in the spec.
38
- * - Updates the `.skills-manifest.json`.
39
- */
40
- export declare function syncExternalSkills(opts: SyncOptions): Promise<SyncResult>;
@@ -1,119 +0,0 @@
1
- /**
2
- * External skills synchronisation.
3
- *
4
- * Reads the desired external skills from a `ClintProjectSpec`, diffs them
5
- * against a `.skills-manifest.json` on disk, and runs `git clone` / `rm -rf`
6
- * to reconcile. Each external skill ends up as a subdirectory of
7
- * `prompts/skills-ext/<name>/` so the build-skills pipeline picks it up.
8
- */
9
- import { spawn } from 'node:child_process';
10
- import fs from 'node:fs/promises';
11
- import path from 'node:path';
12
- const MANIFEST_FILE = '.skills-manifest.json';
13
- const SKILLS_DIR = path.join('prompts', 'skills-ext');
14
- function manifestPath(targetDir) {
15
- return path.join(targetDir, SKILLS_DIR, MANIFEST_FILE);
16
- }
17
- export async function readManifest(targetDir) {
18
- try {
19
- const raw = await fs.readFile(manifestPath(targetDir), 'utf8');
20
- return JSON.parse(raw);
21
- }
22
- catch {
23
- return [];
24
- }
25
- }
26
- async function writeManifest(targetDir, manifest) {
27
- const file = manifestPath(targetDir);
28
- await fs.mkdir(path.dirname(file), { recursive: true });
29
- await fs.writeFile(file, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
30
- }
31
- function execGit(args, cwd) {
32
- return new Promise((resolve, reject) => {
33
- const proc = spawn('git', args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
34
- let stderr = '';
35
- if (proc.stderr) {
36
- proc.stderr.on('data', (d) => {
37
- stderr += d.toString();
38
- });
39
- }
40
- proc.on('close', (code) => resolve({ code: code ?? 1, stderr }));
41
- proc.on('error', (err) => reject(err));
42
- });
43
- }
44
- /**
45
- * Compute the diff between desired (spec) and current (manifest) skills.
46
- *
47
- * Pure function — no I/O.
48
- */
49
- export function diffSkills(desired, current) {
50
- const desiredMap = new Map(desired.map((s) => [s.name, s]));
51
- const currentMap = new Map(current.map((s) => [s.name, s]));
52
- const toAdd = [];
53
- const toRemove = [];
54
- const unchanged = [];
55
- for (const [name, skill] of desiredMap) {
56
- const existing = currentMap.get(name);
57
- if (!existing) {
58
- toAdd.push(skill);
59
- }
60
- else if (existing.githubUrl !== skill.githubUrl) {
61
- // URL changed — remove old, add new.
62
- toRemove.push(existing);
63
- toAdd.push(skill);
64
- }
65
- else {
66
- unchanged.push(name);
67
- }
68
- }
69
- for (const [name, entry] of currentMap) {
70
- if (!desiredMap.has(name)) {
71
- toRemove.push(entry);
72
- }
73
- }
74
- return { toAdd, toRemove, unchanged };
75
- }
76
- /**
77
- * Synchronise external skills on disk to match the spec.
78
- *
79
- * - Clones missing skills via `git clone --depth 1`.
80
- * - Removes skills no longer in the spec.
81
- * - Updates the `.skills-manifest.json`.
82
- */
83
- export async function syncExternalSkills(opts) {
84
- const { targetDir, desired, log } = opts;
85
- const skillsDir = path.join(targetDir, SKILLS_DIR);
86
- await fs.mkdir(skillsDir, { recursive: true });
87
- const current = await readManifest(targetDir);
88
- const { toAdd, toRemove, unchanged } = diffSkills(desired, current);
89
- const result = { added: [], removed: [], unchanged };
90
- // Remove skills.
91
- for (const entry of toRemove) {
92
- const dir = path.join(skillsDir, entry.name);
93
- log?.(`Removing skill "${entry.name}"…`);
94
- await fs.rm(dir, { recursive: true, force: true });
95
- result.removed.push(entry.name);
96
- }
97
- // Add skills.
98
- for (const skill of toAdd) {
99
- const dir = path.join(skillsDir, skill.name);
100
- log?.(`Cloning skill "${skill.name}" from ${skill.githubUrl}…`);
101
- // Ensure the target doesn't exist (re-add after URL change).
102
- await fs.rm(dir, { recursive: true, force: true });
103
- const { code, stderr } = await execGit(['clone', '--depth', '1', skill.githubUrl, skill.name], skillsDir);
104
- if (code !== 0) {
105
- log?.(`Warning: git clone failed for "${skill.name}": ${stderr.trim()}`);
106
- continue;
107
- }
108
- // Remove .git dir — we don't want a nested repo.
109
- await fs.rm(path.join(dir, '.git'), { recursive: true, force: true });
110
- result.added.push(skill.name);
111
- }
112
- // Write updated manifest.
113
- const newManifest = desired.map((s) => ({
114
- name: s.name,
115
- githubUrl: s.githubUrl,
116
- }));
117
- await writeManifest(targetDir, newManifest);
118
- return result;
119
- }