aiki-cli 0.3.1 → 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 (59) hide show
  1. package/CHANGELOG.md +80 -5
  2. package/README.md +73 -15
  3. package/dist/bench/idea-v3-bench.js +104 -5
  4. package/dist/bench/idea-v3-rating.js +159 -4
  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 +76 -5
  9. package/dist/cli/serve.js +48 -0
  10. package/dist/config/config.js +7 -2
  11. package/dist/council/view.js +64 -15
  12. package/dist/orchestration/auto-profile.js +97 -0
  13. package/dist/orchestration/claim-groups.js +56 -0
  14. package/dist/orchestration/context.js +69 -6
  15. package/dist/orchestration/decision-dossier.js +450 -89
  16. package/dist/orchestration/decision-graph.js +33 -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/legacy-idea-adapter.js +3 -0
  21. package/dist/orchestration/modes.js +18 -10
  22. package/dist/orchestration/preflight.js +36 -3
  23. package/dist/orchestration/quick-analysis.js +29 -7
  24. package/dist/orchestration/sanitize-paths.js +10 -0
  25. package/dist/orchestration/stages/s10-render.js +196 -84
  26. package/dist/orchestration/stages/s4-analyze.js +10 -2
  27. package/dist/orchestration/stages/s4b-challenge.js +97 -0
  28. package/dist/orchestration/stages/s5-drift.js +13 -3
  29. package/dist/orchestration/stages/s6-positions.js +18 -0
  30. package/dist/orchestration/stages/s7-decision-graph.js +3 -0
  31. package/dist/orchestration/stages/s8-verify.js +66 -12
  32. package/dist/orchestration/stages/s8b-rebuttal.js +11 -4
  33. package/dist/orchestration/stages/s9-judge.js +52 -14
  34. package/dist/orchestration/stages/s9b-plan.js +227 -48
  35. package/dist/orchestration/url-sources.js +21 -0
  36. package/dist/providers/adapter-core.js +1 -1
  37. package/dist/providers/claude.js +18 -0
  38. package/dist/schemas/index.js +112 -3
  39. package/dist/serve/flight-deck.js +830 -0
  40. package/dist/serve/followup.js +50 -0
  41. package/dist/serve/frames.js +168 -0
  42. package/dist/serve/gates.js +72 -0
  43. package/dist/serve/projections.js +283 -0
  44. package/dist/serve/server.js +219 -0
  45. package/dist/serve/threads.js +145 -0
  46. package/dist/serve-ui/Five.png +0 -0
  47. package/dist/serve-ui/app.js +820 -0
  48. package/dist/serve-ui/index.html +171 -0
  49. package/dist/serve-ui/workspace.css +662 -0
  50. package/dist/skills/idea-refinement/analyst.md +5 -5
  51. package/dist/skills/idea-refinement/chair.md +18 -0
  52. package/dist/skills/idea-refinement/economics-delivery.md +11 -0
  53. package/dist/skills/idea-refinement/market-adoption.md +12 -0
  54. package/dist/skills/idea-refinement/planner.md +25 -19
  55. package/dist/skills/idea-refinement/rebuttal.md +15 -0
  56. package/dist/skills/idea-refinement/verifier.md +17 -0
  57. package/dist/storage/runs.js +2 -1
  58. package/dist/workflows/idea-refinement.js +130 -24
  59. package/package.json +2 -2
@@ -1,11 +1,11 @@
1
- # Analyst playbook — pressure-test the idea
1
+ # Analyst playbook — strengthen and pressure-test the idea
2
2
 
3
- You are an adversarial analyst on a decision panel. Your job is not to like the idea it is to find
4
- where it breaks. Steelman it once, then attack it honestly.
3
+ You are an independent analyst on a decision panel. Build the strongest useful version for your lane,
4
+ then expose where it breaks. Creation and criticism are both required.
5
5
 
6
6
  ## Strongest version first
7
7
  - Before attacking, state the best honest version of the idea: who it is for and why it would win.
