aiki-cli 0.3.2 → 0.3.3

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 (48) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +64 -4
  3. package/dist/bench/idea-v3-bench.js +104 -5
  4. package/dist/bench/idea-v3-rating.js +158 -3
  5. package/dist/cli/bench.js +5 -5
  6. package/dist/cli/index.js +12 -2
  7. package/dist/cli/resume.js +20 -0
  8. package/dist/cli/run.js +75 -4
  9. package/dist/cli/serve.js +48 -0
  10. package/dist/config/config.js +7 -2
  11. package/dist/council/view.js +13 -4
  12. package/dist/orchestration/auto-profile.js +97 -0
  13. package/dist/orchestration/claim-groups.js +56 -0
  14. package/dist/orchestration/context.js +66 -3
  15. package/dist/orchestration/decision-dossier.js +42 -10
  16. package/dist/orchestration/decision-graph.js +2 -2
  17. package/dist/orchestration/engine.js +8 -4
  18. package/dist/orchestration/evidence-origin.js +17 -0
  19. package/dist/orchestration/jsonStage.js +47 -5
  20. package/dist/orchestration/modes.js +4 -2
  21. package/dist/orchestration/preflight.js +19 -0
  22. package/dist/orchestration/quick-analysis.js +8 -3
  23. package/dist/orchestration/sanitize-paths.js +10 -0
  24. package/dist/orchestration/stages/s10-render.js +31 -7
  25. package/dist/orchestration/stages/s4-analyze.js +7 -1
  26. package/dist/orchestration/stages/s4b-challenge.js +97 -0
  27. package/dist/orchestration/stages/s5-drift.js +13 -3
  28. package/dist/orchestration/stages/s8-verify.js +44 -7
  29. package/dist/orchestration/stages/s9-judge.js +20 -5
  30. package/dist/orchestration/stages/s9b-plan.js +44 -15
  31. package/dist/orchestration/url-sources.js +21 -0
  32. package/dist/providers/adapter-core.js +1 -1
  33. package/dist/providers/claude.js +18 -0
  34. package/dist/schemas/index.js +45 -0
  35. package/dist/serve/flight-deck.js +830 -0
  36. package/dist/serve/followup.js +50 -0
  37. package/dist/serve/frames.js +168 -0
  38. package/dist/serve/gates.js +72 -0
  39. package/dist/serve/projections.js +283 -0
  40. package/dist/serve/server.js +219 -0
  41. package/dist/serve/threads.js +145 -0
  42. package/dist/serve-ui/Five.png +0 -0
  43. package/dist/serve-ui/app.js +820 -0
  44. package/dist/serve-ui/index.html +171 -0
  45. package/dist/serve-ui/workspace.css +662 -0
  46. package/dist/storage/runs.js +2 -1
  47. package/dist/workflows/idea-refinement.js +94 -16
  48. package/package.json +2 -2
@@ -12,7 +12,7 @@
12
12
  // an invalid payload throws and writes nothing.
13
13
  import { mkdir, rename, writeFile } from 'node:fs/promises';
14
14
  import { dirname, join } from 'node:path';
