@bamptee/aia-code 0.3.0 → 0.4.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bamptee/aia-code",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "AI Architecture Assistant - orchestrate AI-assisted development workflows via CLI tools (Claude, Codex, Gemini)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -6,7 +6,9 @@ export function registerNextCommand(program) {
6
6
  program
7
7
  .command('next <feature> [description]')
8
8
  .description('Run the next pending step for a feature')
9
- .action(async (feature, description) => {
9
+ .option('-v, --verbose', 'Show CLI logs (thinking, tool use, etc.)')
10
+ .option('-a, --apply', 'Let the AI edit and create files in the project')
11
+ .action(async (feature, description, opts) => {
10
12
  try {
11
13
  const status = await loadStatus(feature);
12
14
  const nextStep = status.current_step;
@@ -17,7 +19,7 @@ export function registerNextCommand(program) {
17
19
  }
18
20
 
19
21
  console.log(chalk.cyan(`[next] Running step: ${nextStep}`));
20
- await runStep(nextStep, feature, { description });
22
+ await runStep(nextStep, feature, { description, verbose: opts.verbose, apply: opts.apply });
21
23
  } catch (err) {
22
24
  console.error(chalk.red(err.message));
23
25
  process.exit(1);
@@ -5,9 +5,11 @@ export function registerRunCommand(program) {
5
5
  program
6
6
  .command('run <step> <feature> [description]')
7
7
  .description('Execute a step for a feature using the configured AI model')
8
- .action(async (step, feature, description) => {
8
+ .option('-v, --verbose', 'Show CLI logs (thinking, tool use, etc.)')
9
+ .option('-a, --apply', 'Let the AI edit and create files in the project')
10
+ .action(async (step, feature, description, opts) => {
9
11
  try {
10
- await runStep(step, feature, { description });
12
+ await runStep(step, feature, { description, verbose: opts.verbose, apply: opts.apply });
11
13
  } catch (err) {
12
14
  console.error(chalk.red(err.message));
13
15
  process.exit(1);
@@ -1,11 +1,17 @@
1
1
  import { runCli } from './cli-runner.js';
2
2
 
3
- export async function generate(prompt, model) {
3
+ export async function generate(prompt, model, { verbose = false, apply = false } = {}) {
4
4
  const args = ['-p'];
5
5
  if (model) {
6
6
  args.push('--model', model);
7
7
  }
8
+ if (apply) {
9
+ args.push('--allowedTools', 'Edit', 'Write', 'Bash', 'Read', 'Glob', 'Grep');
10
+ }
11
+ if (verbose) {
12
+ args.push('--verbose');
13
+ }
8
14
  args.push('-');
9
15
 
10
- return runCli('claude', args, { stdin: prompt });
16
+ return runCli('claude', args, { stdin: prompt, verbose });
11
17
  }
@@ -1,8 +1,9 @@
1
1
  import { spawn } from 'node:child_process';
2
+ import chalk from 'chalk';
2
3
 
3
- const DEFAULT_TIMEOUT_MS = 300_000;
4
+ const DEFAULT_IDLE_TIMEOUT_MS = 180_000;
4
5
 
5
- export function runCli(command, args, { stdin: stdinData, timeoutMs = DEFAULT_TIMEOUT_MS } = {}) {
6
+ export function runCli(command, args, { stdin: stdinData, verbose = false, idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_MS } = {}) {
6
7
  return new Promise((resolve, reject) => {
7
8
  const child = spawn(command, args, {
8
9
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -11,37 +12,56 @@ export function runCli(command, args, { stdin: stdinData, timeoutMs = DEFAULT_TI
11
12
 
12
13
  const chunks = [];
13
14
  let stderr = '';
15
+ let settled = false;
16
+
17
+ function resetTimer() {
18
+ clearTimeout(timer);
19
+ timer = setTimeout(() => {
20
+ child.kill('SIGTERM');
21
+ finish(new Error(`CLI idle timeout (no output for ${idleTimeoutMs / 1000}s): ${command} ${args.join(' ')}`));
22
+ }, idleTimeoutMs);
23
+ }
24
+
25
+ function finish(err, result) {
26
+ if (settled) return;
27
+ settled = true;
28
+ clearTimeout(timer);
29
+ if (err) reject(err);
30
+ else resolve(result);
31
+ }
32
+
33
+ let timer;
34
+ resetTimer();
14
35
 
15
36
  child.stdout.on('data', (data) => {
16
37
  const text = data.toString();
17
38
  process.stdout.write(text);
18
39
  chunks.push(text);
40
+ resetTimer();
19
41
  });
20
42
 
21
43
  child.stderr.on('data', (data) => {
22
- stderr += data.toString();
44
+ const text = data.toString();
45
+ stderr += text;
46
+ if (verbose) {
47
+ process.stderr.write(chalk.gray(text));
48
+ }
49
+ resetTimer();
23
50
  });
24
51
 
25
- const timer = setTimeout(() => {
26
- child.kill('SIGTERM');
27
- reject(new Error(`CLI timed out after ${timeoutMs / 1000}s: ${command} ${args.join(' ')}`));
28
- }, timeoutMs);
29
-
30
52
  child.on('error', (err) => {
31
- clearTimeout(timer);
32
53
  if (err.code === 'ENOENT') {
33
- reject(new Error(`CLI not found: "${command}". Make sure it is installed and in your PATH.`));
54
+ finish(new Error(`CLI not found: "${command}". Make sure it is installed and in your PATH.`));
34
55
  } else {
35
- reject(err);
56
+ finish(err);
36
57
  }
37
58
  });
38
59
 
39
60
  child.on('close', (code) => {
40
- clearTimeout(timer);
41
61
  if (code !== 0) {
42
- reject(new Error(`${command} exited with code ${code}:\n${stderr.trim()}`));
62
+ finish(new Error(`${command} exited with code ${code}:\n${stderr.trim()}`));
43
63
  } else {
44
- resolve(chunks.join(''));
64
+ finish(null, chunks.join(''));
45
65
  }
46
66
  });
47
67
 
@@ -1,11 +1,14 @@
1
1
  import { runCli } from './cli-runner.js';
2
2
 
3
- export async function generate(prompt, model) {
3
+ export async function generate(prompt, model, { verbose = false, apply = false } = {}) {
4
4
  const args = [];
5
5
  if (model) {
6
6
  args.push('-m', model);
7
7
  }
8
+ if (apply) {
9
+ args.push('--sandbox', 'false');
10
+ }
8
11
  args.push('-');
9
12
 
10
- return runCli('gemini', args, { stdin: prompt });
13
+ return runCli('gemini', args, { stdin: prompt, verbose });
11
14
  }
@@ -1,11 +1,14 @@
1
1
  import { runCli } from './cli-runner.js';
2
2
 
3
- export async function generate(prompt, model) {
3
+ export async function generate(prompt, model, { verbose = false, apply = false } = {}) {
4
4
  const args = ['exec'];
5
5
  if (model) {
6
6
  args.push('-c', `model="${model}"`);
7
7
  }
8
+ if (apply) {
9
+ args.push('-c', 'approval_policy="auto-edit"');
10
+ }
8
11
  args.push('-');
9
12
 
10
- return runCli('codex', args, { stdin: prompt });
13
+ return runCli('codex', args, { stdin: prompt, verbose });
11
14
  }
@@ -1,11 +1,12 @@
1
1
  import chalk from 'chalk';
2
2
  import { resolveModelAlias } from '../providers/registry.js';
3
3
 
4
- export async function callModel(model, prompt) {
4
+ export async function callModel(model, prompt, { verbose = false, apply = false } = {}) {
5
5
  const resolved = resolveModelAlias(model);
6
6
  const displayName = resolved.model ?? `${model} (CLI default)`;
7
+ const mode = apply ? 'agent' : 'print';
7
8
 
8
- console.log(chalk.yellow(`[AI] Calling ${displayName}...`));
9
+ console.log(chalk.yellow(`[AI] Calling ${displayName} (${mode} mode)...`));
9
10
 
10
- return resolved.provider.generate(prompt, resolved.model);
11
+ return resolved.provider.generate(prompt, resolved.model, { verbose, apply });
11
12
  }
@@ -8,7 +8,7 @@ import { callModel } from './model-call.js';
8
8
  import { loadStatus, updateStepStatus } from './status.js';
9
9
  import { logExecution } from '../logger.js';
10
10
 
11
- export async function runStep(step, feature, { description, root = process.cwd() } = {}) {
11
+ export async function runStep(step, feature, { description, verbose = false, apply = false, root = process.cwd() } = {}) {
12
12
  if (!FEATURE_STEPS.includes(step)) {
13
13
  throw new Error(`Unknown step "${step}". Valid steps: ${FEATURE_STEPS.join(', ')}`);
14
14
  }
@@ -28,7 +28,7 @@ export async function runStep(step, feature, { description, root = process.cwd()
28
28
  const prompt = await buildPrompt(feature, step, { description, root });
29
29
 
30
30
  const start = performance.now();
31
- const output = await callModel(model, prompt);
31
+ const output = await callModel(model, prompt, { verbose, apply });
32
32
  const duration = performance.now() - start;
33
33
 
34
34
  const outputPath = path.join(root, AIA_DIR, 'features', feature, `${step}.md`);