8
- - Attack THAT version, not a weak strawman. If the steelman is thin, that itself is a finding.
8
+ - Test THAT version, not a weak strawman. If the steelman is thin, that itself is a finding.
9
9
 
10
10
  ## Positions — make the stance explicit
11
11
  - State each decision-critical proposition and take an explicit SUPPORT, OPPOSE, MIXED, or UNKNOWN
@@ -45,5 +45,5 @@ ownership; emit one explicit coverage entry for every owned dimension.
45
45
  - Phrase each so that a yes/no or a single number would actually flip your assessment.
46
46
 
47
47
  ## Do not
48
- - No motivational framing, no pitch language, no summarizing your own output.
48
+ - No unsupported hype or generic feature wishlists. Explain the mechanism and user value.
49
49
  - No unanchored position or evidence. No proposition you cannot tie to the decision.
@@ -0,0 +1,18 @@
1
+ # Chair playbook — rule on the real disagreement
2
+
3
+ Add to your base instructions; the schema and caps are unchanged and always win.
4
+
5
+ ## Synthesis discipline
6
+ - Count convergence only when seats reached the same conclusion independently with different evidence.
7
+ Two seats repeating the same hedge is not agreement.
8
+ - Never smooth over a clash. State both readings, compare their evidence quality, and rule.
9
+ - A strong dissent beats a weak majority. Side with the better-evidenced minority when warranted and
10
+ explain why in `key_points`.
11
+ - Never answer "it depends". Choose the required verdict enum; put contingencies into concrete,
12
+ checkable conditions that name their claim.
13
+ - Lead `key_points` with the evidence or result that would change the verdict.
14
+ - Report a blind spot only when verification or rebuttal actually exposed it.
15
+
16
+ ## First action
17
+ - Anchor the first action to the single cheapest check that could kill or confirm the decision.
18
+ - Pick one thing first, not a list disguised as one action.
@@ -3,5 +3,16 @@
3
3
  Own unit economics and capital needs, technical and operational feasibility, supply constraints,
4
4
  legal and compliance exposure, scalability, failure modes, and the cheapest decisive kill criteria.
5
5
 
6
+ Act as the skeptic/executor for requested deliverables. When FEATURE_BACKLOG is requested, produce 2–4
7
+ `deliverable_proposals` that preserve the standout value while remaining credible under the stated deadline.
8
+ When IMPLEMENTATION_PLAN is requested, propose the shortest build sequence with observable outcomes.
9
+
6
10
  Steelman the idea first. Cross into another lane only for a load-bearing issue. For every owned
7
11
  dimension, emit a `COVERED` entry anchored to positions or a reasoned `NOT_APPLICABLE` entry.
12
+
13
+ ## Lens discipline (council seat)
14
+ - Contrarian: assume a fatal flaw and hunt it — the number that does not close, the unpriced dependency,
15
+ or the deadline that does not fit.
16
+ - Executor: every recommendation must survive the question, "What do you do Monday morning?"
17
+ - Stance strength must match evidence strength — a hunch is an UNKNOWN position with a question
18
+ attached, never a confident claim.
@@ -3,5 +3,17 @@
3
3
  Own target-user urgency, alternatives and status quo, differentiation, distribution and procurement,
4
4
  timing, and the team's ability to execute the required adoption motion.
5
5
 
6
+ Act as the visionary product strategist for requested deliverables. When FEATURE_BACKLOG is requested,
7
+ produce 3–6 bold but concrete `deliverable_proposals` that create a memorable user or demo moment; say why
8
+ each is distinctive rather than listing ordinary table-stakes UI.
9
+
6
10
  Steelman the idea first. Cross into another lane only for a load-bearing issue. For every owned
7
11
  dimension, emit a `COVERED` entry anchored to positions or a reasoned `NOT_APPLICABLE` entry.
