@output.ai/cli 0.8.1 → 0.8.2
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/commands/agents/{init.d.ts → update.d.ts} +2 -4
- package/dist/commands/agents/update.js +29 -0
- package/dist/commands/agents/update.spec.js +84 -0
- package/dist/commands/dev/index.js +3 -0
- package/dist/commands/dev/index.spec.js +36 -0
- package/dist/services/claude_client.js +1 -1
- package/dist/services/coding_agents.d.ts +12 -12
- package/dist/services/coding_agents.js +39 -91
- package/dist/services/coding_agents.spec.js +43 -59
- package/dist/services/workflow_planner.d.ts +1 -1
- package/dist/services/workflow_planner.js +1 -1
- package/dist/services/workflow_planner.spec.js +2 -2
- package/dist/templates/agent_instructions/CLAUDE.md.template +19 -0
- package/dist/test_helpers/mocks.d.ts +1 -1
- package/dist/test_helpers/mocks.js +1 -1
- package/dist/utils/process.js +4 -2
- package/package.json +1 -1
- package/dist/commands/agents/init.js +0 -43
- package/dist/commands/agents/init.spec.js +0 -109
- package/dist/templates/agent_instructions/dotoutputai/AGENTS.md.template +0 -435
- /package/dist/commands/agents/{init.spec.d.ts → update.spec.d.ts} +0 -0
|
@@ -8,7 +8,7 @@ export declare function generatePlanName(description: string, date?: Date): Prom
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function writePlanFile(planName: string, content: string, projectRoot: string): Promise<string>;
|
|
10
10
|
/**
|
|
11
|
-
* Update agent templates by
|
|
11
|
+
* Update agent templates by reinitializing with force flag
|
|
12
12
|
* This recreates all agent configuration files, overwriting existing ones
|
|
13
13
|
* @param projectRoot - Root directory of the project
|
|
14
14
|
*/
|
|
@@ -36,7 +36,7 @@ export async function writePlanFile(planName, content, projectRoot) {
|
|
|
36
36
|
return planFilePath;
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
* Update agent templates by
|
|
39
|
+
* Update agent templates by reinitializing with force flag
|
|
40
40
|
* This recreates all agent configuration files, overwriting existing ones
|
|
41
41
|
* @param projectRoot - Root directory of the project
|
|
42
42
|
*/
|
|
@@ -98,7 +98,7 @@ describe('workflow-planner service', () => {
|
|
|
98
98
|
});
|
|
99
99
|
});
|
|
100
100
|
describe('updateAgentTemplates', () => {
|
|
101
|
-
it('should invoke
|
|
101
|
+
it('should invoke initializeAgentConfig with force flag', async () => {
|
|
102
102
|
vi.mocked(initializeAgentConfig).mockResolvedValue();
|
|
103
103
|
await updateAgentTemplates('/test/project');
|
|
104
104
|
expect(initializeAgentConfig).toHaveBeenCalledWith({
|
|
@@ -106,7 +106,7 @@ describe('workflow-planner service', () => {
|
|
|
106
106
|
force: true
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
|
-
it('should propagate errors from
|
|
109
|
+
it('should propagate errors from initializeAgentConfig', async () => {
|
|
110
110
|
vi.mocked(initializeAgentConfig).mockRejectedValue(new Error('Failed to write templates'));
|
|
111
111
|
await expect(updateAgentTemplates('/test/project'))
|
|
112
112
|
.rejects.toThrow('Failed to write templates');
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This is an **Output.ai** project - a framework for building reliable, production-ready LLM workflows and agents.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
For full framework documentation, commands, and AI-assisted workflow development, install our Claude Code plugins:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
claude plugin marketplace add growthxai/output-claude-plugins
|
|
11
|
+
claude plugin install outputai@outputai --scope project
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Project-Specific Instructions
|
|
17
|
+
|
|
18
|
+
<!-- Add your project-specific instructions below -->
|
|
19
|
+
|
|
@@ -11,7 +11,7 @@ export declare const mockLLM: {
|
|
|
11
11
|
generateText: import("vitest").Mock<(...args: any[]) => any>;
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
14
|
-
* Mock for child_process spawn (for
|
|
14
|
+
* Mock for child_process spawn (for agent commands)
|
|
15
15
|
*/
|
|
16
16
|
export declare const mockSpawn: import("vitest").Mock<(...args: any[]) => any>;
|
|
17
17
|
/**
|
package/dist/utils/process.js
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { ux } from '@oclif/core';
|
|
3
|
+
import debugFactory from 'debug';
|
|
3
4
|
import { getErrorMessage } from './error_utils.js';
|
|
5
|
+
const debug = debugFactory('output-cli:process');
|
|
4
6
|
export async function executeCommand(command, args, cwd) {
|
|
5
7
|
const stderrLines = [];
|
|
6
8
|
const proc = spawn(command, args, { cwd });
|
|
7
9
|
const handleStdout = (data) => {
|
|
8
10
|
const line = data.toString().trim();
|
|
9
11
|
if (line) {
|
|
10
|
-
|
|
12
|
+
debug(line);
|
|
11
13
|
}
|
|
12
14
|
};
|
|
13
15
|
const handleStderr = (data) => {
|
|
14
16
|
const line = data.toString().trim();
|
|
15
17
|
if (line) {
|
|
16
18
|
stderrLines.push(line);
|
|
17
|
-
|
|
19
|
+
debug(line);
|
|
18
20
|
}
|
|
19
21
|
};
|
|
20
22
|
proc.stdout.on('data', handleStdout);
|
package/package.json
CHANGED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { Command, Flags } from '@oclif/core';
|
|
2
|
-
import { initializeAgentConfig } from '#services/coding_agents.js';
|
|
3
|
-
import { getErrorMessage, getErrorCode } from '#utils/error_utils.js';
|
|
4
|
-
export default class Init extends Command {
|
|
5
|
-
static description = 'Initialize agent configuration files for Claude Code plugin integration';
|
|
6
|
-
static examples = [
|
|
7
|
-
'<%= config.bin %> <%= command.id %>',
|
|
8
|
-
'<%= config.bin %> <%= command.id %> --force'
|
|
9
|
-
];
|
|
10
|
-
static args = {};
|
|
11
|
-
static flags = {
|
|
12
|
-
force: Flags.boolean({
|
|
13
|
-
char: 'f',
|
|
14
|
-
description: 'Overwrite existing files',
|
|
15
|
-
default: false
|
|
16
|
-
})
|
|
17
|
-
};
|
|
18
|
-
async run() {
|
|
19
|
-
const { flags } = await this.parse(Init);
|
|
20
|
-
this.log('Initializing agent configuration for Claude Code...');
|
|
21
|
-
try {
|
|
22
|
-
await initializeAgentConfig({
|
|
23
|
-
projectRoot: process.cwd(),
|
|
24
|
-
force: flags.force
|
|
25
|
-
});
|
|
26
|
-
this.log('Agent configuration initialized successfully!');
|
|
27
|
-
this.log('');
|
|
28
|
-
this.log('Configured:');
|
|
29
|
-
this.log(' - Registered marketplace: growthxai/output-claude-plugins');
|
|
30
|
-
this.log(' - Updated marketplace: outputai');
|
|
31
|
-
this.log(' - Installed plugin: outputai@outputai');
|
|
32
|
-
this.log('');
|
|
33
|
-
this.log('Claude Code will automatically use the OutputAI plugin.');
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
if (getErrorCode(error) === 'EACCES') {
|
|
37
|
-
this.error('Permission denied. Please check file permissions and try again.');
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
this.error(`Failed to initialize agent configuration: ${getErrorMessage(error)}`);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
3
|
-
import Init from './init.js';
|
|
4
|
-
import { initializeAgentConfig } from '#services/coding_agents.js';
|
|
5
|
-
vi.mock('#services/coding_agents.js', () => ({
|
|
6
|
-
initializeAgentConfig: vi.fn(),
|
|
7
|
-
AGENT_CONFIGS: { 'claude-code': { id: 'claude-code' } }
|
|
8
|
-
}));
|
|
9
|
-
vi.mock('#config.js', () => ({
|
|
10
|
-
AGENT_CONFIG_DIR: '.outputai'
|
|
11
|
-
}));
|
|
12
|
-
describe('agents init', () => {
|
|
13
|
-
const createTestCommand = (args = []) => {
|
|
14
|
-
const cmd = new Init(args, {});
|
|
15
|
-
cmd.log = vi.fn();
|
|
16
|
-
cmd.warn = vi.fn();
|
|
17
|
-
cmd.error = vi.fn();
|
|
18
|
-
cmd.debug = vi.fn();
|
|
19
|
-
cmd.parse = vi.fn();
|
|
20
|
-
return cmd;
|
|
21
|
-
};
|
|
22
|
-
beforeEach(() => {
|
|
23
|
-
vi.clearAllMocks();
|
|
24
|
-
vi.mocked(initializeAgentConfig).mockResolvedValue(undefined);
|
|
25
|
-
});
|
|
26
|
-
afterEach(() => {
|
|
27
|
-
vi.restoreAllMocks();
|
|
28
|
-
});
|
|
29
|
-
describe('command structure', () => {
|
|
30
|
-
it('should have correct description', () => {
|
|
31
|
-
expect(Init.description).toBeDefined();
|
|
32
|
-
expect(Init.description).toContain('agent configuration');
|
|
33
|
-
});
|
|
34
|
-
it('should have correct examples without agent-provider flag', () => {
|
|
35
|
-
expect(Init.examples).toBeDefined();
|
|
36
|
-
expect(Array.isArray(Init.examples)).toBe(true);
|
|
37
|
-
const examplesStr = Init.examples.join(' ');
|
|
38
|
-
expect(examplesStr).not.toContain('agent-provider');
|
|
39
|
-
});
|
|
40
|
-
it('should have no required arguments', () => {
|
|
41
|
-
expect(Init.args).toBeDefined();
|
|
42
|
-
expect(Object.keys(Init.args)).toHaveLength(0);
|
|
43
|
-
});
|
|
44
|
-
it('should only have force flag', () => {
|
|
45
|
-
expect(Init.flags).toBeDefined();
|
|
46
|
-
expect(Init.flags.force).toBeDefined();
|
|
47
|
-
expect(Object.keys(Init.flags)).toHaveLength(1);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
describe('successful execution', () => {
|
|
51
|
-
it('should call initializeAgentConfig with correct options', async () => {
|
|
52
|
-
const cmd = createTestCommand();
|
|
53
|
-
cmd.parse.mockResolvedValue({ flags: { force: false }, args: {} });
|
|
54
|
-
await cmd.run();
|
|
55
|
-
expect(initializeAgentConfig).toHaveBeenCalledWith({
|
|
56
|
-
projectRoot: expect.any(String),
|
|
57
|
-
force: false
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
it('should pass force flag to initializeAgentConfig', async () => {
|
|
61
|
-
const cmd = createTestCommand(['--force']);
|
|
62
|
-
cmd.parse.mockResolvedValue({ flags: { force: true }, args: {} });
|
|
63
|
-
await cmd.run();
|
|
64
|
-
expect(initializeAgentConfig).toHaveBeenCalledWith({
|
|
65
|
-
projectRoot: expect.any(String),
|
|
66
|
-
force: true
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
it('should display success messages', async () => {
|
|
70
|
-
const cmd = createTestCommand();
|
|
71
|
-
cmd.parse.mockResolvedValue({ flags: { force: false }, args: {} });
|
|
72
|
-
await cmd.run();
|
|
73
|
-
expect(cmd.log).toHaveBeenCalledWith(expect.stringContaining('initialized successfully'));
|
|
74
|
-
expect(cmd.log).toHaveBeenCalledWith('Configured:');
|
|
75
|
-
expect(cmd.log).toHaveBeenCalledWith(expect.stringContaining('OutputAI plugin'));
|
|
76
|
-
});
|
|
77
|
-
it('should display plugin configuration messages', async () => {
|
|
78
|
-
const cmd = createTestCommand();
|
|
79
|
-
cmd.parse.mockResolvedValue({ flags: { force: false }, args: {} });
|
|
80
|
-
await cmd.run();
|
|
81
|
-
expect(cmd.log).toHaveBeenCalledWith(expect.stringContaining('marketplace'));
|
|
82
|
-
expect(cmd.log).toHaveBeenCalledWith(expect.stringContaining('plugin'));
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
describe('error handling', () => {
|
|
86
|
-
it('should handle permission errors', async () => {
|
|
87
|
-
vi.mocked(initializeAgentConfig).mockRejectedValue({ code: 'EACCES' });
|
|
88
|
-
const cmd = createTestCommand();
|
|
89
|
-
cmd.parse.mockResolvedValue({ flags: { force: false }, args: {} });
|
|
90
|
-
await cmd.run();
|
|
91
|
-
expect(cmd.error).toHaveBeenCalledWith(expect.stringContaining('Permission denied'));
|
|
92
|
-
});
|
|
93
|
-
it('should handle general errors with message', async () => {
|
|
94
|
-
vi.mocked(initializeAgentConfig).mockRejectedValue(new Error('Something went wrong'));
|
|
95
|
-
const cmd = createTestCommand();
|
|
96
|
-
cmd.parse.mockResolvedValue({ flags: { force: false }, args: {} });
|
|
97
|
-
await cmd.run();
|
|
98
|
-
expect(cmd.error).toHaveBeenCalledWith(expect.stringContaining('Failed to initialize agent configuration'));
|
|
99
|
-
expect(cmd.error).toHaveBeenCalledWith(expect.stringContaining('Something went wrong'));
|
|
100
|
-
});
|
|
101
|
-
it('should handle Claude CLI not found error', async () => {
|
|
102
|
-
vi.mocked(initializeAgentConfig).mockRejectedValue(new Error('Claude CLI not found. Please install Claude Code CLI and ensure \'claude\' is in your PATH.'));
|
|
103
|
-
const cmd = createTestCommand();
|
|
104
|
-
cmd.parse.mockResolvedValue({ flags: { force: false }, args: {} });
|
|
105
|
-
await cmd.run();
|
|
106
|
-
expect(cmd.error).toHaveBeenCalledWith(expect.stringContaining('Claude CLI not found'));
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
});
|