aiki-cli 0.2.1 → 0.3.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 (60) hide show
  1. package/CHANGELOG.md +99 -7
  2. package/README.md +109 -30
  3. package/dist/bench/arms.js +10 -9
  4. package/dist/bench/harness.js +13 -10
  5. package/dist/bench/idea-lane-rotation.js +237 -0
  6. package/dist/bench/idea-v3-bench.js +506 -0
  7. package/dist/bench/idea-v3-rating.js +582 -0
  8. package/dist/bench/results.js +10 -3
  9. package/dist/bench/scoring/decision-insights.js +112 -0
  10. package/dist/bench/scoring/seeded-bugs.js +4 -0
  11. package/dist/cli/bench.js +180 -3
  12. package/dist/cli/doctor.js +56 -24
  13. package/dist/cli/index.js +32 -7
  14. package/dist/cli/resolve.js +7 -6
  15. package/dist/cli/resume.js +18 -0
  16. package/dist/cli/run.js +63 -8
  17. package/dist/cli/version.js +8 -0
  18. package/dist/council/view.js +378 -109
  19. package/dist/orchestration/calculations.js +97 -0
  20. package/dist/orchestration/context.js +37 -9
  21. package/dist/orchestration/decision-dossier.js +262 -0
  22. package/dist/orchestration/decision-graph.js +256 -0
  23. package/dist/orchestration/engine.js +5 -2
  24. package/dist/orchestration/evidence-pack.js +46 -0
  25. package/dist/orchestration/idea-lanes.js +20 -0
  26. package/dist/orchestration/jsonStage.js +72 -0
  27. package/dist/orchestration/legacy-idea-adapter.js +102 -0
  28. package/dist/orchestration/modes.js +33 -0
  29. package/dist/orchestration/preflight.js +183 -0
  30. package/dist/orchestration/quick-analysis.js +81 -0
  31. package/dist/orchestration/stages/cr-ladder.js +80 -0
  32. package/dist/orchestration/stages/s10-render.js +562 -150
  33. package/dist/orchestration/stages/s4-analyze.js +12 -7
  34. package/dist/orchestration/stages/s5-drift.js +9 -9
  35. package/dist/orchestration/stages/s6-positions.js +10 -0
  36. package/dist/orchestration/stages/s7-decision-graph.js +76 -0
  37. package/dist/orchestration/stages/s8-verify.js +153 -46
  38. package/dist/orchestration/stages/s8b-rebuttal.js +208 -0
  39. package/dist/orchestration/stages/s9-judge.js +329 -108
  40. package/dist/orchestration/stages/s9b-plan.js +85 -75
  41. package/dist/providers/codex.js +2 -1
  42. package/dist/providers/spawn.js +5 -0
  43. package/dist/schemas/index.js +572 -13
  44. package/dist/skills/idea-refinement/analyst.md +18 -14
  45. package/dist/skills/idea-refinement/economics-delivery.md +7 -0
  46. package/dist/skills/idea-refinement/market-adoption.md +7 -0
  47. package/dist/storage/runs.js +11 -4
  48. package/dist/tui/app.js +37 -13
  49. package/dist/tui/format.js +4 -5
  50. package/dist/tui/smart-entry.js +17 -1
  51. package/dist/tui/timeline.js +2 -4
  52. package/dist/workflows/code-review.js +4 -2
  53. package/dist/workflows/idea-refinement.js +110 -46
  54. package/package.json +12 -4
  55. package/dist/orchestration/stages/s0-grill.js +0 -79
  56. package/dist/orchestration/stages/s1-intent.js +0 -25
  57. package/dist/orchestration/stages/s2-misread.js +0 -76
  58. package/dist/orchestration/stages/s3-prompts.js +0 -55
  59. package/dist/orchestration/stages/s6-claims.js +0 -56
  60. package/dist/orchestration/stages/s7-disagreement.js +0 -134
package/dist/cli/run.js CHANGED
@@ -1,19 +1,29 @@
1
1
  // `aiki run <workflow> [input]` (§5) — headless run. idea-refinement takes inline text or a file path;