12
+
13
+ ## Lens discipline (council seat)
14
+ - Expansionist: lean fully into this lane instead of hedging toward balance; the other seat and verifier
15
+ cover the rest. Name the undervalued upside with a number and evidence ID, or mark it UNKNOWN.
16
+ - Outsider: read the pitch with zero context. If its framing would confuse a fresh reader, that is a
17
+ market finding, not a presentation footnote.
18
+ - Stance strength must match evidence strength — a hunch is an UNKNOWN position with a question
19
+ attached, never a confident claim.
@@ -1,25 +1,31 @@
1
- # Planner playbook — decisive validation
1
+ # Answer editor playbook — useful first, honest throughout
2
2
 
3
- You write the next tests after the council has already judged the idea. Do not plan the build.
4
- Plan only the cheapest validation work that can change the decision.
3
+ You turn the council's work into the answer the user actually asked for. Lead with a clear product
4
+ recommendation, select the strongest ideas from both seats, and make the result practical enough to act on.
5
5
 
6
- ## Order
7
- - Start with upheld HIGH risks. If one fails, the idea should stop or change shape before any other work.
8
- - Then cover blind spots that could hide a blocker.
9
- - Then answer open questions that would flip the verdict.
6
+ ## Reader answer
7
+ - Answer the original task directly. Do not narrate the council process.
8
+ - Prefer specific product language: what to build, why users care, what makes it memorable, and what to do first.
9
+ - Combine complementary proposals; remove duplicates and cautious filler.
10
+ - Explain the user value or demo payoff of each standout idea, not merely its feature name.
11
+ - Keep facts inside supported findings and sources. Present unevidenced product choices as recommendations,
12
+ never as established market facts.
13
+ - Chair output is decision reasoning, not evidence. Reframe its unsupported certainty as a recommendation,
14
+ risk, or hypothesis unless the proposition also appears in supported findings.
15
+ - Use plain-language caveats only when they could change the recommendation.
10
16
 
11
- ## Action quality
12
- - Every action must be concrete enough that a person can run it this week.
13
- - Prefer interviews, landing-page smoke tests, pricing tests, manual concierge trials, prototype probes,
14
- competitor checks, and policy checks over implementation work.
15
- - Tie every action to exactly one anchor in `validates`.
17
+ ## Requested deliverables
18
+ - When a feature backlog is requested, make MUST the smallest compelling golden path. Use SHOULD and LATER
19
+ for real prioritization; WONT protects the concept from scope creep.
20
+ - When an implementation plan is requested, give an outcome-driven build sequence with observable acceptance tests.
21
+ - The reader brief should summarize these deliverables rather than repeat every field verbatim.
16
22
 
17
- ## Kill signals
18
- - A kill signal is not "learn more". It is the result that stops, pivots, or narrows the idea.
19
- - Make the signal observable: a count, threshold, refusal pattern, legal blocker, cost ceiling, or
20
- behavior that contradicts the assumption.
23
+ ## Validation actions
24
+ - Keep 1–4 actions. Start with the cheapest unresolved risk that could stop or reshape the recommendation.
25
+ - Every action must be concrete enough to run this week and tie to exactly one supplied anchor.
26
+ - A kill signal must be observable: a threshold, refusal pattern, blocker, cost ceiling, or failed behavior.
21
27
 
22
28
  ## Do not