15
- import { ActionPlanArtifact, DecisionContractArtifact, DecisionGraph, DisagreementMap, IdeaRoleOutput, JudgeReport, PreflightArtifact, RebuttalEventSet, ReviewMap, RoleOutput, RunBrief, RunMeta, UrlSourceSet, VerificationArtifact } from '../schemas/index.js';
15
+ import { ActionPlanArtifact, ChallengeDeltaSet, DecisionContractArtifact, DecisionGraph, DisagreementMap, IdeaRoleOutput, JudgeReport, PreflightArtifact, RebuttalEventSet, ReviewMap, RoleOutput, RunBrief, RunMeta, UrlSourceSet, VerificationArtifact } from '../schemas/index.js';
16
16
  export class OutOfOrderWriteError extends Error {
17
17
  constructor(slot, ord, maxOrd) {
18
18
  super(`out-of-order write: "${slot}" (stage ${ord}) after stage ${maxOrd} already written`);
@@ -33,6 +33,7 @@ const JSON_SLOTS = {
33
33
  'intent-contract': { ord: 1, path: '01-intent-contract.json', schema: DecisionContractArtifact },
34
34
  'preflight-readings': { ord: 2, path: '02-preflight-readings.json', schema: PreflightArtifact },
35
35
  'misunderstanding-guard': { ord: 2, path: '02-misunderstanding-guard.json', schema: null },
36
+ 'challenge-deltas': { ord: 4.5, path: '04b-challenge-deltas.json', schema: ChallengeDeltaSet },
36
37
  'drift-report': { ord: 5, path: '05-drift-report.json', schema: null },
37
38
  positions: { ord: 6, path: '06-positions.json', schema: null },
38
39
  'coverage-fill': { ord: 6.5, path: '06b-coverage-fill.json', schema: IdeaRoleOutput },
@@ -7,15 +7,19 @@ import { s5Drift } from '../orchestration/stages/s5-drift.js';
7
7
  import { s6Positions } from '../orchestration/stages/s6-positions.js';
8
8
  import { s7DecisionGraph } from '../orchestration/stages/s7-decision-graph.js';
9
9
  import { s8Verify } from '../orchestration/stages/s8-verify.js';
10
+ import { overlayClaimGroups } from '../orchestration/claim-groups.js';
10
11
  import { s8bRebuttal } from '../orchestration/stages/s8b-rebuttal.js';
11
12
  import { s9Judge } from '../orchestration/stages/s9-judge.js';
12
13
  import { s9bPlan } from '../orchestration/stages/s9b-plan.js';
13
14
  import { s10Render } from '../orchestration/stages/s10-render.js';
14
15
  import { loadSkill } from '../orchestration/skills.js';
15
16
  import { buildLanePrompts } from '../orchestration/idea-lanes.js';
16
- import { preflight, renderDecisionInput } from '../orchestration/preflight.js';
17
- import { buildQuickPrompt, quickActionPlan, quickJudgeReport, s4QuickAnalyze } from '../orchestration/quick-analysis.js';
18
- import { snapshotUrlSources } from '../orchestration/url-sources.js';
17
+ import { deterministicContract, preflight, renderDecisionInput } from '../orchestration/preflight.js';
18
+ import { buildAdaptivePrompt, buildQuickPrompt, quickActionPlan, quickJudgeReport, s4QuickAnalyze } from '../orchestration/quick-analysis.js';
19
+ import { blockedSourceStop, snapshotUrlSources } from '../orchestration/url-sources.js';
20
+ import { compileDecisionGraph } from '../orchestration/decision-graph.js';
21
+ import { structuralEscalationGates } from '../orchestration/auto-profile.js';
22
+ import { overlayChallengeDeltas, s4bChallenge } from '../orchestration/stages/s4b-challenge.js';
19
23
  /** Idea-vetting core rubric: 13 mandatory coverage items. S0 adds 3-5 domain dimensions per run.
20
24
  * Inlined here (like the S4 template) while the skill/`rubric.json` loader (§11)
21
25
  * is deferred; it moves to skills/idea-refinement/rubric.json when that loader lands. */
@@ -139,25 +143,96 @@ export function recordIdeaOutcomeFlags(ctx, contract, seats) {
139
143
  export async function runIdeaRefinement(ctx, input) {
140
144
  if (ctx.evidencePack)
141
145
  await ctx.writer.writeInput('evidence-pack.json', JSON.stringify(ctx.evidencePack, null, 2));
142
- const urlSources = await snapshotUrlSources(input);
146
+ // v6 T10b: the CLI may have already snapshotted (and interactively cleared) the sources.
147
+ const urlSources = ctx.urlSources ?? await snapshotUrlSources(input);
143
148
  await ctx.writer.writeJson('url-sources', urlSources);
144
149
  const unreadableSources = urlSources.sources.filter((source) => source.status !== 'FETCHED');
145
150
  const needsSourceFallback = ctx.mode !== 'quick' && unreadableSources.length > 0;
146
- const hasReadableResearch = Boolean(ctx.evidencePack?.files.length)
147
- || urlSources.sources.some((source) => source.status === 'FETCHED');
148
- const canSearch = ctx.roles.s4.includes('codex');
149
- if (needsSourceFallback && !canSearch && !hasReadableResearch) {
150
- const details = unreadableSources.map((source) => `${source.url} (${source.status}: ${source.error})`).join('; ');
151
- throw new StageError('S0', 'SOURCE_UNREADABLE', `source investigation stopped before model calls because no source was readable and Codex search is unavailable${details ? `: ${details}` : ''}. Paste the relevant text, provide a public export, or enable Codex, then rerun.`);
151
+ // v6 T10: ANY unreadable supplied source stops the run before paid calls unless the user
152
+ // explicitly proceeds (--allow-blocked-sources). Codex search no longer silences the ask —
153
+ // it runs in addition, once the user has chosen to proceed.
154
+ const stop = blockedSourceStop(urlSources, ctx.mode, ctx.allowBlockedSources ?? false);
155
+ if (stop)
156
+ throw new StageError('S0', 'SOURCE_UNREADABLE', `source investigation stopped before model calls: ${stop}`);
157
+ let contract;
158
+ let grilledInput;
159
+ if (ctx.fastPath) {
160
+ contract = await runStage(ctx, 'S0', async () => {
161
+ return deterministicContract(input, IDEA_RUBRIC.map((item) => item.label));
162
+ });
163
+ ctx.addFlag('headless_intent');
164
+ grilledInput = input;
165
+ }
166
+ else {
167
+ const result = await runStage(ctx, 'S0', () => preflight(ctx, input, IDEA_RUBRIC.map((item) => item.label), urlSources));
168
+ contract = result.contract;
169
+ grilledInput = renderDecisionInput(input, result.brief, urlSources);
152
170
  }
153
- const { contract, brief } = await runStage(ctx, 'S0', () => preflight(ctx, input, IDEA_RUBRIC.map((item) => item.label), urlSources));
154
- const grilledInput = renderDecisionInput(input, brief, urlSources);
155
171
  // Persist the input as a file so S4's "read the file at {{INPUT_PATH}}" resolves (not a stage).
156
172
  await ctx.writer.writeInput('idea.md', input);
157
173
  await ctx.writer.writeInput('idea-brief.md', grilledInput);
158
174
  const inputPath = resolve(ctx.writer.dir, 'inputs', 'idea-brief.md');
159
175
  const rubric = buildIdeaRubric(contract.domain_dimensions);
160
176
  const analystSkill = loadSkill('idea-refinement', 'analyst');
177
+ if (ctx.isAuto) {
178
+ ctx.addFlag('single_model');
179
+ const startedFast = ctx.fastPath;
180
+ const primaryPrompt = startedFast
181
+ ? buildQuickPrompt(contract, inputPath, ctx.evidencePack, analystSkill)
182
+ : buildAdaptivePrompt(contract, inputPath, ctx.evidencePack, analystSkill);
183
+ if (!startedFast)
184
+ await ctx.writer.writePrompt('auto-primary.md', primaryPrompt);
185
+ const quick = await runStage(ctx, 'S4', () => s4QuickAnalyze(ctx, primaryPrompt, {
186
+ persist: !startedFast,
187
+ stage: startedFast ? 'Q1' : 'S4-auto-primary',
188
+ }));
189
+ const provisional = compileDecisionGraph([{ provider: quick.seat.provider, submission: quick.seat.output }], rubric);
190
+ const gates = structuralEscalationGates(provisional);
191
+ if (gates.length) {
192
+ ctx.markAutoEscalated(gates.map((gate) => gate.reason));
193
+ if (startedFast) {
194
+ const result = await runStage(ctx, 'S0-auto', () => preflight(ctx, input, IDEA_RUBRIC.map((item) => item.label), urlSources));
195
+ contract = result.contract;
196
+ }
197
+ }
198
+ if (startedFast) {
199
+ if (gates.length === 0)
200
+ await ctx.writer.writeJson('intent-contract', contract);
201
+ await ctx.writer.writePrompt('quick-analyst.md', primaryPrompt);
202
+ await ctx.writer.writeRoleOutput(quick.seat.provider, quick.seat.output);
203
+ }
204
+ const challenge = gates.length
205
+ ? await runStage(ctx, 'S4b', () => s4bChallenge(ctx, provisional, gates, quick.seat.provider))
206
+ : { deltas: [] };
207
+ const { kept } = await runStage(ctx, 'S5', () => s5Drift(ctx, contract, [quick.seat], 1));
208
+ if (ctx.mode !== 'quick')
209
+ recordIdeaOutcomeFlags(ctx, contract, kept);
210
+ const positions = await runStage(ctx, 'S6', () => s6Positions(ctx, kept));
211
+ const graph = await runStage(ctx, 'S7', () => s7DecisionGraph(ctx, positions, rubric, contract.task));
212
+ const challenged = overlayChallengeDeltas(graph, challenge.deltas);
213
+ const verifications = await runStage(ctx, 'S8', async () => {
214
+ const result = { verifications: [] };
215
+ await ctx.writer.writeJson('verifications', result);
216
+ return result;
217
+ });
218
+ const rebuttals = await runStage(ctx, 'S8b', async () => {
219
+ const result = { round: 1, selected_claim_ids: [], events: [], stop_reason: 'NO_ESCALATIONS' };
220
+ await ctx.writer.writeJson('rebuttals', result);
221
+ return result;
222
+ });
223
+ const judgeReport = await runStage(ctx, 'S9', async () => {
224
+ const report = quickJudgeReport(quick.decision, challenged);
225
+ await ctx.writer.writeJson('judge-report', report);
226
+ return report;
227
+ });
228
+ const actionPlan = await runStage(ctx, 'S9b', async () => {
229
+ const plan = quickActionPlan(ctx, quick.seat.provider, quick.decision, challenged, contract);
230
+ await ctx.writer.writeJson('action-plan', plan);
231
+ return plan;
232
+ });
233
+ await runStage(ctx, 'S10', () => s10Render(ctx, { contract, seats: kept, graph: challenged, verifications, rebuttals, judgeReport, actionPlan, rubric, original: input }));
234
+ return;
235
+ }
161
236
  if (ctx.mode === 'quick') {
162
237
  ctx.addFlag('single_model');
163
238
  const quickPrompt = buildQuickPrompt(contract, inputPath, ctx.evidencePack, analystSkill);
@@ -198,8 +273,11 @@ export async function runIdeaRefinement(ctx, input) {
198
273
  const positions = await runStage(ctx, 'S6', () => s6Positions(ctx, kept));
199
274
  const graph = await runStage(ctx, 'S7', () => s7DecisionGraph(ctx, positions, rubric, contract.task));
200
275
  const verifications = await runStage(ctx, 'S8', () => s8Verify(ctx, graph));
201
- const rebuttals = await runStage(ctx, 'S8b', () => s8bRebuttal(ctx, graph, verifications, ctx.mode));
202
- const judgeReport = await runStage(ctx, 'S9', () => s9Judge(ctx, contract, graph, verifications, rubric, rebuttals));
203
- const actionPlan = await runStage(ctx, 'S9b', () => s9bPlan(ctx, contract, kept, graph, judgeReport, input));
204
- await runStage(ctx, 'S10', () => s10Render(ctx, { contract, seats: kept, graph, verifications, rebuttals, judgeReport, actionPlan, rubric, original: input }));
276
+ // v6 semantic join: S8's validated claim_groups upgrade cross-provider paraphrase states
277
+ // (UNIQUE CONSENSUS/DISAGREEMENT/…) on a derived copy; the stored 07 artifact stays original.
278
+ const joined = overlayClaimGroups(graph, verifications.claim_groups);
279
+ const rebuttals = await runStage(ctx, 'S8b', () => s8bRebuttal(ctx, joined, verifications, ctx.mode));
280
+ const judgeReport = await runStage(ctx, 'S9', () => s9Judge(ctx, contract, joined, verifications, rubric, rebuttals));
281
+ const actionPlan = await runStage(ctx, 'S9b', () => s9bPlan(ctx, contract, kept, joined, judgeReport, input));
282
+ await runStage(ctx, 'S10', () => s10Render(ctx, { contract, seats: kept, graph: joined, verifications, rebuttals, judgeReport, actionPlan, rubric, original: input }));
205
283
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiki-cli",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Local-first AI model council for code review and idea stress-testing using Claude Code, Codex, and Gemini/Antigravity CLIs. No API keys.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  "node": ">=20"
46
46
  },
47
47
  "scripts": {
48
- "build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json && node -e \"require('fs').copyFileSync('src/providers/profiles.json','dist/providers/profiles.json')\" && node -e \"require('fs').cpSync('src/skills','dist/skills',{recursive:true})\"",
48
+ "build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json && node -e \"require('fs').copyFileSync('src/providers/profiles.json','dist/providers/profiles.json')\" && node -e \"require('fs').cpSync('src/skills','dist/skills',{recursive:true})\" && node -e \"require('fs').cpSync('serve-ui','dist/serve-ui',{recursive:true})\"",
49
49
  "typecheck": "tsc -p tsconfig.json --noEmit",
50
50
  "test": "vitest run",
51
51
  "test:watch": "vitest",