2
2
  // code-review computes a git diff from --base/--head (or reads --diff) and reviews it at the repo root.
3
3
  import { readFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
4
5
  import { createInterface } from 'node:readline';
6
+ import { renderTerminalSummary } from '../orchestration/stages/s10-render.js';
5
7
  import { run as runEngine } from '../orchestration/engine.js';
6
8
  import { ConfigError, loadLayeredConfig } from '../config/config.js';
7
9
  import { computeDiff, detectDefaultBranch, GitError, repoToplevel } from '../orchestration/git.js';
8
10
  import { resolveRunsRoot } from '../storage/paths.js';
9
11
  import { openCouncilHtml } from '../council/open.js';
12
+ import { buildEvidencePack } from '../orchestration/evidence-pack.js';
13
+ import { IdeaModeSchema } from '../schemas/index.js';
14
+ import { defaultBudgetFor, defaultDeadlineFor, IDEA_MODE_PLANS } from '../orchestration/modes.js';
10
15
  const WORKFLOWS = ['idea-refinement', 'code-review'];
11
- /** Rough provider-call estimate for the run-cost preview (V5). Approximate — the real count varies with
12
- * §14 repairs, cross-exam skips, and quorum. `opus` = the Claude/Opus subset (the metered-cost driver). */
13
16
  export function estimateRun(workflow, opts = {}) {
14
17
  if (workflow === 'code-review')
15
18
  return { calls: 5, opus: opts.cheap ? 1 : 2 };
16
- return { calls: 12, opus: 4 }; // idea-refinement (S0/S1/S3 on agy; S2 has claude; S7 + S9 + S9b run on the claude judge)
19
+ const mode = opts.mode ?? 'council';
20
+ const plan = IDEA_MODE_PLANS[mode];
21
+ return {
22
+ calls: plan.maxCalls,
23
+ opus: mode === 'quick' ? 1 : 2,
24
+ minCalls: mode === 'research' ? 8 : plan.baseCalls,
25
+ reserved: plan.reservedCalls,
26
+ };
17
27
  }
18
28
  /** Thin y/N prompt (default yes). Only used on an interactive TTY. */
19
29
  function confirm(question) {
@@ -79,8 +89,22 @@ export async function runCommand(workflow, input, opts = {}) {
79
89
  process.stderr.write(`unknown workflow "${workflow}". Available: ${WORKFLOWS.join(', ')}\n`);
80
90
  return 1;
81
91
  }
92
+ let mode;
93
+ if (workflow === 'idea-refinement') {
94
+ const parsed = IdeaModeSchema.safeParse(opts.mode ?? 'council');
95
+ if (!parsed.success) {
96
+ process.stderr.write(`unknown idea mode "${opts.mode}". Available: quick, council, research\n`);
97
+ return 1;
98
+ }
99
+ mode = parsed.data;
100
+ }
101
+ else if (opts.mode) {
102
+ process.stderr.write('--mode only applies to idea-refinement.\n');
103
+ return 1;
104
+ }
82
105
  let text;
83
106
  let cwd;
107
+ let evidencePack;
84
108
  if (workflow === 'code-review') {
85
109
  const r = await resolveCodeReview(opts);
86
110
  if ('done' in r)
@@ -95,6 +119,19 @@ export async function runCommand(workflow, input, opts = {}) {
95
119
  }
96
120
  text = resolved;
97
121
  }
122
+ if (opts.evidence) {
123
+ if (workflow !== 'idea-refinement') {
124
+ process.stderr.write('--evidence only applies to idea-refinement.\n');
125
+ return 1;
126
+ }
127
+ try {
128
+ evidencePack = await buildEvidencePack(opts.evidence);
129
+ }
130
+ catch (error) {
131
+ process.stderr.write(`cannot load evidence pack: ${error instanceof Error ? error.message : String(error)}\n`);
132
+ return 1;
133
+ }
134
+ }
98
135
  // Precedence (§10/T9): --budget flag > config.budget > built-in default. roles/deadline/models are
99
136
  // config-only (layered: global ~/.aiki base, project .aiki override).
100
137
  let cfg;
@@ -118,8 +155,12 @@ export async function runCommand(workflow, input, opts = {}) {
118
155
  process.stderr.write('--cheap only applies to code-review; ignoring for this workflow.\n');
119
156
  }
120
157
  // Run-cost preview (V5): show the estimate; confirm interactively unless --yes or non-interactive.
121
- const est = estimateRun(workflow, { cheap: opts.cheap });
122
- const note = ` ≈${est.calls} provider call(s), ~${est.opus} on Claude/Opus (the metered part).`;
158
+ const est = estimateRun(workflow, { cheap: opts.cheap, mode });
159
+ const callEstimate = est.minCalls !== undefined && est.minCalls !== est.calls ? `${est.minCalls}–${est.calls}` : `${est.calls}`;
160
+ const resolvedBudget = opts.budget ?? cfg.budget ?? defaultBudgetFor(workflow, mode);
161
+ const reservation = est.reserved ? `; ${est.reserved} call(s) reserved for chair + planner` : '';
162
+ const modeLabel = mode ? ` in ${mode} mode` : '';
163
+ const note = ` ≈${callEstimate} provider call(s)${modeLabel}, ~${est.opus} on Claude/Opus; budget ${resolvedBudget}${reservation}.`;
123
164
  if (!opts.yes && process.stdin.isTTY && process.stdout.isTTY) {
124
165
  if (!(await confirm(`${note}\n Continue? [Y/n] `))) {
125
166
  process.stdout.write(' cancelled.\n');
@@ -130,15 +171,29 @@ export async function runCommand(workflow, input, opts = {}) {
130
171
  process.stdout.write(`${note}\n`);
131
172
  }
132
173
  const outcome = await runEngine(workflow, text, {
133
- budget: opts.budget ?? cfg.budget,
134
- deadlineMs: cfg.deadlineMs,
174
+ mode,
175
+ budget: resolvedBudget,
176
+ deadlineMs: cfg.deadlineMs ?? defaultDeadlineFor(workflow, mode),
135
177
  roleOverrides,
136
178
  cwd, // code-review: repo root; idea-refinement: undefined → run dir
137
179
  runsRoot: await resolveRunsRoot(), // hybrid: repo .aiki when in a repo, else ~/.aiki
138
180
  providerModels: cfg.models, // V8: per-provider model → CLI --model
181
+ evidencePack,
139
182
  });
140
183
  if (outcome.ok) {
141
- process.stdout.write(`\n ✔ run ${outcome.runId} complete — ${outcome.callCount} provider call(s)\n artifacts: ${outcome.dir}\n`);
184
+ process.stdout.write(`\n ✔ run ${outcome.runId} complete — ${outcome.callCount} provider call(s)\n artifacts: ${outcome.dir}\n\n`);
185
+ // Level-1 terminal summary from the machine-readable report (idea runs; absent for code-review).
186
+ try {
187
+ const report = JSON.parse(await readFile(join(outcome.dir, '10-decision-report.json'), 'utf8'));
188
+ const summary = renderTerminalSummary(report, {
189
+ markdownPath: join(outcome.dir, 'final-report.md'),
190
+ jsonPath: join(outcome.dir, '10-decision-report.json'),
191
+ });
192
+ process.stdout.write(summary.split('\n').map((line) => ` ${line}`).join('\n') + '\n');
193
+ }
194
+ catch {
195
+ /* code-review runs and pre-v4 artifacts have no decision report — the line above already links artifacts */
196
+ }
142
197
  // Auto-open the readable report in the browser (interactive terminals only; skipped in pipes/CI).
143
198
  if (process.stdout.isTTY) {
144
199
  const html = await openCouncilHtml(outcome.runId, outcome.dir);
@@ -0,0 +1,8 @@
1
+ import { readFileSync } from 'node:fs';
2
+ export function readPackageVersion(metaUrl = import.meta.url) {
3
+ const pkg = JSON.parse(readFileSync(new URL('../../package.json', metaUrl), 'utf8'));
4
+ if (typeof pkg.version !== 'string')
5
+ throw new Error('package.json version missing');
6
+ return pkg.version;
7
+ }
8
+ export const VERSION = readPackageVersion();