23
- - No product roadmap, scaffolding plan, architecture plan, or feature list.
24
- - No action for a claim the chair already settled.
25
- - No vague market research. No unanchored action.
29
+ - No graph ids, verification labels, confidence formulas, audit vocabulary, or model-process commentary in reader_brief.
30
+ - No generic "do more research" action.
31
+ - No invented source or unsupported hype.
@@ -0,0 +1,15 @@
1
+ # Rebuttal playbook — answer the strongest opposition
2
+
3
+ Add to your base instructions; the schema and caps are unchanged and always win.
4
+
5
+ ## Review in this order
6
+ 1. Steelman the opposing position in one line before answering it.
7
+ 2. Name its biggest blind spot: the assumption it never checks. Attack that assumption with supplied
8
+ evidence IDs.
9
+ 3. Name what both sides missed. Use NARROW or UNRESOLVED instead of pretending it was covered.
10
+
11
+ ## Stance discipline
12
+ - CONCEDE when the evidence beats your position. An early concession on a lost point preserves
13
+ credibility for the decision-critical dispute.
14
+ - Never change a stance word without a supplied evidence ID.
15
+ - Prefer a precise unresolved boundary over a broad defensive counterclaim.
@@ -0,0 +1,17 @@
1
+ # Verifier playbook — try to disprove the claim
2
+
3
+ Add to your base instructions; the schema and caps are unchanged and always win.
4
+
5
+ ## Refute first
6
+ - Assume each claim is wrong. Hunt for the disconfirming reading of the same supplied evidence.
7
+ - Confirm only after a serious refutation attempt fails.
8
+ - Agreement without attempted refutation is analytically NOT_CHECKED, not SUPPORTED; express that
9
+ uncertainty with the closest allowed schema status rather than returning VERIFIED.
10
+ - Judge the evidence, never its author.
11
+
12
+ ## Evidence discipline
13
+ - Treat CONFLICTED as a finding, not an output enum: use the allowed status and record the exact two
14
+ clashing readings in the reasoning.
15
+ - Never verify a value judgment as fact. Numbers, deadlines, and rule text can be checked; taste and
16
+ strategy remain positions for the chair.
17
+ - Include one concise sentence describing the method used for each verification.
@@ -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. */
@@ -42,7 +46,7 @@ export function buildIdeaRubric(domainDimensions = []) {
42
46
  }
43
47
  /** Idea S4 analyst template. R6 fills every slot deterministically before the parallel scout calls. */
44
48
  export const IDEA_S4_ANALYST_TEMPLATE = `ROLE: Independent analyst on a decision panel. You work ALONE; you will not see
45
- other analysts' output. Be adversarial toward the idea, not polite.
49
+ other analysts' output. Improve the strongest version and pressure-test it honestly within your assigned lane.
46
50
 
47
51
  TASK CONTRACT: {{INTENT_CONTRACT_JSON}}
48
52
  INPUT DOCUMENT: read the file at {{INPUT_PATH}}{{SKILL}}
@@ -54,7 +58,10 @@ Produce ONLY JSON matching {{S4_SCHEMA_REF}} with:
54
58
  - task_echo: restate the task in ≤2 sentences (drift check).
55
59
  - strongest_version: the best honest version of this idea in ≤150 words.
56
60
  - positions: explicit claim positions with local_id, proposition, rubric dimension_id, stance
57
- SUPPORT|OPPOSE|MIXED|UNKNOWN, basis EVIDENCE|INFERENCE|ASSUMPTION, load_bearing, if_false
61
+ SUPPORT|OPPOSE|MIXED|UNKNOWN, basis EVIDENCE|INFERENCE|ASSUMPTION, nature FACTUAL when the position
62
+ asserts something independently checkable about the world (rules, deadlines, prices, observed CLI
63
+ behavior, published numbers) or JUDGMENT for a design choice, recommendation, prioritization, or
64
+ prediction (when unsure use JUDGMENT), load_bearing, if_false
58
65
  STOP|PIVOT|CONDITION|MINOR, concise reasoning, evidence_ids, and depends_on position ids.
59
66
  - evidence: evidence cards {id, claim_supported, source_kind USER|PRIMARY|SECONDARY|MODEL_KNOWLEDGE,
60
67
  support SUPPORTS|CONTRADICTS|CONTEXT_ONLY (exact token, no extra words), freshness CURRENT|DATED|UNKNOWN,
@@ -66,8 +73,11 @@ Produce ONLY JSON matching {{S4_SCHEMA_REF}} with:
66
73
  - coverage: one entry per rubric dimension {dimension_id, status COVERED|NOT_APPLICABLE,
67
74
  position_ids ([] when none), rationale (required for NOT_APPLICABLE)}.
68
75
  - decision_questions: questions {question, claim_ids} whose answers could change the verdict.
69
- Caps: at most 12 positions, 20 evidence cards, 8 calculations, 8 decision_questions.
70
- Rules: no motivation, no summaries of your own output, no markdown, JSON only.`;
76
+ - deliverable_proposals: when requested_outputs includes FEATURE_BACKLOG or IMPLEMENTATION_PLAN, propose
77
+ concrete user-facing work as {output,title,detail,user_value,why_distinctive,evidence_ids}; otherwise [].
78
+ Proposals are recommendations, not factual claims. Use evidence_ids only when evidence directly supports them.
79
+ Caps: at most 12 positions, 20 evidence cards, 8 calculations, 8 decision_questions, 8 deliverable_proposals.
80
+ Rules: no unsupported hype, no summaries of your own output, no markdown, JSON only.`;
71
81
  /**
72
82
  * Resolve the {{SKILL}} slot before deterministic structural fill. An empty skill collapses the slot
73
83
  * to the pre-skill baseline.
@@ -77,11 +87,11 @@ export function buildAnalystTemplate(skill) {
77
87
  }
78
88
  /** R6 deterministic S4 prompt fill. No model-authored prompt generation remains. */
79
89
  export function buildAnalystPrompt(contract, inputPath, evidencePack, mode, skill) {
80
- const modeRules = mode === 'research'
81
- ? `\n\nMODE: research. Use provider-native read-only source investigation when available. Every current
90
+ const modeRules = mode !== 'quick'
91
+ ? `\n\nMODE: full council. Use provider-native read-only source investigation when available. Every current
82
92
  fact must have an independently checkable locator and access date. If investigation is unavailable,
83
93
  leave the claim unverified; never invent a source.`
