@powerhousedao/ph-clint-cli 0.0.1
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/README.md +84 -0
- package/dist/agents/clint-agent.d.ts +12 -0
- package/dist/agents/clint-agent.js +42 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +122 -0
- package/dist/codegen/index.d.ts +11 -0
- package/dist/codegen/index.js +11 -0
- package/dist/commands/clint-project-build.d.ts +83 -0
- package/dist/commands/clint-project-build.js +34 -0
- package/dist/commands/clint-project-init.d.ts +177 -0
- package/dist/commands/clint-project-init.js +193 -0
- package/dist/commands/clint-project-publish.d.ts +92 -0
- package/dist/commands/clint-project-publish.js +73 -0
- package/dist/commands/clint-project-regen.d.ts +94 -0
- package/dist/commands/clint-project-regen.js +92 -0
- package/dist/commands/clint-skills-sync.d.ts +86 -0
- package/dist/commands/clint-skills-sync.js +56 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +5 -0
- package/dist/framework.d.ts +501 -0
- package/dist/framework.gen.d.ts +77 -0
- package/dist/framework.gen.js +16 -0
- package/dist/framework.js +37 -0
- package/dist/gen/agent-profiles/PhClintDevAgent.md +13 -0
- package/dist/gen/skills/cli-setup/.cli-docs.md +135 -0
- package/dist/gen/skills/cli-setup/SKILL.md +125 -0
- package/dist/gen/skills/cli-setup/references/00.assess-cli-needs.md +53 -0
- package/dist/gen/skills/cli-setup/references/01.define-config-schema.md +78 -0
- package/dist/gen/skills/cli-setup/references/02.wire-cli.md +141 -0
- package/dist/gen/skills/cli-setup/references/03.add-entrypoint.md +128 -0
- package/dist/gen/skills/cli-setup/references/expected-outcome.md +3 -0
- package/dist/gen/skills/command-definition/.cli-docs.md +84 -0
- package/dist/gen/skills/command-definition/SKILL.md +99 -0
- package/dist/gen/skills/command-definition/references/00.assess-requirements.md +58 -0
- package/dist/gen/skills/command-definition/references/01.define-schema.md +72 -0
- package/dist/gen/skills/command-definition/references/02.implement-execute.md +118 -0
- package/dist/gen/skills/command-definition/references/03.add-prompting.md +54 -0
- package/dist/gen/skills/command-definition/references/expected-outcome.md +3 -0
- package/dist/gen/skills/service-definition/.cli-docs.md +214 -0
- package/dist/gen/skills/service-definition/SKILL.md +148 -0
- package/dist/gen/skills/service-definition/references/00.assess-service.md +69 -0
- package/dist/gen/skills/service-definition/references/01.define-service.md +166 -0
- package/dist/gen/skills/service-definition/references/02.add-preflight.md +132 -0
- package/dist/gen/skills/service-definition/references/03.add-project-scanner.md +82 -0
- package/dist/gen/skills/service-definition/references/04.wire-events.md +120 -0
- package/dist/gen/skills/service-definition/references/expected-outcome.md +3 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +3 -0
- package/dist/mastra/index.d.ts +10 -0
- package/dist/mastra/index.js +11 -0
- package/dist/services/clint-project.d.ts +1 -0
- package/dist/services/clint-project.js +68 -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 -0
- package/dist/spec/file.js +1 -0
- package/dist/spec/from-document.d.ts +21 -0
- package/dist/spec/from-document.js +18 -0
- package/dist/spec/types.d.ts +1 -0
- package/dist/spec/types.js +1 -0
- package/dist/triggers/publish-trigger.d.ts +81 -0
- package/dist/triggers/publish-trigger.js +137 -0
- package/dist/triggers/spec-change.d.ts +85 -0
- package/dist/triggers/spec-change.js +224 -0
- package/package.json +54 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed document registry derived from the reactor package's document models.
|
|
3
|
+
* Regenerated whenever the spec's `documentTypes` list changes.
|
|
4
|
+
*/
|
|
5
|
+
export declare const registry: import("@powerhousedao/ph-clint").InferRegistry<readonly [{
|
|
6
|
+
readonly version: 1;
|
|
7
|
+
readonly reducer: import("document-model").Reducer<import("@powerhousedao/ph-clint-app").PhClintProjectPHState>;
|
|
8
|
+
readonly actions: {
|
|
9
|
+
setAgentModel: (input: import("@powerhousedao/ph-clint-app").SetAgentModelInput) => import("@powerhousedao/ph-clint-app").SetAgentModelAction;
|
|
10
|
+
addAgentProfileRef: (input: import("@powerhousedao/ph-clint-app").AddAgentProfileRefInput) => import("@powerhousedao/ph-clint-app").AddAgentProfileRefAction;
|
|
11
|
+
removeAgentProfileRef: (input: import("@powerhousedao/ph-clint-app").RemoveAgentProfileRefInput) => import("@powerhousedao/ph-clint-app").RemoveAgentProfileRefAction;
|
|
12
|
+
reorderAgentProfileRefs: (input: import("@powerhousedao/ph-clint-app").ReorderAgentProfileRefsInput) => import("@powerhousedao/ph-clint-app").ReorderAgentProfileRefsAction;
|
|
13
|
+
addAgentSkill: (input: import("@powerhousedao/ph-clint-app").AddAgentSkillInput) => import("@powerhousedao/ph-clint-app").AddAgentSkillAction;
|
|
14
|
+
removeAgentSkill: (input: import("@powerhousedao/ph-clint-app").RemoveAgentSkillInput) => import("@powerhousedao/ph-clint-app").RemoveAgentSkillAction;
|
|
15
|
+
addAgentToolPattern: (input: import("@powerhousedao/ph-clint-app").AddAgentToolPatternInput) => import("@powerhousedao/ph-clint-app").AddAgentToolPatternAction;
|
|
16
|
+
removeAgentToolPattern: (input: import("@powerhousedao/ph-clint-app").RemoveAgentToolPatternInput) => import("@powerhousedao/ph-clint-app").RemoveAgentToolPatternAction;
|
|
17
|
+
addSubAgent: (input: import("@powerhousedao/ph-clint-app").AddSubAgentInput) => import("@powerhousedao/ph-clint-app").AddSubAgentAction;
|
|
18
|
+
removeSubAgent: (input: import("@powerhousedao/ph-clint-app").RemoveSubAgentInput) => import("@powerhousedao/ph-clint-app").RemoveSubAgentAction;
|
|
19
|
+
setSubAgentName: (input: import("@powerhousedao/ph-clint-app").SetSubAgentNameInput) => import("@powerhousedao/ph-clint-app").SetSubAgentNameAction;
|
|
20
|
+
setSubAgentDescription: (input: import("@powerhousedao/ph-clint-app").SetSubAgentDescriptionInput) => import("@powerhousedao/ph-clint-app").SetSubAgentDescriptionAction;
|
|
21
|
+
setMainAgentName: (input: import("@powerhousedao/ph-clint-app").SetMainAgentNameInput) => import("@powerhousedao/ph-clint-app").SetMainAgentNameAction;
|
|
22
|
+
setMainAgentDescription: (input: import("@powerhousedao/ph-clint-app").SetMainAgentDescriptionInput) => import("@powerhousedao/ph-clint-app").SetMainAgentDescriptionAction;
|
|
23
|
+
clearMainAgentDescription: (input: import("@powerhousedao/ph-clint-app").ClearMainAgentDescriptionInput) => import("@powerhousedao/ph-clint-app").ClearMainAgentDescriptionAction;
|
|
24
|
+
setMainAgentImage: (input: import("@powerhousedao/ph-clint-app").SetMainAgentImageInput) => import("@powerhousedao/ph-clint-app").SetMainAgentImageAction;
|
|
25
|
+
clearMainAgentImage: (input: import("@powerhousedao/ph-clint-app").ClearMainAgentImageInput) => import("@powerhousedao/ph-clint-app").ClearMainAgentImageAction;
|
|
26
|
+
addProfile: (input: import("@powerhousedao/ph-clint-app").AddProfileInput) => import("@powerhousedao/ph-clint-app").AddProfileAction;
|
|
27
|
+
updateProfile: (input: import("@powerhousedao/ph-clint-app").UpdateProfileInput) => import("@powerhousedao/ph-clint-app").UpdateProfileAction;
|
|
28
|
+
removeProfile: (input: import("@powerhousedao/ph-clint-app").RemoveProfileInput) => import("@powerhousedao/ph-clint-app").RemoveProfileAction;
|
|
29
|
+
reorderProfiles: (input: import("@powerhousedao/ph-clint-app").ReorderProfilesInput) => import("@powerhousedao/ph-clint-app").ReorderProfilesAction;
|
|
30
|
+
addModel: (input: import("@powerhousedao/ph-clint-app").AddModelInput) => import("@powerhousedao/ph-clint-app").AddModelAction;
|
|
31
|
+
removeModel: (input: import("@powerhousedao/ph-clint-app").RemoveModelInput) => import("@powerhousedao/ph-clint-app").RemoveModelAction;
|
|
32
|
+
enableMastra: (input: import("@powerhousedao/ph-clint-app").EnableMastraInput) => import("@powerhousedao/ph-clint-app").EnableMastraAction;
|
|
33
|
+
disableMastra: (input: import("@powerhousedao/ph-clint-app").DisableMastraInput) => import("@powerhousedao/ph-clint-app").DisableMastraAction;
|
|
34
|
+
setEnableChat: (input: import("@powerhousedao/ph-clint-app").SetEnableChatInput) => import("@powerhousedao/ph-clint-app").SetEnableChatAction;
|
|
35
|
+
addSupportedResource: (input: import("@powerhousedao/ph-clint-app").AddSupportedResourceInput) => import("@powerhousedao/ph-clint-app").AddSupportedResourceAction;
|
|
36
|
+
removeSupportedResource: (input: import("@powerhousedao/ph-clint-app").RemoveSupportedResourceInput) => import("@powerhousedao/ph-clint-app").RemoveSupportedResourceAction;
|
|
37
|
+
setProxyEnabled: (input: import("@powerhousedao/ph-clint-app").SetProxyEnabledInput) => import("@powerhousedao/ph-clint-app").SetProxyEnabledAction;
|
|
38
|
+
setObservabilityEnabled: (input: import("@powerhousedao/ph-clint-app").SetObservabilityEnabledInput) => import("@powerhousedao/ph-clint-app").SetObservabilityEnabledAction;
|
|
39
|
+
importSpec: (input: import("@powerhousedao/ph-clint-app").ImportSpecInput) => import("@powerhousedao/ph-clint-app").ImportSpecAction;
|
|
40
|
+
bumpVersion: (input: import("@powerhousedao/ph-clint-app").BumpVersionInput) => import("@powerhousedao/ph-clint-app").BumpVersionAction;
|
|
41
|
+
publishDev: (input: import("@powerhousedao/ph-clint-app").PublishDevInput) => import("@powerhousedao/ph-clint-app").PublishDevAction;
|
|
42
|
+
publishStaging: (input: import("@powerhousedao/ph-clint-app").PublishStagingInput) => import("@powerhousedao/ph-clint-app").PublishStagingAction;
|
|
43
|
+
publishProduction: (input: import("@powerhousedao/ph-clint-app").PublishProductionInput) => import("@powerhousedao/ph-clint-app").PublishProductionAction;
|
|
44
|
+
setPublishStatus: (input: import("@powerhousedao/ph-clint-app").SetPublishStatusInput) => import("@powerhousedao/ph-clint-app").SetPublishStatusAction;
|
|
45
|
+
addExternalSkill: (input: import("@powerhousedao/ph-clint-app").AddExternalSkillInput) => import("@powerhousedao/ph-clint-app").AddExternalSkillAction;
|
|
46
|
+
removeExternalSkill: (input: import("@powerhousedao/ph-clint-app").RemoveExternalSkillInput) => import("@powerhousedao/ph-clint-app").RemoveExternalSkillAction;
|
|
47
|
+
setExternalSkillName: (input: import("@powerhousedao/ph-clint-app").SetExternalSkillNameInput) => import("@powerhousedao/ph-clint-app").SetExternalSkillNameAction;
|
|
48
|
+
setExternalSkillGithubUrl: (input: import("@powerhousedao/ph-clint-app").SetExternalSkillGithubUrlInput) => import("@powerhousedao/ph-clint-app").SetExternalSkillGithubUrlAction;
|
|
49
|
+
addPowerhousePackage: (input: import("@powerhousedao/ph-clint-app").AddPowerhousePackageInput) => import("@powerhousedao/ph-clint-app").AddPowerhousePackageAction;
|
|
50
|
+
removePowerhousePackage: (input: import("@powerhousedao/ph-clint-app").RemovePowerhousePackageInput) => import("@powerhousedao/ph-clint-app").RemovePowerhousePackageAction;
|
|
51
|
+
addPackageDocumentType: (input: import("@powerhousedao/ph-clint-app").AddPackageDocumentTypeInput) => import("@powerhousedao/ph-clint-app").AddPackageDocumentTypeAction;
|
|
52
|
+
removePackageDocumentType: (input: import("@powerhousedao/ph-clint-app").RemovePackageDocumentTypeInput) => import("@powerhousedao/ph-clint-app").RemovePackageDocumentTypeAction;
|
|
53
|
+
setPackageVersion: (input: import("@powerhousedao/ph-clint-app").SetPackageVersionInput) => import("@powerhousedao/ph-clint-app").SetPackageVersionAction;
|
|
54
|
+
enableRoutine: (input: import("@powerhousedao/ph-clint-app").EnableRoutineInput) => import("@powerhousedao/ph-clint-app").EnableRoutineAction;
|
|
55
|
+
disableRoutine: (input: import("@powerhousedao/ph-clint-app").DisableRoutineInput) => import("@powerhousedao/ph-clint-app").DisableRoutineAction;
|
|
56
|
+
setPowerhouseLevel: (input: import("@powerhousedao/ph-clint-app").SetPowerhouseLevelInput) => import("@powerhousedao/ph-clint-app").SetPowerhouseLevelAction;
|
|
57
|
+
setDescription: (input: import("@powerhousedao/ph-clint-app").SetDescriptionInput) => import("@powerhousedao/ph-clint-app").SetDescriptionAction;
|
|
58
|
+
setVersion: (input: import("@powerhousedao/ph-clint-app").SetVersionInput) => import("@powerhousedao/ph-clint-app").SetVersionAction;
|
|
59
|
+
setPackageIdentifier: (input: import("@powerhousedao/ph-clint-app").SetPackageIdentifierInput) => import("@powerhousedao/ph-clint-app").SetPackageIdentifierAction;
|
|
60
|
+
setName: (name: string | {
|
|
61
|
+
name: string;
|
|
62
|
+
}) => import("document-model").SetNameAction;
|
|
63
|
+
setPreferredEditor: (input: string | null | {
|
|
64
|
+
preferredEditor: string | null;
|
|
65
|
+
}) => import("document-model").SetPreferredEditorAction;
|
|
66
|
+
undo: (count?: number, scope?: string) => import("document-model").UndoAction;
|
|
67
|
+
redo: (count?: number, scope?: string) => import("document-model").RedoAction;
|
|
68
|
+
prune: (start?: number, end?: number, scope?: string) => import("document-model").SchemaPruneAction;
|
|
69
|
+
loadState: <TState extends import("document-model").PHBaseState = import("document-model").PHBaseState>(state: TState & {
|
|
70
|
+
name: string;
|
|
71
|
+
}, operations: number) => import("document-model").LoadStateAction;
|
|
72
|
+
noop: (scope?: string) => import("document-model").NOOPAction;
|
|
73
|
+
};
|
|
74
|
+
readonly utils: import("document-model").DocumentModelUtils<import("@powerhousedao/ph-clint-app").PhClintProjectPHState>;
|
|
75
|
+
readonly documentModel: import("document-model").DocumentModelPHState;
|
|
76
|
+
}]>;
|
|
77
|
+
export type Registry = typeof registry;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THIS FILE IS GENERATED BY ph-clint-cli. DO NOT EDIT.
|
|
3
|
+
*
|
|
4
|
+
* Regenerated on every `ph-clint clint-project-regen` and on every spec-change tick.
|
|
5
|
+
* Put custom bindings in `framework.ts`, not here — edits to this file
|
|
6
|
+
* will be overwritten.
|
|
7
|
+
*/
|
|
8
|
+
import { defineRegistry } from '@powerhousedao/ph-clint';
|
|
9
|
+
import { PhClintProject } from '@powerhousedao/ph-clint-app';
|
|
10
|
+
/**
|
|
11
|
+
* Typed document registry derived from the reactor package's document models.
|
|
12
|
+
* Regenerated whenever the spec's `documentTypes` list changes.
|
|
13
|
+
*/
|
|
14
|
+
export const registry = defineRegistry([
|
|
15
|
+
PhClintProject,
|
|
16
|
+
]);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-CLI typed framework binding.
|
|
3
|
+
*
|
|
4
|
+
* This file is USER-OWNED. ph-clint-cli emits it once at project creation
|
|
5
|
+
* and never overwrites it afterwards — edit `configSchema` and
|
|
6
|
+
* `secretsSchema` freely.
|
|
7
|
+
*
|
|
8
|
+
* Typed factories (`defineCommand`, `defineTrigger`, ...) and the document
|
|
9
|
+
* `registry` come from `framework.gen.ts`, which IS regenerated whenever
|
|
10
|
+
* the spec's `documentTypes` list changes.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { createTypes } from '@powerhousedao/ph-clint';
|
|
14
|
+
import { registry } from './framework.gen.js';
|
|
15
|
+
export const configSchema = z.object({
|
|
16
|
+
model: z
|
|
17
|
+
.string()
|
|
18
|
+
.default('anthropic/claude-haiku-4-5')
|
|
19
|
+
.describe('LLM model to use'),
|
|
20
|
+
devServicePort: z
|
|
21
|
+
.number()
|
|
22
|
+
.default(3000)
|
|
23
|
+
.describe('Port reserved for the impl project (Service B) `pnpm dev`'),
|
|
24
|
+
phVersion: z
|
|
25
|
+
.string()
|
|
26
|
+
.default('latest')
|
|
27
|
+
.describe('Pinned Powerhouse version used when emitting a new impl project'),
|
|
28
|
+
});
|
|
29
|
+
export const secretsSchema = z.object({
|
|
30
|
+
apiKey: z.string().optional().describe('Anthropic API key'),
|
|
31
|
+
});
|
|
32
|
+
const fullConfigSchema = configSchema.merge(secretsSchema);
|
|
33
|
+
export const { defineCommand, defineTrigger, defineService, createDocumentChangeTrigger, } = createTypes({
|
|
34
|
+
configSchema: fullConfigSchema,
|
|
35
|
+
registry,
|
|
36
|
+
});
|
|
37
|
+
export { registry } from './framework.gen.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Agent Base System Prompt
|
|
2
|
+
|
|
3
|
+
You are PhClintDevAgent, an agent available through the CLI.
|
|
4
|
+
|
|
5
|
+
## Capabilities
|
|
6
|
+
|
|
7
|
+
This base profile is a minimal placeholder. Extend it with project-specific
|
|
8
|
+
context, workflows, and domain knowledge. Additional sections listed in the
|
|
9
|
+
agent's `sections` array are concatenated after this file at build time.
|
|
10
|
+
|
|
11
|
+
See `examples/05-ph-rupert/prompts/agent-profiles/AgentBase.md` for a more
|
|
12
|
+
complete example covering Powerhouse document system fundamentals,
|
|
13
|
+
collaboration documents (inbox, WBS), and task management guidelines.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
## API Reference: CLI Setup
|
|
2
|
+
|
|
3
|
+
### `defineCli<TSchema, TSecrets>(options): Cli`
|
|
4
|
+
|
|
5
|
+
Factory function that creates a CLI from a declarative options object. Two generic type parameters:
|
|
6
|
+
|
|
7
|
+
- `TSchema extends z.ZodType` — config schema type (defaults to `Record<string, unknown>`)
|
|
8
|
+
- `TSecrets extends z.ZodType` — secrets schema type (defaults to `Record<string, unknown>`)
|
|
9
|
+
|
|
10
|
+
### `CliOptions<TSchema, TSecrets>` Interface
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
interface CliOptions<TSchema, TSecrets> {
|
|
14
|
+
name: string; // CLI name (kebab-case, used for config files and env var prefix)
|
|
15
|
+
version: string; // Semantic version (shown in --version)
|
|
16
|
+
root?: string; // Absolute path to package root (resolves sibling packages)
|
|
17
|
+
description: Resolvable<string, Config>; // Static string or function of ({ config, workdir })
|
|
18
|
+
commands: Command<any, any, any>[]; // Array of command definitions
|
|
19
|
+
configSchema?: TSchema; // Zod schema for user-facing config
|
|
20
|
+
secretsSchema?: TSecrets; // Zod schema for sensitive config (API keys, tokens)
|
|
21
|
+
interactive?: InteractiveConfig<Config>; // REPL configuration
|
|
22
|
+
triggers?: Trigger<any, any, any>[]; // Routine loop triggers
|
|
23
|
+
routine?: RoutineConfig; // Routine loop timing & project scanner
|
|
24
|
+
services?: ServiceDefinition<Config>[]; // Background service definitions
|
|
25
|
+
events?: Record<string, (data: any, log: Logger) => void>; // Event handlers
|
|
26
|
+
workdir?: string; // Implementation-level workdir override (hides --workdir flag)
|
|
27
|
+
configDefaults?: Record<string, unknown>; // Layer 5 config defaults
|
|
28
|
+
prompts?: PromptsConfig; // Agent skills & profiles
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### `InteractiveConfig<TConfig>` Interface
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
interface InteractiveConfig<TConfig> {
|
|
36
|
+
welcome: Resolvable<string, TConfig>; // Welcome message (static or dynamic)
|
|
37
|
+
outputWindow?: number; // Trailing output lines in REPL (default: 6)
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### `Resolvable<T, TConfig>` Type
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
type Resolvable<T, TConfig> = T | ((ctx: { workdir: string; config: TConfig }) => T);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Allows static values OR dynamic computation based on resolved workdir and config.
|
|
48
|
+
|
|
49
|
+
### `Cli` Object Interface
|
|
50
|
+
|
|
51
|
+
Methods available on the object returned by `defineCli()`:
|
|
52
|
+
|
|
53
|
+
| Method | Signature | Description |
|
|
54
|
+
|--------|-----------|-------------|
|
|
55
|
+
| `run` | `(argv: string[], options?: RunOptions) => Promise<void>` | Main entry point — parse args, dispatch command or start REPL |
|
|
56
|
+
| `bootstrap` | `(opts?: BootstrapOptions) => Promise<BootstrapResult>` | Initialize runtime without dispatch — for programmatic access |
|
|
57
|
+
| `execute` | `(commandId, args, context?) => Promise<unknown>` | Execute a command directly (programmatic use) |
|
|
58
|
+
| `parseArgs` | `(commandId, argv) => Record<string, unknown>` | Parse CLI argv for a specific command |
|
|
59
|
+
| `getCommand` | `(id: string) => Command \| undefined` | Look up a registered command |
|
|
60
|
+
| `listCommands` | `() => Command[]` | List all registered commands |
|
|
61
|
+
| `generateHelp` | `() => string` | Generate CLI help text |
|
|
62
|
+
| `generateCommandHelp` | `(commandId: string) => string` | Generate help for a specific command |
|
|
63
|
+
| `generateCompletion` | `(shell: string) => string` | Generate shell completion script (bash/zsh/fish) |
|
|
64
|
+
| `configEnvVars` | `() => ConfigEnvVar[]` | List config env var mappings |
|
|
65
|
+
| `getMetadata` | `() => CliMetadata` | JSON-serializable CLI metadata |
|
|
66
|
+
| `configureAgent` | `(loader: AgentLoader<any>) => void` | Set the agent factory (lazy-loaded) |
|
|
67
|
+
| `configureReactor` | `(config: ReactorConfiguration) => void` | Set the reactor configuration (lazy-loaded) |
|
|
68
|
+
|
|
69
|
+
Properties:
|
|
70
|
+
|
|
71
|
+
| Property | Type | Description |
|
|
72
|
+
|----------|------|-------------|
|
|
73
|
+
| `name` | `string` | CLI name |
|
|
74
|
+
| `version` | `string` | CLI version |
|
|
75
|
+
| `description` | `string` | CLI description |
|
|
76
|
+
| `hasAgent` | `boolean` | True when `configureAgent()` has been called |
|
|
77
|
+
| `hasReactor` | `boolean` | True when `configureReactor()` has been called |
|
|
78
|
+
|
|
79
|
+
### `RunOptions` Interface
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
interface RunOptions {
|
|
83
|
+
exit?: (code: number) => void; // Override process.exit (for testing)
|
|
84
|
+
stdout?: (message: string) => void; // Capture stdout
|
|
85
|
+
stderr?: (message: string) => void; // Capture stderr
|
|
86
|
+
interactiveInput?: AsyncIterable<string>; // Headless REPL input (for testing)
|
|
87
|
+
resume?: string; // Resume agent conversation by thread ID
|
|
88
|
+
workdir?: string; // Override workdir (for testing)
|
|
89
|
+
configFile?: string; // --config flag value
|
|
90
|
+
logLevel?: LogLevel; // Override log verbosity (default: 'info')
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `BootstrapOptions` & `BootstrapResult`
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
interface BootstrapOptions {
|
|
98
|
+
workdir?: string; // Explicit workdir (skips flag/cwd logic)
|
|
99
|
+
configFile?: string; // Config file override
|
|
100
|
+
logLevel?: LogLevel; // Log level (default: 'info')
|
|
101
|
+
stdout?: (text: string) => void;
|
|
102
|
+
stderr?: (text: string) => void;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface BootstrapResult {
|
|
106
|
+
workdir: string;
|
|
107
|
+
config: Record<string, unknown>;
|
|
108
|
+
context: CommandContext;
|
|
109
|
+
getAgent(): Promise<AgentProvider | undefined>;
|
|
110
|
+
get mastraAgent(): Promise<unknown | undefined>;
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Built-in Commands (Auto-Injected)
|
|
115
|
+
|
|
116
|
+
| Command ID | Condition | Purpose |
|
|
117
|
+
|-----------|-----------|---------|
|
|
118
|
+
| `cli-docs` | Always | Show CLI help (also usable as agent tool) |
|
|
119
|
+
| `config` | When `configSchema` provided | View/modify configuration settings |
|
|
120
|
+
| `{service-id}-start` | Per service definition | Start a background service |
|
|
121
|
+
| `{service-id}-stop` | Per service definition | Stop a running service |
|
|
122
|
+
| `{service-id}-restart` | Per service definition | Restart a service |
|
|
123
|
+
| `{service-id}-ps` | Per service definition | Show service status |
|
|
124
|
+
| `{service-id}-logs` | Per service definition | Tail service logs |
|
|
125
|
+
| `{service-id}-manage` | Per service definition | Interactive management (REPL only) |
|
|
126
|
+
| `{service-id}-ls` | Per service + projectScanner | List discovered projects |
|
|
127
|
+
|
|
128
|
+
### `readPackageInfo(importMetaUrl)`
|
|
129
|
+
|
|
130
|
+
Utility to read name and version from the nearest `package.json`:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { readPackageInfo } from '@powerhousedao/ph-clint';
|
|
134
|
+
const { name, version } = readPackageInfo(import.meta.url);
|
|
135
|
+
```
|
|
@@ -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`
|