brainctl 0.1.0

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 (44) hide show
  1. package/README.md +242 -0
  2. package/dist/cli.d.ts +14 -0
  3. package/dist/cli.js +52 -0
  4. package/dist/commands/doctor.d.ts +3 -0
  5. package/dist/commands/doctor.js +13 -0
  6. package/dist/commands/init.d.ts +3 -0
  7. package/dist/commands/init.js +27 -0
  8. package/dist/commands/run.d.ts +3 -0
  9. package/dist/commands/run.js +25 -0
  10. package/dist/commands/status.d.ts +3 -0
  11. package/dist/commands/status.js +18 -0
  12. package/dist/config.d.ts +6 -0
  13. package/dist/config.js +78 -0
  14. package/dist/context/builder.d.ts +6 -0
  15. package/dist/context/builder.js +13 -0
  16. package/dist/context/memory.d.ts +5 -0
  17. package/dist/context/memory.js +38 -0
  18. package/dist/context/skills.d.ts +2 -0
  19. package/dist/context/skills.js +8 -0
  20. package/dist/errors.d.ts +27 -0
  21. package/dist/errors.js +45 -0
  22. package/dist/executor/claude.d.ts +5 -0
  23. package/dist/executor/claude.js +12 -0
  24. package/dist/executor/codex.d.ts +5 -0
  25. package/dist/executor/codex.js +12 -0
  26. package/dist/executor/process.d.ts +10 -0
  27. package/dist/executor/process.js +38 -0
  28. package/dist/executor/resolver.d.ts +13 -0
  29. package/dist/executor/resolver.js +94 -0
  30. package/dist/executor/types.d.ts +13 -0
  31. package/dist/executor/types.js +1 -0
  32. package/dist/output.d.ts +4 -0
  33. package/dist/output.js +25 -0
  34. package/dist/services/doctor-service.d.ts +14 -0
  35. package/dist/services/doctor-service.js +79 -0
  36. package/dist/services/init-service.d.ts +14 -0
  37. package/dist/services/init-service.js +88 -0
  38. package/dist/services/run-service.d.ts +11 -0
  39. package/dist/services/run-service.js +93 -0
  40. package/dist/services/status-service.d.ts +17 -0
  41. package/dist/services/status-service.js +21 -0
  42. package/dist/types.d.ts +53 -0
  43. package/dist/types.js +1 -0
  44. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,242 @@