84
- : `\n\nMODE: council. Analyze independently; do not assume another seat will cover your lane.`;
94
+ : `\n\nMODE: quick. Analyze independently and keep unsupported claims visibly unverified.`;
85
95
  const prompt = buildAnalystTemplate(skill)
86
96
  .replace('{{INTENT_CONTRACT_JSON}}', JSON.stringify(contract))
87
97
  .replace('{{INPUT_PATH}}', inputPath)
@@ -107,27 +117,122 @@ export const IDEA_STAGES = [
107
117
  { id: 'S9b', label: 'Validation plan', role: 'judge' },
108
118
  { id: 'S10', label: 'Report', role: null },
109
119
  ];
120
+ /** Record guarantees observed at the surviving typed S4 boundary; never infer them from prompts. */
121
+ export function recordIdeaOutcomeFlags(ctx, contract, seats) {
122
+ if (ctx.mode === 'quick')
123
+ return;
124
+ const requested = (contract.requested_outputs ?? [])
125
+ .filter((output) => output === 'FEATURE_BACKLOG' || output === 'IMPLEMENTATION_PLAN');
126
+ if (requested.some((output) => seats.some((seat) => !seat.output.deliverable_proposals.some((proposal) => proposal.output === output)))) {
127
+ ctx.addFlag('deliverable_gap');
128
+ }
129
+ const grounded = seats.some((seat) => {
130
+ const cited = new Set(seat.output.positions.flatMap((position) => position.evidence_ids));
131
+ return seat.output.evidence.some((card) => cited.has(card.id)
132
+ && (card.source_kind === 'PRIMARY' || card.source_kind === 'SECONDARY')
133
+ && card.freshness === 'CURRENT'
134
+ && Boolean(card.accessed_at && (card.url || card.locator))
135
+ && card.support !== 'CONTEXT_ONLY');
136
+ });
137
+ if (!grounded)
138
+ ctx.addFlag('research_ungrounded');
139
+ }
110
140
  /** Runs the full idea-refinement pipeline S0–S10. Throws on any fatal condition; the engine's
111
141
  * `executeRun` wrapper turns that into a graceful failure + meta. Each stage is wrapped in
112
142
  * `runStage` so the TUI timeline (T8) gets start/end events; headless, that's a no-op. */
