@powerhousedao/ph-clint-cli 0.1.0-dev.6 → 0.1.0-dev.60
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 +1 -0
- package/dist/codegen/actions.js +1 -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.d.ts +1 -8
- package/dist/codegen/builders/cli-package-json.js +1 -96
- package/dist/codegen/builders/cli-ts.js +88 -37
- 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 +1 -44
- package/dist/codegen/builders/index.js +1 -61
- 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/publish-config-ts.d.ts +4 -2
- package/dist/codegen/builders/publish-config-ts.js +25 -11
- package/dist/codegen/builders/readme-md.js +7 -6
- package/dist/codegen/builders/root-package-json.js +14 -11
- 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 +1 -20
- package/dist/codegen/exec.js +1 -41
- package/dist/codegen/generated.d.ts +1 -0
- package/dist/codegen/generated.js +1 -0
- package/dist/codegen/hashes.d.ts +1 -6
- package/dist/codegen/hashes.js +1 -60
- package/dist/codegen/index.d.ts +8 -36
- package/dist/codegen/index.js +6 -293
- package/dist/codegen/markers.d.ts +1 -36
- package/dist/codegen/markers.js +1 -86
- package/dist/codegen/scaffold.d.ts +1 -34
- package/dist/codegen/scaffold.js +1 -60
- package/dist/codegen/write.d.ts +1 -6
- package/dist/codegen/write.js +1 -32
- package/dist/commands/clint-project-build.d.ts +6 -1
- package/dist/commands/clint-project-build.js +11 -28
- package/dist/commands/clint-project-init.d.ts +40 -10
- package/dist/commands/clint-project-init.js +55 -47
- package/dist/commands/clint-project-publish.d.ts +7 -1
- package/dist/commands/clint-project-publish.js +6 -4
- package/dist/commands/clint-project-regen.d.ts +6 -1
- package/dist/commands/clint-project-regen.js +26 -2
- package/dist/commands/clint-skills-sync.d.ts +15 -0
- package/dist/commands/clint-skills-sync.js +56 -0
- package/dist/framework.d.ts +6 -170
- package/dist/framework.gen.d.ts +1 -32
- 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/services/clint-project.js +21 -0
- package/dist/skills/sync.d.ts +1 -0
- package/dist/skills/sync.js +1 -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 +10 -0
- package/dist/triggers/publish-trigger.js +133 -0
- package/dist/triggers/spec-change.d.ts +5 -34
- package/dist/triggers/spec-change.js +137 -102
- package/package.json +12 -12
- package/prompts/skills-ext/.gitkeep +0 -0
- package/prompts/skills-tpl/.gitkeep +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cli-setup
|
|
3
|
+
description: "Set up a new CLI with defineCli, config schemas, entrypoint, and interactive mode"
|
|
4
|
+
metadata:
|
|
5
|
+
author: Powerhouse
|
|
6
|
+
version: "1.0.0"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
=== BEGIN SKILL BRIEFING ===
|
|
10
|
+
|
|
11
|
+
IMPORTANT: Don't take any action yet. You will be guided through your tasks after the briefing(s). Just process and confirm your understanding.
|
|
12
|
+
|
|
13
|
+
# CLI Setup - Skill Preamble
|
|
14
|
+
|
|
15
|
+
With this skill, you can scaffold or extend a `defineCli()` configuration — the composition root that wires commands, config, services, triggers, and integrations into a single CLI runtime. A single `defineCli()` call produces a CLI that works in command mode (`mycli cmd --arg val`), interactive REPL mode (`/cmd --arg val`), and as an MCP server — all from the same code.
|
|
16
|
+
|
|
17
|
+
## Core Principles
|
|
18
|
+
|
|
19
|
+
### defineCli Is Declarative
|
|
20
|
+
|
|
21
|
+
You describe _what_ the CLI has — the framework wires it up. The order of options doesn't matter, but understanding what triggers what does:
|
|
22
|
+
|
|
23
|
+
- `configSchema` present → auto-injects a `config` command for viewing/modifying settings
|
|
24
|
+
- `secretsSchema` present → fields merge into configSchema internally, but are censored in output
|
|
25
|
+
- `services` present → auto-injects per-service management commands (`{id}-start`, `{id}-stop`, etc.)
|
|
26
|
+
- `interactive` present → enables the `-i` flag for REPL mode
|
|
27
|
+
- `triggers` present → enables routine loop
|
|
28
|
+
- `cli-docs` command is always auto-injected (CLI help for the agent)
|
|
29
|
+
|
|
30
|
+
### Resolvable Values
|
|
31
|
+
|
|
32
|
+
`description` and `interactive.welcome` accept either a static string or a function `({ config, workdir }) => string`. Use functions when the message depends on runtime state — e.g., showing "demo mode" vs "LLM mode" based on whether an API key is configured.
|
|
33
|
+
|
|
34
|
+
### The Cli Object
|
|
35
|
+
|
|
36
|
+
`defineCli()` returns a `Cli` object — the public API with methods for running, testing, introspection, and metadata. The standard entry point is `cli.run(process.argv)`. For programmatic access (e.g., codegen scripts), use `cli.bootstrap()` which resolves workdir, config, and context without entering the dispatch loop.
|
|
37
|
+
|
|
38
|
+
### Two Interaction Modes
|
|
39
|
+
|
|
40
|
+
1. **Command mode** (headless): Execute one subcommand, then exit. Triggered by `mycli cmd --flag val`.
|
|
41
|
+
2. **Interactive REPL mode**: Persistent session with `/command` syntax and bare text for the default subcommand (typically the agent). Triggered by `mycli -i` or when keep-alive features are active (routine loop, API server).
|
|
42
|
+
|
|
43
|
+
### 6-Layer Config Resolution
|
|
44
|
+
|
|
45
|
+
Config values are resolved in this priority order (highest wins):
|
|
46
|
+
1. `--config <file>` flag
|
|
47
|
+
2. Environment variables: `{CLI_NAME}_{UPPER_SNAKE_FIELD}`
|
|
48
|
+
3. Local config: `{workdir}/.ph/{cliName}.config.local.json`
|
|
49
|
+
4. User config: `~/.ph/{cliName}.config.user.json`
|
|
50
|
+
5. Implementation defaults: `configDefaults` in CliOptions
|
|
51
|
+
6. Zod schema `.default()` values
|
|
52
|
+
|
|
53
|
+
### Config vs Secrets
|
|
54
|
+
|
|
55
|
+
- `configSchema` — user-facing settings (model name, ports, feature flags). Shown in `config` command output.
|
|
56
|
+
- `secretsSchema` — sensitive values (API keys, tokens). Merged into configSchema internally but censored as `***` in output unless `--revealSecrets` is used.
|
|
57
|
+
|
|
58
|
+
Put API keys and tokens in `secretsSchema`, not `configSchema`.
|
|
59
|
+
|
|
60
|
+
### configDefaults vs Schema Defaults
|
|
61
|
+
|
|
62
|
+
- `.default(value)` in the Zod schema → layer 6, the fallback when nothing else is configured
|
|
63
|
+
- `configDefaults` in CliOptions → layer 5, implementation-level overrides that sit above schema defaults but below user/local config
|
|
64
|
+
|
|
65
|
+
Use schema `.default()` for universal sensible defaults. Use `configDefaults` for implementation-specific overrides that differ from the general-purpose default.
|
|
66
|
+
|
|
67
|
+
### Entry Point Convention
|
|
68
|
+
|
|
69
|
+
The CLI entry point is a TypeScript file with a Node.js shebang:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
#!/usr/bin/env node
|
|
73
|
+
import { defineCli } from '@powerhousedao/ph-clint';
|
|
74
|
+
// ... imports ...
|
|
75
|
+
const cli = defineCli({ /* options */ });
|
|
76
|
+
cli.run(process.argv);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The `package.json` needs a `"bin"` field pointing to the compiled output and `"type": "module"` for ESM.
|
|
80
|
+
|
|
81
|
+
## Common Pitfalls
|
|
82
|
+
|
|
83
|
+
- **Forgetting `version`** — Commander needs it for the `--version` flag; omitting it breaks help output
|
|
84
|
+
- **Putting secrets in `configSchema`** — they show up in `config` command output and metadata, exposing sensitive values
|
|
85
|
+
- **Not setting `interactive.welcome`** — REPL starts with no context, confusing the user
|
|
86
|
+
- **Using `configDefaults` for universal defaults** — use `.default()` in the schema instead; `configDefaults` is for implementation-level overrides only
|
|
87
|
+
- **Calling `configureAgent()` inside `defineCli()`** — it's a method on the returned `Cli` object, called after definition
|
|
88
|
+
- **Forgetting `"type": "module"` in package.json** — ESM imports fail at runtime
|
|
89
|
+
- **Not exporting the `cli` object** — other files (e.g., `mastra/index.ts`) may need it for `cli.bootstrap()`
|
|
90
|
+
|
|
91
|
+
## When to Use `createTypes()`
|
|
92
|
+
|
|
93
|
+
For projects with a config schema, use the typed factory to get automatic config typing in all commands:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { createTypes } from '@powerhousedao/ph-clint';
|
|
97
|
+
const { defineCommand, defineTrigger } = createTypes({ configSchema });
|
|
98
|
+
// context.config is now fully typed in every command
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Codegen-Managed Projects
|
|
102
|
+
|
|
103
|
+
In ph-clint-cli projects, `clint-project-init` generates the initial scaffold including `cli.ts` with `@clint:begin`/`@clint:end` marker regions. The codegen system:
|
|
104
|
+
|
|
105
|
+
- **Generates `cli.ts`** with marker regions for imports, commands, services, triggers, prompts, events, interactive, reactor, and mastra
|
|
106
|
+
- **Generates `framework.gen.ts`** (codegen-owned) with the document registry — regenerated when the spec's `documentTypes` change
|
|
107
|
+
- **Emits `framework.ts`** once (user-owned) with `configSchema`, `secretsSchema`, and `createTypes()` — never overwritten after creation
|
|
108
|
+
|
|
109
|
+
**The agent never hand-edits marker regions in `cli.ts`.** To add or change CLI features:
|
|
110
|
+
|
|
111
|
+
1. Update `project-spec.json` to declare the new structure
|
|
112
|
+
2. Run `clint-project-regen` to regenerate the marker regions
|
|
113
|
+
3. Run `clint-project-build` to verify
|
|
114
|
+
|
|
115
|
+
User-owned code outside markers (`configSchema`, `secretsSchema`, `CLI_NAME`) is preserved across regens. User-owned files (`framework.ts`, `src/commands/*.ts`, `src/services/*.ts`, `src/triggers/*.ts`) are never overwritten.
|
|
116
|
+
|
|
117
|
+
=== END OF SKILL BRIEFING ===
|
|
118
|
+
|
|
119
|
+
## Specific tasks
|
|
120
|
+
|
|
121
|
+
* **Assess Cli Needs** [references/00.assess-cli-needs.md](references/00.assess-cli-needs.md)
|
|
122
|
+
* **Define Config Schema** [references/01.define-config-schema.md](references/01.define-config-schema.md)
|
|
123
|
+
* **Wire Cli** [references/02.wire-cli.md](references/02.wire-cli.md)
|
|
124
|
+
* **Add Entrypoint** [references/03.add-entrypoint.md](references/03.add-entrypoint.md)
|
|
125
|
+
* **Expected Outcome** [references/expected-outcome.md](references/expected-outcome.md)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Phase 0: Assess CLI Needs
|
|
2
|
+
|
|
3
|
+
Before writing any code, determine which features the CLI requires.
|
|
4
|
+
|
|
5
|
+
## Steps
|
|
6
|
+
|
|
7
|
+
### 1. Name the CLI
|
|
8
|
+
|
|
9
|
+
Choose a kebab-case name. This name is used for:
|
|
10
|
+
- Config file paths: `{workdir}/.ph/{name}.config.local.json`
|
|
11
|
+
- Environment variable prefix: `{NAME}_*` (UPPER_SNAKE_CASE)
|
|
12
|
+
- Package `"bin"` field and executable name
|
|
13
|
+
|
|
14
|
+
### 2. Determine version sourcing
|
|
15
|
+
|
|
16
|
+
Choose one:
|
|
17
|
+
- **Hardcoded**: `version: '1.0.0'`
|
|
18
|
+
- **From package.json**: `const { version } = readPackageInfo(import.meta.url)`
|
|
19
|
+
|
|
20
|
+
### 3. Feature checklist
|
|
21
|
+
|
|
22
|
+
For each feature, determine if the CLI needs it:
|
|
23
|
+
|
|
24
|
+
- [ ] **Custom config?** → needs `configSchema` (Zod object)
|
|
25
|
+
- [ ] **Sensitive config (API keys, tokens)?** → needs `secretsSchema` (Zod object)
|
|
26
|
+
- [ ] **Interactive REPL?** → needs `interactive` with `welcome` message
|
|
27
|
+
- [ ] **Background services?** → needs `services` array of `defineService()` definitions
|
|
28
|
+
- [ ] **Automated triggers?** → needs `triggers` array + `routine` config
|
|
29
|
+
- [ ] **AI agent?** → needs `cli.configureAgent(loader)` after `defineCli()`
|
|
30
|
+
- [ ] **Skill templates?** → needs `prompts` config with `artifacts`, `agents`, `skills`
|
|
31
|
+
- [ ] **Powerhouse documents?** → needs `cli.configureReactor(config)` after `defineCli()`
|
|
32
|
+
- [ ] **Service lifecycle events?** → needs `events` handlers
|
|
33
|
+
- [ ] **Implementation-level workdir override?** → needs `workdir` option (hides `--workdir` flag)
|
|
34
|
+
|
|
35
|
+
### 4. List commands to register
|
|
36
|
+
|
|
37
|
+
Enumerate all commands that will be passed to the `commands` array. These should already be defined using `defineCommand()` (see the `command-definition` skill). Note which ones need agent-compatible `{ text, data }` returns.
|
|
38
|
+
|
|
39
|
+
### 5. Detect codegen vs manual project
|
|
40
|
+
|
|
41
|
+
For existing projects, check if `cli.ts` already has `@clint:begin` marker regions:
|
|
42
|
+
- **Codegen-managed**: Markers present — update `project-spec.json` and run `clint-project-regen`. Never hand-edit marker regions.
|
|
43
|
+
- **Manual**: No markers — edit `defineCli()` directly as a regular TypeScript file.
|
|
44
|
+
|
|
45
|
+
For new projects, prefer using `clint-project-init` to generate the scaffold with markers.
|
|
46
|
+
|
|
47
|
+
### 6. Determine config field names
|
|
48
|
+
|
|
49
|
+
For each config/secret field, verify the auto-generated env var name is sensible:
|
|
50
|
+
- Field `apiKey` on CLI `mycli` → env var `MYCLI_API_KEY`
|
|
51
|
+
- Field `connectPort` on CLI `vetra` → env var `VETRA_CONNECT_PORT`
|
|
52
|
+
|
|
53
|
+
If a name would be confusing, consider renaming the field.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Phase 1: Define Config and Secrets Schemas
|
|
2
|
+
|
|
3
|
+
Design and wire the configuration layer. Skip this phase if the CLI needs no configuration.
|
|
4
|
+
|
|
5
|
+
## Steps
|
|
6
|
+
|
|
7
|
+
### 1. Define configSchema
|
|
8
|
+
|
|
9
|
+
Create a Zod object schema for user-facing settings:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
|
|
14
|
+
export const configSchema = z.object({
|
|
15
|
+
model: z.string().default('anthropic/claude-sonnet-4-5').describe('LLM model to use'),
|
|
16
|
+
port: z.number().default(4001).describe('Server port'),
|
|
17
|
+
verbose: z.boolean().default(false).describe('Enable verbose output'),
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Rules:
|
|
22
|
+
- Every field MUST have `.describe('...')` — it appears in `config` command output, `--help`, and env var listings
|
|
23
|
+
- Use `.default(value)` for fields with sensible defaults
|
|
24
|
+
- Use `.optional()` only for truly optional fields with no default
|
|
25
|
+
- Prefer specific types: `z.enum([...])` for constrained choices, `z.number()` for ports
|
|
26
|
+
|
|
27
|
+
### 2. Define secretsSchema
|
|
28
|
+
|
|
29
|
+
Create a separate Zod object schema for sensitive values:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
export const secretsSchema = z.object({
|
|
33
|
+
apiKey: z.string().optional().describe('LLM API key'),
|
|
34
|
+
dbToken: z.string().optional().describe('Database access token'),
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Rules:
|
|
39
|
+
- Secrets are almost always `.optional()` — the CLI should work without them (possibly in a degraded mode)
|
|
40
|
+
- These fields are merged into configSchema internally but censored in output
|
|
41
|
+
- They follow the same env var naming: `{CLI_NAME}_{FIELD}`
|
|
42
|
+
|
|
43
|
+
### 3. Set configDefaults (if needed)
|
|
44
|
+
|
|
45
|
+
Use `configDefaults` in `defineCli()` for implementation-specific overrides that differ from the schema defaults:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
defineCli({
|
|
49
|
+
configSchema,
|
|
50
|
+
configDefaults: {
|
|
51
|
+
port: 8080, // This implementation uses 8080, not the schema default of 4001
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This is layer 5 — above schema `.default()` but below user/local config files.
|
|
57
|
+
|
|
58
|
+
### 4. Use createTypes for typed commands
|
|
59
|
+
|
|
60
|
+
If you have a configSchema, create a typed factory so all commands get typed `context.config`:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// framework.ts
|
|
64
|
+
import { createTypes } from '@powerhousedao/ph-clint';
|
|
65
|
+
import { configSchema, secretsSchema } from './config.js';
|
|
66
|
+
|
|
67
|
+
export const { defineCommand, defineTrigger } = createTypes({ configSchema, secretsSchema });
|
|
68
|
+
export { configSchema, secretsSchema };
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Then import `defineCommand` from `./framework.js` instead of `ph-clint` in all command files.
|
|
72
|
+
|
|
73
|
+
### 5. Verify env var names
|
|
74
|
+
|
|
75
|
+
Run through each field and check the auto-generated env var name:
|
|
76
|
+
- `{CLI_NAME}` is the CLI name uppercased with hyphens replaced by underscores
|
|
77
|
+
- Field keys are converted to UPPER_SNAKE_CASE
|
|
78
|
+
- Example: CLI `my-app`, field `connectPort` → `MY_APP_CONNECT_PORT`
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Phase 2: Wire the defineCli Call
|
|
2
|
+
|
|
3
|
+
Compose the `defineCli()` call with all the options determined in Phase 0.
|
|
4
|
+
|
|
5
|
+
## Steps
|
|
6
|
+
|
|
7
|
+
### 1. Assemble the core options
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { defineCli } from '@powerhousedao/ph-clint';
|
|
11
|
+
import { configSchema, secretsSchema } from './config.js';
|
|
12
|
+
import { myCommand, otherCommand } from './commands/index.js';
|
|
13
|
+
|
|
14
|
+
export const cli = defineCli({
|
|
15
|
+
name: 'my-app',
|
|
16
|
+
version: '1.0.0',
|
|
17
|
+
description: 'My application CLI',
|
|
18
|
+
commands: [myCommand, otherCommand],
|
|
19
|
+
configSchema,
|
|
20
|
+
secretsSchema,
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Always export the `cli` object — other files may need it (e.g., `mastra/index.ts` for `cli.bootstrap()`).
|
|
25
|
+
|
|
26
|
+
### 2. Configure interactive mode
|
|
27
|
+
|
|
28
|
+
Add an `interactive` block if the CLI supports REPL mode:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
interactive: {
|
|
32
|
+
welcome: 'My App CLI — type /help for commands',
|
|
33
|
+
},
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
For dynamic welcome messages that depend on config:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
interactive: {
|
|
40
|
+
welcome: ({ config, workdir }) => {
|
|
41
|
+
const mode = config.apiKey ? config.model : 'demo mode';
|
|
42
|
+
return `My App (${mode})\nWorkdir: ${workdir}`;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Add services (if needed)
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { myService } from './services/my-service.js';
|
|
51
|
+
|
|
52
|
+
defineCli({
|
|
53
|
+
// ...
|
|
54
|
+
services: [myService],
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This auto-injects `my-service-start`, `my-service-stop`, `my-service-restart`, `my-service-ps`, `my-service-logs`, and `my-service-manage` commands.
|
|
59
|
+
|
|
60
|
+
### 4. Add event handlers (if needed)
|
|
61
|
+
|
|
62
|
+
Wire lifecycle events for services or custom events:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
events: {
|
|
66
|
+
'service:ready': (event, log) => {
|
|
67
|
+
log.info(`${event.name} is ready`);
|
|
68
|
+
},
|
|
69
|
+
'service:failed': (event, log) => {
|
|
70
|
+
log.error(`${event.name} failed: ${event.error}`);
|
|
71
|
+
},
|
|
72
|
+
'service:stopped': (event, log) => {
|
|
73
|
+
log.info(`${event.name} stopped`);
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Available service events: `service:pattern-matched`, `service:ready`, `service:failed`, `service:restarting`, `service:stopped`. Each receives `(event, log)` where `log` is a structured Logger.
|
|
79
|
+
|
|
80
|
+
### 5. Add prompts config (if skills are needed)
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import path from 'node:path';
|
|
84
|
+
|
|
85
|
+
prompts: {
|
|
86
|
+
artifacts: [path.join(CLI_ROOT, 'gen', 'skills')],
|
|
87
|
+
agents: {
|
|
88
|
+
'my-agent': {
|
|
89
|
+
name: 'MyAgent',
|
|
90
|
+
sections: ['AgentBase.md', 'MySpecialization.md'],
|
|
91
|
+
skills: ['skill-one', 'skill-two'],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
skills: {
|
|
95
|
+
'skill-one': {
|
|
96
|
+
description: 'Description of skill one',
|
|
97
|
+
inputSchema: z.object({
|
|
98
|
+
mode: z.enum(['expert', 'discovery']).default('expert').describe('Interaction mode'),
|
|
99
|
+
}),
|
|
100
|
+
instructionTemplate: 'Use your {{skillId}} skill in {{mode}} mode for: {{prompt}}',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 6. Call configureAgent / configureReactor (if needed)
|
|
107
|
+
|
|
108
|
+
These are called AFTER `defineCli()` — they are methods on the returned `Cli` object:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
export const cli = defineCli({ /* ... */ });
|
|
112
|
+
|
|
113
|
+
// Agent integration (Mastra)
|
|
114
|
+
cli.configureAgent(createAgent);
|
|
115
|
+
|
|
116
|
+
// Reactor integration (Powerhouse)
|
|
117
|
+
cli.configureReactor({
|
|
118
|
+
registry: [/* document models */],
|
|
119
|
+
// ...
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Both are lazy-loaded — the actual agent/reactor is only created when first accessed.
|
|
124
|
+
|
|
125
|
+
### 7. Codegen projects: use spec + regen
|
|
126
|
+
|
|
127
|
+
In codegen-managed projects, do NOT manually edit `cli.ts` marker regions. Instead:
|
|
128
|
+
|
|
129
|
+
1. Update `project-spec.json` with the new features (commands, services, triggers, integrations)
|
|
130
|
+
2. Run `clint-project-regen` to regenerate marker regions
|
|
131
|
+
3. Edit user-owned files directly: `framework.ts` for config/secrets schemas, `src/commands/*.ts` for commands, etc.
|
|
132
|
+
|
|
133
|
+
Core options outside markers (`name`, `version`, `description`, `configSchema`, `secretsSchema`) are in the user-editable zone — edit those directly in `cli.ts`.
|
|
134
|
+
|
|
135
|
+
### 8. Verify built-in commands
|
|
136
|
+
|
|
137
|
+
After wiring, confirm these commands will be auto-injected:
|
|
138
|
+
- `cli-docs` — always present
|
|
139
|
+
- `config` — present if `configSchema` was provided
|
|
140
|
+
- Service commands — present for each entry in `services`
|
|
141
|
+
- Skill commands — present for each entry in `prompts.skills`
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Phase 3: Create the Entry Point
|
|
2
|
+
|
|
3
|
+
Set up the CLI entry point and package.json configuration.
|
|
4
|
+
|
|
5
|
+
## Steps
|
|
6
|
+
|
|
7
|
+
### 1. Create the entry point file
|
|
8
|
+
|
|
9
|
+
Create `src/cli.ts` (or `src/main.ts`) with the Node.js shebang:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
#!/usr/bin/env node
|
|
13
|
+
import { defineCli } from '@powerhousedao/ph-clint';
|
|
14
|
+
import { configSchema } from './config.js';
|
|
15
|
+
import { myCommand } from './commands/my-command.js';
|
|
16
|
+
|
|
17
|
+
const cli = defineCli({
|
|
18
|
+
name: 'my-app',
|
|
19
|
+
version: '1.0.0',
|
|
20
|
+
description: 'My application',
|
|
21
|
+
commands: [myCommand],
|
|
22
|
+
configSchema,
|
|
23
|
+
interactive: {
|
|
24
|
+
welcome: 'My App — type /help for commands',
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
cli.run(process.argv);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
If the CLI definition is complex, keep it in a separate file (`src/cli-definition.ts`) and import it:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
#!/usr/bin/env node
|
|
35
|
+
import { cli } from './cli-definition.js';
|
|
36
|
+
cli.run(process.argv);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. Configure package.json
|
|
40
|
+
|
|
41
|
+
Add these fields:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"type": "module",
|
|
46
|
+
"bin": {
|
|
47
|
+
"my-app": "./dist/cli.js"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsc",
|
|
51
|
+
"start": "node dist/cli.js",
|
|
52
|
+
"dev": "tsx src/cli.ts"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- `"type": "module"` — required for ESM imports
|
|
58
|
+
- `"bin"` — maps the CLI name to the compiled entry point
|
|
59
|
+
- `"dev"` script uses `tsx` for development without compilation
|
|
60
|
+
|
|
61
|
+
### 3. Configure tsconfig.json
|
|
62
|
+
|
|
63
|
+
Ensure these compiler options:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"compilerOptions": {
|
|
68
|
+
"target": "ES2022",
|
|
69
|
+
"module": "Node16",
|
|
70
|
+
"moduleResolution": "Node16",
|
|
71
|
+
"outDir": "./dist",
|
|
72
|
+
"rootDir": "./src",
|
|
73
|
+
"declaration": true,
|
|
74
|
+
"strict": true,
|
|
75
|
+
"esModuleInterop": true
|
|
76
|
+
},
|
|
77
|
+
"include": ["src"]
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 4. Add ph-clint dependency
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
pnpm add @powerhousedao/ph-clint zod
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Or for local development with the library:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"dependencies": {
|
|
92
|
+
"ph-clint": "file:../../packages/ph-clint"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 5. Codegen projects already have entry points
|
|
98
|
+
|
|
99
|
+
In codegen-managed projects (created by `clint-project-init`), the scaffold already includes:
|
|
100
|
+
- `src/main.ts` — shebang entry point with `cli.run(process.argv)`
|
|
101
|
+
- `src/cli.ts` — `defineCli()` with marker regions
|
|
102
|
+
- `src/framework.ts` — user-owned config schemas and `createTypes()`
|
|
103
|
+
- `package.json` — pre-configured with `bin`, `type: "module"`, and scripts
|
|
104
|
+
|
|
105
|
+
Skip steps 1-4 if these already exist. Proceed directly to verification.
|
|
106
|
+
|
|
107
|
+
### 6. Verify the CLI works
|
|
108
|
+
|
|
109
|
+
Run these checks:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
# Build
|
|
113
|
+
pnpm build
|
|
114
|
+
|
|
115
|
+
# Help output (should show all commands)
|
|
116
|
+
node dist/cli.js --help
|
|
117
|
+
|
|
118
|
+
# Version
|
|
119
|
+
node dist/cli.js --version
|
|
120
|
+
|
|
121
|
+
# A specific command
|
|
122
|
+
node dist/cli.js my-command --help
|
|
123
|
+
|
|
124
|
+
# Interactive mode (if configured)
|
|
125
|
+
node dist/cli.js -i
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Expected: `--help` shows the description, version, all registered commands (including auto-injected ones like `config` and `cli-docs`), and global options (`-i`, `--workdir`, `--config`, `--verbose`).
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
## Expected Outcome
|
|
2
|
+
|
|
3
|
+
CLI is defined with all required features wired in (config, secrets, services, interactive mode as needed). The entry point is set up with a shebang and `cli.run(process.argv)`. The `package.json` has `"bin"` and `"type": "module"` fields. The CLI responds correctly to `--help`, `--version`, `-i`, and all registered commands. If `configureAgent()` or `configureReactor()` are needed, they are called after `defineCli()`.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
## API Reference: Command Definition
|
|
2
|
+
|
|
3
|
+
### `defineCommand<TInput, TOutput, TConfig>(options)`
|
|
4
|
+
|
|
5
|
+
Identity function that returns the options object with full type inference. Accepts three generic parameters:
|
|
6
|
+
|
|
7
|
+
- `TInput extends z.ZodType` — the input schema type
|
|
8
|
+
- `TOutput` — the return type of `execute`
|
|
9
|
+
- `TConfig` — the config type from `defineCli`
|
|
10
|
+
|
|
11
|
+
### `Command<TInput, TOutput, TConfig>` Interface
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
interface Command<TInput, TOutput, TConfig> {
|
|
15
|
+
id: string; // Kebab-case identifier (e.g. 'add-task')
|
|
16
|
+
description: string; // One-line description for help text
|
|
17
|
+
inputSchema: TInput; // Zod object schema — each field = CLI flag
|
|
18
|
+
outputSchema?: z.ZodType; // Optional output validation schema
|
|
19
|
+
prompt?: PromptConfig; // Interactive prompting configuration
|
|
20
|
+
execute: (
|
|
21
|
+
input: z.output<TInput>,
|
|
22
|
+
context: CommandContext<TConfig>
|
|
23
|
+
) => Promise<TOutput>;
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### `CommandContext<TConfig>` Interface
|
|
28
|
+
|
|
29
|
+
Available properties on the context object:
|
|
30
|
+
|
|
31
|
+
| Property | Type | Description |
|
|
32
|
+
|----------|------|-------------|
|
|
33
|
+
| `workdir` | `string` | Resolved working directory |
|
|
34
|
+
| `workspace` | `WorkdirStore` | Persistent file-based state (`.ph/{cliName}/`) |
|
|
35
|
+
| `config` | `TConfig` | Typed configuration object |
|
|
36
|
+
| `stdout` | `(text: string) => void` | Output function for streaming text |
|
|
37
|
+
| `log` | `Logger?` | Structured logger (debug/info/warn/error) |
|
|
38
|
+
| `routine` | `Routine?` | Routine loop control (if triggers configured) |
|
|
39
|
+
| `processes` | `ProcessManager?` | Run shell commands with timeout and labeling |
|
|
40
|
+
| `services` | `ServiceManager?` | Manage background services (if configured) |
|
|
41
|
+
| `emit` | `EmitFn?` | Event bus emitter |
|
|
42
|
+
| `reactor` | `() => Promise<ReactorContext?>` | Lazy Powerhouse reactor access |
|
|
43
|
+
| `agent` | `() => Promise<AgentProvider?>` | Lazy Mastra agent access |
|
|
44
|
+
|
|
45
|
+
### `WorkdirStore` Methods
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
workspace.loadJsonObject<T>(filename, fallback) // Load JSON from .ph/ store
|
|
49
|
+
workspace.storeJsonObject(filename, value) // Save JSON to .ph/ store
|
|
50
|
+
workspace.loadLocalConfig() // Load local config
|
|
51
|
+
workspace.storeLocalConfig(config) // Save local config
|
|
52
|
+
workspace.getWorkdir() // Get workdir path
|
|
53
|
+
workspace.getStoreFolder(subpath?) // Get .ph/ store folder path
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### `PromptConfig` Interface
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
interface PromptConfig {
|
|
60
|
+
promptForDefaults?: boolean; // Prompt for fields with .default()? (default: true)
|
|
61
|
+
promptOptional?: string[]; // List of optional field IDs to prompt for
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Return Value Handling
|
|
66
|
+
|
|
67
|
+
The framework processes return values as follows:
|
|
68
|
+
|
|
69
|
+
1. `undefined` or `null` — nothing is printed
|
|
70
|
+
2. `string` — displayed directly as output
|
|
71
|
+
3. Object with `.text` property — the `text` string is displayed; `.data` is available for programmatic/agent consumption
|
|
72
|
+
4. Any other value — converted via `String(value)`
|
|
73
|
+
|
|
74
|
+
### Registration in `defineCli`
|
|
75
|
+
|
|
76
|
+
Commands are registered via the `commands` array:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const cli = defineCli({
|
|
80
|
+
name: 'mycli',
|
|
81
|
+
commands: [greet, addTask, listTasks],
|
|
82
|
+
// ...
|
|
83
|
+
});
|
|
84
|
+
```
|