1
+ # 🧠 brainctl
2
+
3
+ > Stop reconfiguring your AI tools.
4
+
5
+ `brainctl` is a CLI for managing a portable AI environment across tools like Claude Code and Codex.
6
+
7
+ Define your memory, skills, and execution flow once, then reuse them across different AI agents.
8
+
9
+ ---
10
+
11
+ ## ✨ Why brainctl?
12
+
13
+ If you're using multiple AI tools, you've probably already hit the same problems:
14
+
15
+ - Rewriting the same prompt for different agents
16
+ - Losing context between tools
17
+ - Rebuilding your environment every time you switch
18
+
19
+ `brainctl` solves that with one core idea:
20
+
21
+ > **One AI setup. Multiple agents.**
22
+
23
+ ---
24
+
25
+ ## 🚀 Features
26
+
27
+ - 🧠 File-based memory from Markdown files
28
+ - 🧩 Reusable skills stored in `ai-stack.yaml`
29
+ - 🔌 Multi-agent execution with Claude and Codex
30
+ - ⚙️ Unified context builder
31
+ - 🛠 CLI-first workflow
32
+ - 🔍 `status` and `doctor` for visibility
33
+ - 🔁 Optional fallback agent support with `--fallback`
34
+
35
+ ---
36
+
37
+ ## 📦 Installation
38
+
39
+ ### Option 1: Install from npm
40
+
41
+ ```bash
42
+ npm install -g brainctl
43
+ ```
44
+
45
+ Then:
46
+
47
+ ```bash
48
+ brainctl --help
49
+ ```
50
+
51
+ ### Option 2: Local CLI install from source
52
+
53
+ ```bash
54
+ npm install
55
+ npm run build
56
+ npm link
57
+ ```
58
+
59
+ Then:
60
+
61
+ ```bash
62
+ brainctl --help
63
+ ```
64
+
65
+ ### Option 3: Run without linking
66
+
67
+ ```bash
68
+ npm install
69
+ npm run build
70
+ node dist/cli.js --help
71
+ ```
72
+
73
+ `brainctl` does not bundle agent CLIs. You still need at least one supported agent installed separately and available on `PATH`, such as `claude` or `codex`.
74
+
75
+ ---
76
+
77
+ ## ⚡ Quick Start
78
+
79
+ ### 1. Initialize a project
80
+
81
+ ```bash
82
+ brainctl init
83
+ ```
84
+
85
+ This creates:
86
+
87
+ - `ai-stack.yaml`
88
+ - `memory/`
89
+ - `memory/notes.md`
90
+
91
+ ### 2. Inspect the setup
92
+
93
+ ```bash
94
+ brainctl status
95
+ brainctl doctor
96
+ ```
97
+
98
+ ### 3. Run a task
99
+
100
+ ```bash
101
+ brainctl run summarize ./memory/notes.md --with claude
102
+ ```
103
+
104
+ Or:
105
+
106
+ ```bash
107
+ brainctl run summarize ./memory/notes.md --with codex
108
+ ```
109
+
110
+ With fallback:
111
+
112
+ ```bash
113
+ brainctl run summarize ./memory/notes.md --with claude --fallback codex
114
+ ```
115
+
116
+ ---
117
+
118
+ ## 🧠 Example `ai-stack.yaml`
119
+
120
+ ```yaml
121
+ memory:
122
+ paths:
123
+ - ./memory
124
+
125
+ skills:
126
+ summarize:
127
+ description: Summarize content
128
+ prompt: |
129
+ Summarize the following content into concise bullet points.
130
+
131
+ analyze:
132
+ description: Analyze content deeply
133
+ prompt: |
134
+ Analyze the following content and extract key insights.
135
+
136
+ mcps: {}
137
+ ```
138
+
139
+ ---
140
+
141
+ ## 🧩 How It Works
142
+
143
+ `brainctl` builds a unified context before calling an agent:
144
+
145
+ ```text
146
+ --- MEMORY ---
147
+ [your markdown files]
148
+
149
+ --- SKILL ---
150
+ [prompt template]
151
+
152
+ --- INPUT ---
153
+ [your file]
154
+ ```
155
+
156
+ That context is then sent to the selected agent over stdin.
157
+
158
+ ---
159
+
160
+ ## 🛠 Usage
161
+
162
+ ### Commands
163
+
164
+ | Command | Purpose |
165
+ | --- | --- |
166
+ | `brainctl init` | Initialize `ai-stack.yaml` and memory files |
167
+ | `brainctl status` | Show memory, skills, MCP count, and agent availability |
168
+ | `brainctl doctor` | Validate config, memory paths, skills, and installed agents |
169
+ | `brainctl run <skill> <file> --with <agent>` | Build context and execute with an agent |
170
+
171
+ ### Examples
172
+
173
+ ```bash
174
+ brainctl run summarize ./memory/notes.md --with claude
175
+ brainctl run analyze ./memory/notes.md --with codex
176
+ brainctl run summarize ./memory/notes.md --with claude --fallback codex
177
+ ```
178
+
179
+ ---
180
+
181
+ ## 📂 Project Structure
182
+
183
+ ```text
184
+ brainctl/
185
+ ├── src/
186
+ │ ├── cli.ts
187
+ │ ├── config.ts
188
+ │ ├── context/
189
+ │ ├── commands/
190
+ │ ├── executor/
191
+ │ └── services/
192
+ ├── tests/
193
+ ├── ai-stack.yaml
194
+ ├── memory/
195
+ ├── package.json
196
+ └── tsconfig.json
197
+ ```
198
+
199
+ ---
200
+
201
+ ## 🧪 Development
202
+
203
+ ```bash
204
+ npm install
205
+ npm test
206
+ npm run build
207
+ ```
208
+
209
+ ---
210
+
211
+ ## 🧠 Philosophy
212
+
213
+ `brainctl` does not replace your AI tools.
214
+
215
+ It sits between you and them as a thin orchestration layer:
216
+
217
+ - You keep using Claude, Codex, and other agent CLIs
218
+ - `brainctl` keeps the environment consistent
219
+
220
+ ---
221
+
222
+ ## 🗺 Roadmap
223
+
224
+ - [ ] JSON output mode
225
+ - [ ] Multi-agent pipelines
226
+ - [ ] MCP runtime integration
227
+ - [ ] Better execution tracing and logs
228
+ - [ ] UI / dashboard
229
+
230
+ ---
231
+
232
+ ## 💡 Inspiration
233
+
234
+ AI tools are getting more powerful, but also more fragmented.
235
+
236
+ `brainctl` is an attempt to bring state, structure, and consistency to that workflow.
237
+
238
+ ---
239
+
240
+ ## 📄 License
241
+
242
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { type DoctorService } from './services/doctor-service.js';
4
+ import { type InitService } from './services/init-service.js';
5
+ import { type RunService } from './services/run-service.js';
6
+ import { type StatusService } from './services/status-service.js';
7
+ export interface CliServices {
8
+ initService: InitService;
9
+ runService: RunService;
10
+ statusService: StatusService;
11
+ doctorService: DoctorService;
12
+ }
13
+ export declare function createProgram(overrides?: Partial<CliServices>): Command;
14
+ export declare function main(argv?: string[]): Promise<void>;
package/dist/cli.js ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { Command } from 'commander';
5
+ import { registerDoctorCommand } from './commands/doctor.js';
6
+ import { registerInitCommand } from './commands/init.js';
7
+ import { registerRunCommand } from './commands/run.js';
8
+ import { registerStatusCommand } from './commands/status.js';
9
+ import { printError } from './output.js';
10
+ import { createDoctorService } from './services/doctor-service.js';
11
+ import { createInitService } from './services/init-service.js';
12
+ import { createRunService } from './services/run-service.js';
13
+ import { createStatusService } from './services/status-service.js';
14
+ import { createExecutorResolver } from './executor/resolver.js';
15
+ export function createProgram(overrides = {}) {
16
+ const services = createDefaultServices(overrides);
17
+ const program = new Command();
18
+ program
19
+ .name('brainctl')
20
+ .description('Manage repeatable AI environments for local agent workflows')
21
+ .version('0.1.0');
22
+ registerInitCommand(program, services.initService);
23
+ registerStatusCommand(program, services.statusService);
24
+ registerRunCommand(program, services.runService);
25
+ registerDoctorCommand(program, services.doctorService);
26
+ return program;
27
+ }
28
+ export async function main(argv = process.argv) {
29
+ const program = createProgram();
30
+ try {
31
+ await program.parseAsync(argv);
32
+ }
33
+ catch (error) {
34
+ printError(error);
35
+ process.exitCode = 1;
36
+ }
37
+ }
38
+ function createDefaultServices(overrides) {
39
+ const resolver = createExecutorResolver();
40
+ return {
41
+ initService: createInitService(),
42
+ runService: createRunService({ resolver }),
43
+ statusService: createStatusService({ resolver }),
44
+ doctorService: createDoctorService({ resolver }),
45
+ ...overrides
46
+ };
47
+ }
48
+ const entryPointPath = process.argv[1] ? path.resolve(process.argv[1]) : '';
49
+ const currentFilePath = fileURLToPath(import.meta.url);
50
+ if (entryPointPath === currentFilePath) {
51
+ void main();
52
+ }
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { DoctorService } from '../services/doctor-service.js';
3
+ export declare function registerDoctorCommand(program: Command, doctorService: DoctorService): void;
@@ -0,0 +1,13 @@
1
+ import { formatDiagnosticStatus } from '../output.js';
2
+ export function registerDoctorCommand(program, doctorService) {
3
+ program
4
+ .command('doctor')
5
+ .description('Validate the local brainctl setup')
6
+ .action(async () => {
7
+ const result = await doctorService.execute({ cwd: process.cwd() });
8
+ for (const check of result.checks) {
9
+ console.log(`${formatDiagnosticStatus(check.status)} ${check.label}: ${check.message}`);
10
+ }
11
+ process.exitCode = result.hasIssues ? 1 : 0;
12
+ });
13
+ }
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { InitService } from '../services/init-service.js';
3
+ export declare function registerInitCommand(program: Command, initService: InitService): void;
@@ -0,0 +1,27 @@
1
+ import pc from 'picocolors';
2
+ export function registerInitCommand(program, initService) {
3
+ program
4
+ .command('init')
5
+ .description('Initialize brainctl in the current directory')
6
+ .option('--force', 'Overwrite existing scaffolded files')
7
+ .action(async (options) => {
8
+ const result = await initService.execute({
9
+ cwd: process.cwd(),
10
+ force: options.force
11
+ });
12
+ if (result.alreadyInitialized) {
13
+ console.log('brainctl is already initialized in this directory');
14
+ console.log('Use --force to overwrite existing files.');
15
+ return;
16
+ }
17
+ for (const item of result.created) {
18
+ console.log(pc.green(`created ${item}`));
19
+ }
20
+ for (const item of result.replaced) {
21
+ console.log(pc.yellow(`replaced ${item}`));
22
+ }
23
+ if (result.created.length === 0 && result.replaced.length === 0) {
24
+ console.log('No changes were required.');
25
+ }
26
+ });
27
+ }
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { RunService } from '../services/run-service.js';
3
+ export declare function registerRunCommand(program: Command, runService: RunService): void;
@@ -0,0 +1,25 @@
1
+ export function registerRunCommand(program, runService) {
2
+ program
3
+ .command('run')
4
+ .description('Run a file through a configured skill and AI agent')
5
+ .argument('<skill>', 'Skill name from ai-stack.yaml')
6
+ .argument('<file>', 'Input file to send to the agent')
7
+ .requiredOption('--with <agent>', 'Primary agent to run', validateAgentName)
8
+ .option('--fallback <agent>', 'Fallback agent if the primary agent is unavailable', validateAgentName)
9
+ .action(async (skill, inputFile, options) => {
10
+ const trace = await runService.execute({
11
+ cwd: process.cwd(),
12
+ skill,
13
+ inputFile,
14
+ primaryAgent: options.with,
15
+ fallbackAgent: options.fallback
16
+ });
17
+ process.exitCode = trace.finalExitCode;
18
+ });
19
+ }
20
+ function validateAgentName(value) {
21
+ if (value !== 'claude' && value !== 'codex') {
22
+ throw new Error(`Unsupported agent: ${value}`);
23
+ }
24
+ return value;
25
+ }
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { StatusService } from '../services/status-service.js';
3
+ export declare function registerStatusCommand(program: Command, statusService: StatusService): void;
@@ -0,0 +1,18 @@
1
+ import pc from 'picocolors';
2
+ export function registerStatusCommand(program, statusService) {
3
+ program
4
+ .command('status')
5
+ .description('Show current brainctl configuration status')
6
+ .action(async () => {
7
+ const status = await statusService.execute({ cwd: process.cwd() });
8
+ console.log(pc.bold('brainctl status'));
9
+ console.log(`Config: ${status.configPath}`);
10
+ console.log(`Memory files loaded: ${status.memory.count}`);
11
+ console.log(`Available skills: ${status.skills.length > 0 ? status.skills.join(', ') : 'none'}`);
12
+ console.log(`MCP count: ${status.mcpCount}`);
13
+ console.log('Available agents:');
14
+ for (const agent of Object.values(status.agents)) {
15
+ console.log(`- ${agent.agent}: ${agent.available ? pc.green('available') : pc.yellow('missing')}`);
16
+ }
17
+ });
18
+ }
@@ -0,0 +1,6 @@
1
+ import type { BrainctlConfig } from './types.js';
2
+ interface LoadConfigOptions {
3
+ cwd?: string;
4
+ }
5
+ export declare function loadConfig(options?: LoadConfigOptions): Promise<BrainctlConfig>;
6
+ export {};
package/dist/config.js ADDED
@@ -0,0 +1,78 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import YAML from 'yaml';
4
+ import { ConfigError } from './errors.js';
5
+ export async function loadConfig(options = {}) {
6
+ const cwd = options.cwd ?? process.cwd();
7
+ const configPath = path.join(cwd, 'ai-stack.yaml');
8
+ let source;
9
+ try {
10
+ source = await readFile(configPath, 'utf8');
11
+ }
12
+ catch (error) {
13
+ throw new ConfigError(`Could not read ai-stack.yaml in ${cwd}.`);
14
+ }
15
+ let parsed;
16
+ try {
17
+ parsed = (YAML.parse(source) ?? {});
18
+ }
19
+ catch (error) {
20
+ throw new ConfigError('ai-stack.yaml could not be parsed.');
21
+ }
22
+ if (!parsed.memory || !Array.isArray(parsed.memory.paths)) {
23
+ throw new ConfigError('ai-stack.yaml is missing the required "memory.paths" section.');
24
+ }
25
+ if (!parsed.skills || typeof parsed.skills !== 'object' || Array.isArray(parsed.skills)) {
26
+ throw new ConfigError('ai-stack.yaml is missing the required "skills" section.');
27
+ }
28
+ const skills = normalizeSkills(parsed.skills);
29
+ return {
30
+ configPath,
31
+ rootDir: cwd,
32
+ memory: {
33
+ paths: parsed.memory.paths.map((memoryPath) => {
34
+ if (typeof memoryPath !== 'string' || memoryPath.trim().length === 0) {
35
+ throw new ConfigError('ai-stack.yaml contains an invalid memory path.');
36
+ }
37
+ return path.resolve(cwd, memoryPath);
38
+ })
39
+ },
40
+ skills,
41
+ mcps: normalizeMcps(parsed.mcps)
42
+ };
43
+ }
44
+ function normalizeSkills(value) {
45
+ const entries = Object.entries(value);
46
+ if (entries.length === 0) {
47
+ throw new ConfigError('ai-stack.yaml must define at least one skill.');
48
+ }
49
+ return Object.fromEntries(entries.map(([name, skillValue]) => {
50
+ if (!skillValue || typeof skillValue !== 'object' || Array.isArray(skillValue)) {
51
+ throw new ConfigError(`Skill "${name}" must be an object with a prompt.`);
52
+ }
53
+ const prompt = skillValue.prompt;
54
+ const description = skillValue.description;
55
+ if (typeof prompt !== 'string' || prompt.trim().length === 0) {
56
+ throw new ConfigError(`Skill "${name}" is missing a valid prompt.`);
57
+ }
58
+ if (description !== undefined && typeof description !== 'string') {
59
+ throw new ConfigError(`Skill "${name}" has an invalid description.`);
60
+ }
61
+ return [
62
+ name,
63
+ {
64
+ prompt,
65
+ description
66
+ }
67
+ ];
68
+ }));
69
+ }
70
+ function normalizeMcps(value) {
71
+ if (value === null || value === undefined) {
72
+ return {};
73
+ }
74
+ if (typeof value !== 'object' || Array.isArray(value)) {
75
+ throw new ConfigError('The "mcps" section must be an object when present.');
76
+ }
77
+ return value;
78
+ }
@@ -0,0 +1,6 @@
1
+ export interface BuildContextInput {
2
+ memory: string;
3
+ skill: string;
4
+ input: string;
5
+ }
6
+ export declare function buildContext({ memory, skill, input }: BuildContextInput): string;
@@ -0,0 +1,13 @@
1
+ export function buildContext({ memory, skill, input }) {
2
+ const sections = [memory, skill, input].map((value) => value.replace(/\n+$/, ''));
3
+ return [
4
+ '--- MEMORY ---',
5
+ sections[0],
6
+ '',
7
+ '--- SKILL ---',
8
+ sections[1],
9
+ '',
10
+ '--- INPUT ---',
11
+ sections[2]
12
+ ].join('\n');
13
+ }
@@ -0,0 +1,5 @@
1
+ import type { MemoryLoadResult } from '../types.js';
2
+ export interface LoadMemoryOptions {
3
+ paths: string[];
4
+ }
5
+ export declare function loadMemory(options: LoadMemoryOptions): Promise<MemoryLoadResult>;
@@ -0,0 +1,38 @@
1
+ import { readdir, readFile, stat } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { MemoryPathError } from '../errors.js';
4
+ export async function loadMemory(options) {
5
+ const markdownFiles = (await Promise.all(options.paths.map(async (memoryPath) => collectMarkdownFiles(memoryPath))))
6
+ .flat()
7
+ .sort((left, right) => left.localeCompare(right));
8
+ const contents = await Promise.all(markdownFiles.map(async (filePath) => (await readFile(filePath, 'utf8')).trim()));
9
+ return {
10
+ files: markdownFiles,
11
+ count: markdownFiles.length,
12
+ content: contents.filter((entry) => entry.length > 0).join('\n\n')
13
+ };
14
+ }
15
+ async function collectMarkdownFiles(targetPath) {
16
+ let targetStats;
17
+ try {
18
+ targetStats = await stat(targetPath);
19
+ }
20
+ catch (error) {
21
+ throw new MemoryPathError(`Memory path does not exist: ${targetPath}`);
22
+ }
23
+ if (!targetStats.isDirectory()) {
24
+ throw new MemoryPathError(`Memory path is not a directory: ${targetPath}`);
25
+ }
26
+ const entries = await readdir(targetPath, { withFileTypes: true });
27
+ const nestedResults = await Promise.all(entries.map(async (entry) => {
28
+ const entryPath = path.join(targetPath, entry.name);
29
+ if (entry.isDirectory()) {
30
+ return collectMarkdownFiles(entryPath);
31
+ }
32
+ if (entry.isFile() && path.extname(entry.name).toLowerCase() === '.md') {
33
+ return [entryPath];
34
+ }
35
+ return [];
36
+ }));
37
+ return nestedResults.flat();
38
+ }
@@ -0,0 +1,2 @@
1
+ import type { BrainctlConfig } from '../types.js';
2
+ export declare function resolveSkillPrompt(config: BrainctlConfig, skillName: string): string;
@@ -0,0 +1,8 @@
1
+ import { SkillNotFoundError } from '../errors.js';
2
+ export function resolveSkillPrompt(config, skillName) {
3
+ const skill = config.skills[skillName];
4
+ if (!skill) {
5
+ throw new SkillNotFoundError(`Skill "${skillName}" is not defined in ai-stack.yaml.`);
6
+ }
7
+ return skill.prompt;
8
+ }
@@ -0,0 +1,27 @@
1
+ import type { ErrorCategory } from './types.js';
2
+ export declare class BrainctlError extends Error {
3
+ readonly category: ErrorCategory;
4
+ readonly code: string;
5
+ constructor(message: string, category: ErrorCategory, code: string);
6
+ }
7
+ export declare class ConfigError extends BrainctlError {
8
+ constructor(message: string);
9
+ }
10
+ export declare class ValidationError extends BrainctlError {
11
+ constructor(message: string);
12
+ }
13
+ export declare class MemoryPathError extends BrainctlError {
14
+ constructor(message: string);
15
+ }
16
+ export declare class SkillNotFoundError extends BrainctlError {
17
+ constructor(message: string);
18
+ }
19
+ export declare class InputFileError extends BrainctlError {
20
+ constructor(message: string);
21
+ }
22
+ export declare class AgentNotAvailableError extends BrainctlError {
23
+ constructor(message: string);
24
+ }
25
+ export declare class ExecutionError extends BrainctlError {
26
+ constructor(message: string);
27
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,45 @@
1
+ export class BrainctlError extends Error {
2
+ category;
3
+ code;
4
+ constructor(message, category, code) {
5
+ super(message);
6
+ this.name = new.target.name;
7
+ this.category = category;
8
+ this.code = code;
9
+ }
10
+ }
11
+ export class ConfigError extends BrainctlError {
12
+ constructor(message) {
13
+ super(message, 'user', 'CONFIG_ERROR');
14
+ }
15
+ }
16
+ export class ValidationError extends BrainctlError {
17
+ constructor(message) {
18
+ super(message, 'user', 'VALIDATION_ERROR');
19
+ }
20
+ }
21
+ export class MemoryPathError extends BrainctlError {
22
+ constructor(message) {
23
+ super(message, 'user', 'MEMORY_PATH_ERROR');
24
+ }
25
+ }
26
+ export class SkillNotFoundError extends BrainctlError {
27
+ constructor(message) {
28
+ super(message, 'user', 'SKILL_NOT_FOUND');
29
+ }
30
+ }
31
+ export class InputFileError extends BrainctlError {
32
+ constructor(message) {
33
+ super(message, 'user', 'INPUT_FILE_ERROR');
34
+ }
35
+ }
36
+ export class AgentNotAvailableError extends BrainctlError {
37
+ constructor(message) {
38
+ super(message, 'user', 'AGENT_NOT_AVAILABLE');
39
+ }
40
+ }
41
+ export class ExecutionError extends BrainctlError {
42
+ constructor(message) {
43
+ super(message, 'system', 'EXECUTION_ERROR');
44
+ }
45
+ }
@@ -0,0 +1,5 @@
1
+ import type { Executor, ExecutorRunOptions, ExecutorResult } from './types.js';
2
+ export declare class ClaudeExecutor implements Executor {
3
+ readonly agent: "claude";
4
+ run(context: string, options?: ExecutorRunOptions): Promise<ExecutorResult>;
5
+ }
@@ -0,0 +1,12 @@
1
+ import { runAgentProcess } from './process.js';
2
+ export class ClaudeExecutor {
3
+ agent = 'claude';
4
+ async run(context, options) {
5
+ return await runAgentProcess({
6
+ command: 'claude',
7
+ agent: this.agent,
8
+ context,
9
+ runOptions: options
10
+ });
11
+ }
12
+ }