113
143
  export async function runIdeaRefinement(ctx, input) {
114
144
  if (ctx.evidencePack)
115
145
  await ctx.writer.writeInput('evidence-pack.json', JSON.stringify(ctx.evidencePack, null, 2));
116
- 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);
117
148
  await ctx.writer.writeJson('url-sources', urlSources);
118
149
  const unreadableSources = urlSources.sources.filter((source) => source.status !== 'FETCHED');
119
- if (ctx.mode === 'research' && unreadableSources.length > 0) {
120
- const details = unreadableSources.map((source) => `${source.url} (${source.status}: ${source.error})`).join('; ');
121
- throw new StageError('S0', 'SOURCE_UNREADABLE', `research stopped before model calls because a supplied source could not be read: ${details}. Paste the relevant text or provide a public export, then rerun.`);
150
+ const needsSourceFallback = ctx.mode !== 'quick' && unreadableSources.length > 0;
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);
122
170
  }
123
- const { contract, brief } = await runStage(ctx, 'S0', () => preflight(ctx, input, IDEA_RUBRIC.map((item) => item.label), urlSources));
124
- const grilledInput = renderDecisionInput(input, brief, urlSources);
125
171
  // Persist the input as a file so S4's "read the file at {{INPUT_PATH}}" resolves (not a stage).
126
172
  await ctx.writer.writeInput('idea.md', input);
127
173
  await ctx.writer.writeInput('idea-brief.md', grilledInput);
128
174
  const inputPath = resolve(ctx.writer.dir, 'inputs', 'idea-brief.md');
129
175
  const rubric = buildIdeaRubric(contract.domain_dimensions);
130
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
+ }
131
236
  if (ctx.mode === 'quick') {
132
237
  ctx.addFlag('single_model');
133
238
  const quickPrompt = buildQuickPrompt(contract, inputPath, ctx.evidencePack, analystSkill);
@@ -159,19 +264,20 @@ export async function runIdeaRefinement(ctx, input) {
159
264
  await runStage(ctx, 'S10', () => s10Render(ctx, { contract, seats: kept, graph, verifications, rebuttals, judgeReport, actionPlan, rubric, original: input }));
160
265
  return;
161
266
  }
162
- if (ctx.mode === 'research' && !ctx.evidencePack && !ctx.available().includes('codex')) {
163
- ctx.addFlag('research_ungrounded');
164
- }
165
267
  const analystPrompt = buildAnalystPrompt(contract, inputPath, ctx.evidencePack, ctx.mode, analystSkill);
166
268
  await ctx.writer.writePrompt('analyst.md', analystPrompt);
167
269
  const lanePrompts = buildLanePrompts(analystPrompt, rubric);
168
- const seats = await runStage(ctx, 'S4', () => s4Analyze(ctx, lanePrompts));
270
+ const seats = await runStage(ctx, 'S4', () => s4Analyze(ctx, lanePrompts, needsSourceFallback));
169
271
  const { kept } = await runStage(ctx, 'S5', () => s5Drift(ctx, contract, seats));
272
+ recordIdeaOutcomeFlags(ctx, contract, kept);
170
273
  const positions = await runStage(ctx, 'S6', () => s6Positions(ctx, kept));
171
274
  const graph = await runStage(ctx, 'S7', () => s7DecisionGraph(ctx, positions, rubric, contract.task));
172
275
  const verifications = await runStage(ctx, 'S8', () => s8Verify(ctx, graph));
173
- const rebuttals = await runStage(ctx, 'S8b', () => s8bRebuttal(ctx, graph, verifications, ctx.mode));
174
- const judgeReport = await runStage(ctx, 'S9', () => s9Judge(ctx, contract, graph, verifications, rubric, rebuttals));
175
- const actionPlan = await runStage(ctx, 'S9b', () => s9bPlan(ctx, contract, kept, graph, judgeReport));
176
- 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 }));
177
283
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiki-cli",
3
- "version": "0.3.1",
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",