aiki-cli 0.2.2 → 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.
- package/CHANGELOG.md +98 -7
- package/README.md +109 -30
- package/dist/bench/arms.js +10 -9
- package/dist/bench/harness.js +13 -10
- package/dist/bench/idea-lane-rotation.js +237 -0
- package/dist/bench/idea-v3-bench.js +506 -0
- package/dist/bench/idea-v3-rating.js +582 -0
- package/dist/bench/results.js +10 -3
- package/dist/bench/scoring/decision-insights.js +112 -0
- package/dist/bench/scoring/seeded-bugs.js +4 -0
- package/dist/cli/bench.js +180 -3
- package/dist/cli/doctor.js +56 -24
- package/dist/cli/index.js +31 -6
- package/dist/cli/resolve.js +7 -6
- package/dist/cli/resume.js +18 -0
- package/dist/cli/run.js +63 -8
- package/dist/council/view.js +378 -109
- package/dist/orchestration/calculations.js +97 -0
- package/dist/orchestration/context.js +37 -9
- package/dist/orchestration/decision-dossier.js +262 -0
- package/dist/orchestration/decision-graph.js +256 -0
- package/dist/orchestration/engine.js +5 -2
- package/dist/orchestration/evidence-pack.js +46 -0
- package/dist/orchestration/idea-lanes.js +20 -0
- package/dist/orchestration/jsonStage.js +72 -0
- package/dist/orchestration/legacy-idea-adapter.js +102 -0
- package/dist/orchestration/modes.js +33 -0
- package/dist/orchestration/preflight.js +183 -0
- package/dist/orchestration/quick-analysis.js +81 -0
- package/dist/orchestration/stages/cr-ladder.js +80 -0
- package/dist/orchestration/stages/s10-render.js +562 -150
- package/dist/orchestration/stages/s4-analyze.js +12 -7
- package/dist/orchestration/stages/s5-drift.js +9 -9
- package/dist/orchestration/stages/s6-positions.js +10 -0
- package/dist/orchestration/stages/s7-decision-graph.js +76 -0
- package/dist/orchestration/stages/s8-verify.js +153 -46
- package/dist/orchestration/stages/s8b-rebuttal.js +208 -0
- package/dist/orchestration/stages/s9-judge.js +329 -108
- package/dist/orchestration/stages/s9b-plan.js +85 -75
- package/dist/providers/codex.js +2 -1
- package/dist/providers/spawn.js +5 -0
- package/dist/schemas/index.js +572 -13
- package/dist/skills/idea-refinement/analyst.md +18 -14
- package/dist/skills/idea-refinement/economics-delivery.md +7 -0
- package/dist/skills/idea-refinement/market-adoption.md +7 -0
- package/dist/storage/runs.js +11 -4
- package/dist/tui/app.js +37 -13
- package/dist/tui/format.js +4 -5
- package/dist/tui/smart-entry.js +17 -1
- package/dist/tui/timeline.js +2 -4
- package/dist/workflows/code-review.js +4 -2
- package/dist/workflows/idea-refinement.js +110 -46
- package/package.json +12 -4
- package/dist/orchestration/stages/s0-grill.js +0 -79
- package/dist/orchestration/stages/s1-intent.js +0 -25
- package/dist/orchestration/stages/s2-misread.js +0 -76
- package/dist/orchestration/stages/s3-prompts.js +0 -55
- package/dist/orchestration/stages/s6-claims.js +0 -56
- package/dist/orchestration/stages/s7-disagreement.js +0 -134
|
@@ -7,22 +7,22 @@ where it breaks. Steelman it once, then attack it honestly.
|
|
|
7
7
|
- Before attacking, state the best honest version of the idea: who it is for and why it would win.
|
|
8
8
|
- Attack THAT version, not a weak strawman. If the steelman is thin, that itself is a finding.
|
|
9
9
|
|
|
10
|
-
##
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
- Flag
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- Prefer the
|
|
10
|
+
## Positions — make the stance explicit
|
|
11
|
+
- State each decision-critical proposition and take an explicit SUPPORT, OPPOSE, MIXED, or UNKNOWN
|
|
12
|
+
stance. Mark whether the basis is EVIDENCE, INFERENCE, or ASSUMPTION.
|
|
13
|
+
- Flag load-bearing positions and say whether falsity means STOP, PIVOT, CONDITION, or MINOR.
|
|
14
|
+
|
|
15
|
+
## Evidence — anchored and honest
|
|
16
|
+
- Anchor evidence cards to position IDs. Distinguish user material, primary sources, secondary
|
|
17
|
+
sources, and model knowledge; never invent a source or URL.
|
|
18
|
+
- Model knowledge cannot settle current, numeric, legal, medical, financial, market, or regulatory
|
|
19
|
+
facts. Mark uncertainty instead of laundering memory into evidence.
|
|
20
|
+
- Prefer the objection a smart skeptic would actually make: no strawmen or cosmetic caveats.
|
|
21
21
|
|
|
22
22
|
## MANDATORY coverage — address every dimension below
|
|
23
23
|
Do not leave a dimension unexamined; an unaddressed dimension is a hole in your analysis, not a
|
|
24
24
|
neutral omission. For each, either raise an assumption/attack or state plainly why it is not a
|
|
25
|
-
concern for THIS idea:
|
|
25
|
+
concern for THIS idea using a reasoned NOT_APPLICABLE coverage entry:
|
|
26
26
|
1. Target user / who this is actually for.
|
|
27
27
|
2. Existing alternatives — including "do nothing" and the status quo.
|
|
28
28
|
3. Differentiation — why this wins over those alternatives.
|
|
@@ -35,11 +35,15 @@ concern for THIS idea:
|
|
|
35
35
|
10. Timing — why now, and what makes the market ready or not.
|
|
36
36
|
11. Scalability — what breaks as it grows.
|
|
37
37
|
12. Key risks / assumptions that must be validated first.
|
|
38
|
+
13. Team / founder capability against the execution requirements.
|
|
39
|
+
|
|
40
|
+
Also cover every domain-specific dimension listed in the task contract. The lane prompt assigns
|
|
41
|
+
ownership; emit one explicit coverage entry for every owned dimension.
|
|
38
42
|
|
|
39
|
-
##
|
|
43
|
+
## Decision questions that move the verdict
|
|
40
44
|
- List only questions whose ANSWER would change the decision. "Nice to know" is not one of them.
|
|
41
45
|
- Phrase each so that a yes/no or a single number would actually flip your assessment.
|
|
42
46
|
|
|
43
47
|
## Do not
|
|
44
48
|
- No motivational framing, no pitch language, no summarizing your own output.
|
|
45
|
-
- No
|
|
49
|
+
- No unanchored position or evidence. No proposition you cannot tie to the decision.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Economics and delivery lane
|
|
2
|
+
|
|
3
|
+
Own unit economics and capital needs, technical and operational feasibility, supply constraints,
|
|
4
|
+
legal and compliance exposure, scalability, failure modes, and the cheapest decisive kill criteria.
|
|
5
|
+
|
|
6
|
+
Steelman the idea first. Cross into another lane only for a load-bearing issue. For every owned
|
|
7
|
+
dimension, emit a `COVERED` entry anchored to positions or a reasoned `NOT_APPLICABLE` entry.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Market and adoption lane
|
|
2
|
+
|
|
3
|
+
Own target-user urgency, alternatives and status quo, differentiation, distribution and procurement,
|
|
4
|
+
timing, and the team's ability to execute the required adoption motion.
|
|
5
|
+
|
|
6
|
+
Steelman the idea first. Cross into another lane only for a load-bearing issue. For every owned
|
|
7
|
+
dimension, emit a `COVERED` entry anchored to positions or a reasoned `NOT_APPLICABLE` entry.
|
package/dist/storage/runs.js
CHANGED
|
@@ -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 {
|
|
15
|
+
import { ActionPlanArtifact, DecisionContractArtifact, DecisionGraph, DisagreementMap, IdeaRoleOutput, JudgeReport, PreflightArtifact, RebuttalEventSet, ReviewMap, RoleOutput, RunBrief, RunMeta, 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`);
|
|
@@ -29,17 +29,24 @@ export class DuplicateWriteError extends Error {
|
|
|
29
29
|
* are written as-is; their schemas land with S2/S5/S6 (T5–T6). */
|
|
30
30
|
const JSON_SLOTS = {
|
|
31
31
|
'run-brief': { ord: 0.5, path: '00b-run-brief.json', schema: RunBrief },
|
|
32
|
-
'intent-contract': { ord: 1, path: '01-intent-contract.json', schema:
|
|
32
|
+
'intent-contract': { ord: 1, path: '01-intent-contract.json', schema: DecisionContractArtifact },
|
|
33
|
+
'preflight-readings': { ord: 2, path: '02-preflight-readings.json', schema: PreflightArtifact },
|
|
33
34
|
'misunderstanding-guard': { ord: 2, path: '02-misunderstanding-guard.json', schema: null },
|
|
34
35
|
'drift-report': { ord: 5, path: '05-drift-report.json', schema: null },
|
|
36
|
+
positions: { ord: 6, path: '06-positions.json', schema: null },
|
|
37
|
+
'coverage-fill': { ord: 6.5, path: '06b-coverage-fill.json', schema: IdeaRoleOutput },
|
|
35
38
|
claims: { ord: 6, path: '06-claims.json', schema: null },
|
|
39
|
+
'decision-graph': { ord: 7, path: '07-decision-graph.json', schema: DecisionGraph },
|
|
36
40
|
'disagreement-map': { ord: 7, path: '07-disagreement-map.json', schema: DisagreementMap },
|
|
37
41
|
// code-review's stage-7 artifact (ord 7, distinct path). A run writes one of {disagreement-map,
|
|
38
42
|
// review-map} depending on its workflow, so the shared ord never collides within a run.
|
|
39
43
|
'review-map': { ord: 7, path: '07-review-map.json', schema: ReviewMap },
|
|
40
|
-
verifications: { ord: 8, path: '08-verifications.json', schema:
|
|
44
|
+
verifications: { ord: 8, path: '08-verifications.json', schema: VerificationArtifact },
|
|
45
|
+
rebuttals: { ord: 8.5, path: '08b-rebuttals.json', schema: RebuttalEventSet },
|
|
41
46
|
'judge-report': { ord: 9, path: '09-judge-report.json', schema: JudgeReport },
|
|
42
|
-
'action-plan': { ord: 9.5, path: '09b-action-plan.json', schema:
|
|
47
|
+
'action-plan': { ord: 9.5, path: '09b-action-plan.json', schema: ActionPlanArtifact },
|
|
48
|
+
// machine-readable final report (three-level report v4); schema-less: derived output, never re-read by stages
|
|
49
|
+
'decision-report': { ord: 10, path: '10-decision-report.json', schema: null },
|
|
43
50
|
};
|
|
44
51
|
/** Text (markdown) stage slots (§15). */
|
|
45
52
|
const TEXT_SLOTS = {
|
package/dist/tui/app.js
CHANGED
|
@@ -8,8 +8,9 @@ import Spinner from 'ink-spinner';
|
|
|
8
8
|
import TextInput from 'ink-text-input';
|
|
9
9
|
import { readFile } from 'node:fs/promises';
|
|
10
10
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
11
|
-
import { DISPLAY_NAME } from '../providers/types.js';
|
|
12
|
-
import {
|
|
11
|
+
import { DISPLAY_NAME, PROVIDER_IDS } from '../providers/types.js';
|
|
12
|
+
import { preflightLine, runDoctorChecks } from '../cli/doctor.js';
|
|
13
|
+
import { RunCtx, makeRunId, resolveRoles, setupProviders, } from '../orchestration/context.js';
|
|
13
14
|
import { executeRun } from '../orchestration/engine.js';
|
|
14
15
|
import { RunWriter } from '../storage/runs.js';
|
|
15
16
|
import { recordSession, updateSessionStatus, readSessions, findSession } from '../storage/sessions.js';
|
|
@@ -21,6 +22,8 @@ import { CR_STAGES, runCodeReview } from '../workflows/code-review.js';
|
|
|
21
22
|
import { computeDiff, computeWorkingTreeDiff, detectRepoStatus } from '../orchestration/git.js';
|
|
22
23
|
import { loadCouncilView } from '../council/view.js';
|
|
23
24
|
import { openCouncilHtml } from '../council/open.js';
|
|
25
|
+
import { readJsonArtifact } from '../storage/runs-read.js';
|
|
26
|
+
import { defaultBudgetFor } from '../orchestration/modes.js';
|
|
24
27
|
import { GLYPH, displayNames, elapsedLabel, initTimeline, markEnd, markStart, progressBar, runningPhrase, totalElapsed } from './timeline.js';
|
|
25
28
|
import { formatCompletion, formatError } from './format.js';
|
|
26
29
|
import { COMMANDS, PRODUCT_LINE, filterCommands, parseCommand, routeInput, scopeRedirect, suggestCommand } from './smart-entry.js';
|
|
@@ -28,7 +31,7 @@ async function loadCompletion(dir) {
|
|
|
28
31
|
try {
|
|
29
32
|
const [judge, map] = await Promise.all([
|
|
30
33
|
readFile(join(dir, '09-judge-report.json'), 'utf8').then((s) => JSON.parse(s)),
|
|
31
|
-
readFile(join(dir, '07-
|
|
34
|
+
readFile(join(dir, '07-decision-graph.json'), 'utf8').then((s) => JSON.parse(s)),
|
|
32
35
|
]);
|
|
33
36
|
return formatCompletion(dir, judge, map);
|
|
34
37
|
}
|
|
@@ -67,16 +70,24 @@ export function App(props) {
|
|
|
67
70
|
const [aborted, setAborted] = useState(false);
|
|
68
71
|
const abortRef = useRef(null);
|
|
69
72
|
const ctxRef = useRef(null);
|
|
70
|
-
//
|
|
73
|
+
// Startup preflight (full doctor: CLI presence, version, auth/quota smoke — smoke cached ≤6h).
|
|
74
|
+
const [checks, setChecks] = useState({});
|
|
75
|
+
const [preflightFail, setPreflightFail] = useState(null);
|
|
76
|
+
// Full doctor preflight + provider handles + repo context once, up front. The menu only shows
|
|
77
|
+
// when ≥2 providers pass; a failure stays on this screen with the exact fix per provider.
|
|
71
78
|
useEffect(() => {
|
|
72
79
|
let alive = true;
|
|
73
|
-
void Promise.all([
|
|
80
|
+
void Promise.all([
|
|
81
|
+
setupProviders(providerModels),
|
|
82
|
+
runDoctorChecks({ onRow: (row) => { if (alive)
|
|
83
|
+
setChecks((prev) => ({ ...prev, [row.det.id]: preflightLine(row) })); } }),
|
|
84
|
+
detectRepoStatus(process.cwd()),
|
|
85
|
+
]).then(([hs, report, repoStatus]) => {
|
|
74
86
|
if (!alive)
|
|
75
87
|
return;
|
|
76
88
|
setRepo(repoStatus);
|
|
77
|
-
if (hs.length < 2) {
|
|
78
|
-
|
|
79
|
-
setPhase('finished');
|
|
89
|
+
if (report.ready < 2 || hs.length < 2) {
|
|
90
|
+
setPreflightFail(report);
|
|
80
91
|
return;
|
|
81
92
|
}
|
|
82
93
|
setHandles(hs);
|
|
@@ -93,6 +104,8 @@ export function App(props) {
|
|
|
93
104
|
const t = setInterval(() => setNow(Date.now()), 500);
|
|
94
105
|
return () => clearInterval(t);
|
|
95
106
|
}, [phase]);
|
|
107
|
+
// Preflight rows that failed but left quorum intact — surfaced as a warning on the home screen.
|
|
108
|
+
const degraded = Object.values(checks).filter((line) => !!line && !line.ok);
|
|
96
109
|
// V10 command palette: matches for what's being typed (only on the input screen, not mid-confirm).
|
|
97
110
|
const paletteMatches = phase === 'input' && pendingIdea === null ? filterCommands(idea) : [];
|
|
98
111
|
const selIdx = Math.min(sel, Math.max(paletteMatches.length - 1, 0));
|
|
@@ -130,6 +143,11 @@ export function App(props) {
|
|
|
130
143
|
exit();
|
|
131
144
|
return;
|
|
132
145
|
}
|
|
146
|
+
// Failed preflight: any of q / Esc / Enter leaves — there is nothing else to do here.
|
|
147
|
+
if (phase === 'detecting' && preflightFail && (input === 'q' || key.escape || key.return)) {
|
|
148
|
+
exit();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
133
151
|
// V10 confirm gate: the TextInput is unmounted while pending, so Enter/Esc arrive here only.
|
|
134
152
|
if (phase === 'input' && pendingIdea !== null) {
|
|
135
153
|
if (key.return) {
|
|
@@ -198,7 +216,7 @@ export function App(props) {
|
|
|
198
216
|
if (phase === 'finished')
|
|
199
217
|
exit();
|
|
200
218
|
});
|
|
201
|
-
const startRun = (wf, text, cwd, runner, stages, replay) => {
|
|
219
|
+
const startRun = (wf, text, cwd, runner, stages, replay, mode) => {
|
|
202
220
|
const trimmed = text.trim();
|
|
203
221
|
if (!trimmed)
|
|
204
222
|
return;
|
|
@@ -242,7 +260,7 @@ export function App(props) {
|
|
|
242
260
|
setPhase('clarify');
|
|
243
261
|
}),
|
|
244
262
|
};
|
|
245
|
-
const ctx = new RunCtx({ runId, workflow: wf, handles, roles: rs, writer, cwd: cwd ?? writer.dir, budget: budgetOverride, signal: controller.signal, events, replay });
|
|
263
|
+
const ctx = new RunCtx({ runId, workflow: wf, mode, handles, roles: rs, writer, cwd: cwd ?? writer.dir, budget: budgetOverride, signal: controller.signal, events, replay });
|
|
246
264
|
ctxRef.current = ctx;
|
|
247
265
|
setWorkflow(wf);
|
|
248
266
|
setRows(initTimeline(stages, rs, available));
|
|
@@ -341,7 +359,8 @@ export function App(props) {
|
|
|
341
359
|
if (replay.size === 0)
|
|
342
360
|
return void setRouterMessage(`no completed calls for ${sess.id} — start fresh`);
|
|
343
361
|
const [runner, stages] = wf === 'code-review' ? [runCodeReview, CR_STAGES] : [runIdeaRefinement, IDEA_STAGES];
|
|
344
|
-
|
|
362
|
+
const meta = await readJsonArtifact(oldDir, 'meta.json');
|
|
363
|
+
startRun(wf, input, wf === 'code-review' ? sess.cwd : null, runner, stages, replay, meta?.mode);
|
|
345
364
|
};
|
|
346
365
|
const runCommand = async (p) => {
|
|
347
366
|
setRouterMessage('');
|
|
@@ -421,9 +440,14 @@ export function App(props) {
|
|
|
421
440
|
setPendingIdea(text);
|
|
422
441
|
};
|
|
423
442
|
// ── render ────────────────────────────────────────────────────────────────
|
|
424
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "aiki" }), version ? _jsxs(Text, { dimColor: true, children: [" v", version] }) : null, _jsxs(Text, { dimColor: true, children: [" \u00B7 ", phase === 'input' ? 'local model council — ideas & code review' : workflow] })] }), phase === 'detecting' && (_jsxs(
|
|
443
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "aiki" }), version ? _jsxs(Text, { dimColor: true, children: [" v", version] }) : null, _jsxs(Text, { dimColor: true, children: [" \u00B7 ", phase === 'input' ? 'local model council — ideas & code review' : workflow] })] }), phase === 'detecting' && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "preflight \u2014 checking provider CLIs, auth & quota (smoke cached \u22646h)" }), PROVIDER_IDS.map((id) => {
|
|
444
|
+
const line = checks[id];
|
|
445
|
+
return (_jsxs(Text, { children: [line
|
|
446
|
+
? line.ok ? _jsx(Text, { color: "green", children: "\u2714" }) : _jsx(Text, { color: "red", children: "\u2716" })
|
|
447
|
+
: _jsx(Text, { color: "yellow", children: _jsx(Spinner, { type: "dots" }) }), ' ', line ? line.label : `${DISPLAY_NAME[id]} — checking…`, line?.fix ? _jsxs(Text, { dimColor: true, children: [" \u2192 ", line.fix] }) : null] }, id));
|
|
448
|
+
}), preflightFail && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: "red", bold: true, children: ["preflight failed \u2014 ", preflightFail.ready, "/3 providers ready (aiki needs 2)"] }), _jsx(Text, { dimColor: true, children: "apply the fix shown next to each \u2716, then run `aiki` again \u00B7 `aiki doctor --fresh` re-checks live \u00B7 q quits" })] }))] })), (phase === 'input' || phase === 'running' || phase === 'grill' || phase === 'clarify' || phase === 'finished') && handles.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [repo && (_jsxs(Text, { children: ["repo: ", repo.name, " \u2014 ", repo.changedFiles, " changed files vs ", repo.defaultBranch ?? 'unknown default branch'] })), _jsxs(Text, { children: [handles.map((h, i) => (_jsxs(Text, { children: [i > 0 ? _jsx(Text, { dimColor: true, children: " \u00B7 " }) : null, _jsx(Text, { color: "green", children: "\u2714" }), " ", DISPLAY_NAME[h.id], h.version ? _jsxs(Text, { dimColor: true, children: [" ", h.version] }) : null] }, h.id))), _jsx(Text, { dimColor: true, children: " \u2014 council ready" })] }), degraded.length > 0 && (_jsxs(Text, { color: "yellow", children: ["\u26A0 ", degraded.map((line) => `${line.label}${line.fix ? ` (${line.fix})` : ''}`).join(' · '), " \u2014 continuing with ", Math.max(handles.length - degraded.length, 0), "/3 providers"] }))] })), phase === 'input' && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "/idea " }), _jsx(Text, { dimColor: true, children: '<text>' }), ' stress-test an idea'] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "/review " }), _jsx(Text, { dimColor: true, children: "[--branch]" }), ' review your changes', repo ? '' : _jsx(Text, { dimColor: true, children: " (needs a git repo)" })] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "/resume " }), _jsx(Text, { dimColor: true, children: '<id>' }), ' continue a stopped run · ', _jsx(Text, { color: "cyan", children: "/sessions" }), ' ', _jsx(Text, { color: "cyan", children: "/models" }), ' ', _jsx(Text, { color: "cyan", children: "/config" }), ' ', _jsx(Text, { color: "cyan", children: "/help" })] })] }), pendingIdea !== null ? (
|
|
425
449
|
/* V10 confirm gate — nothing spends model calls until Enter. */
|
|
426
|
-
_jsxs(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [_jsx(Text, { children: "Run the idea council on:" }), _jsxs(Text, { color: "cyan", children: [" \u201C", pendingIdea.length > 100 ? `${pendingIdea.slice(0, 97)}…` : pendingIdea, "\u201D"] }), _jsxs(Text, { dimColor: true, children: ["
|
|
450
|
+
_jsxs(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [_jsx(Text, { children: "Run the idea council on:" }), _jsxs(Text, { color: "cyan", children: [" \u201C", pendingIdea.length > 100 ? `${pendingIdea.slice(0, 97)}…` : pendingIdea, "\u201D"] }), _jsxs(Text, { dimColor: true, children: [" 10-stage pipeline \u00B7 up to ", budgetOverride ?? defaultBudgetFor('idea-refinement', 'council'), " model calls \u00B7 Ctrl+C aborts mid-run"] }), _jsxs(Text, { children: [_jsx(Text, { color: "green", children: "enter" }), " run \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " cancel"] })] })) : (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "Type a command, or just describe your idea and press Enter:" }), _jsxs(Box, { borderStyle: "round", paddingX: 1, children: [_jsx(Text, { children: "\u25B8 " }), _jsx(TextInput, { value: idea, onChange: (v) => setIdea(v.replace(/\s*[\r\n]+\s*/g, ' ').replace(/\t/g, '')), onSubmit: submitInput }, inputEpoch)] })] })), paletteMatches.length > 0 && (
|
|
427
451
|
/* V10 live command palette — filtered as you type; ↑↓ move, Tab completes, Enter runs. */
|
|
428
452
|
_jsxs(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [paletteMatches.map((m, i) => (_jsxs(Text, { children: [_jsxs(Text, { color: i === selIdx ? 'cyan' : undefined, bold: i === selIdx, children: [i === selIdx ? '▸ ' : ' ', "/", m.name] }), _jsx(Text, { dimColor: true, children: ` ${m.usage.replace(`/${m.name}`, '').trim().padEnd(10)} ${m.help}` })] }, m.name))), _jsx(Text, { dimColor: true, children: "\u2191\u2193 select \u00B7 tab complete \u00B7 enter run" })] })), routerMessage ? _jsx(Text, { color: "yellow", children: routerMessage }) : null, panel ? (_jsx(Box, { flexDirection: "column", marginTop: 1, borderStyle: "round", paddingX: 1, children: panel.split('\n').map((l, i) => (_jsx(Text, { children: l }, i))) })) : (_jsx(Text, { dimColor: true, children: "new here? /help explains how aiki works \u00B7 long idea? `aiki run idea-refinement ./idea.md`" }))] })), (phase === 'running' || phase === 'grill' || phase === 'clarify' || phase === 'finished') && rows.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [rows.map((r) => {
|
|
429
453
|
const color = r.status === 'done' ? 'green' : r.status === 'failed' ? 'red' : r.status === 'running' ? 'yellow' : 'gray';
|
package/dist/tui/format.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
// Pure formatters for the completion + error screens (T8, §4.3, §471). No Ink — unit-tested directly.
|
|
2
2
|
/** Completion summary (§4.3): verdict + the top-N contradictions with their adjudication ruling. */
|
|
3
|
-
export function formatCompletion(dir, judge,
|
|
3
|
+
export function formatCompletion(dir, judge, graph, topN = 3) {
|
|
4
4
|
const ruling = new Map(judge.adjudications.map((a) => [a.id, a.ruling]));
|
|
5
|
-
const disagreements =
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
return `${d.id} → ${r}: ${arg}`;
|
|
5
|
+
const disagreements = graph.claims.filter((claim) => claim.state === 'DISAGREEMENT').slice(0, topN).map((claim) => {
|
|
6
|
+
const result = ruling.get(claim.id) ?? 'UNRESOLVED';
|
|
7
|
+
return `${claim.id} → ${result}: ${claim.proposition}`;
|
|
9
8
|
});
|
|
10
9
|
return { verdict: judge.verdict, disagreements, reportPath: `${dir}/final-report.md`, rawPath: `${dir}/raw/` };
|
|
11
10
|
}
|
package/dist/tui/smart-entry.js
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
export const PRODUCT_LINE = 'aiki stress-tests ideas and reviews code; for general questions use a single model — a council adds cost, not accuracy, when there is one right answer.';
|
|
2
2
|
const QUESTION_START = /^(what|why|how|who|when|where|is|are|can|could|should|would|do|does|did|will)\b/i;
|
|
3
|
-
|
|
3
|
+
// Detect PASTED code / a diff, NOT prose that merely contains a code-ish word. Bare keywords
|
|
4
|
+
// (`class`, `export`, `import`) and a lone `;`/`{`/`}` collide with ordinary English — "a class
|
|
5
|
+
// scheduling app; export our data" is an idea, not a diff — so every alternative below requires code
|
|
6
|
+
// *structure*: a diff/fence marker, a file path with a code extension, arrow/`){`, or a keyword in
|
|
7
|
+
// real syntax (`class Foo {`, `const x =`, `import { … }` / `import x from '…'`, `export default/const…`).
|
|
8
|
+
const CODE_MARKER = new RegExp([
|
|
9
|
+
'diff --git', '^@@', '^\\+\\+\\+ b/', '^--- a/', // unified-diff headers
|
|
10
|
+
'```', // markdown code fence
|
|
11
|
+
'[A-Za-z0-9_-]+/[A-Za-z0-9_./-]+\\.(?:ts|tsx|js|jsx|py|go|rs|java|rb|php|css|html|md)\\b', // path/to/file.ext
|
|
12
|
+
'=>', // arrow function
|
|
13
|
+
'\\)\\s*\\{', // ) { — block open
|
|
14
|
+
'\\bfunction\\s+[A-Za-z_$][\\w$]*\\s*\\(|\\bfunction\\s*\\(', // function foo( / function(
|
|
15
|
+
'\\bclass\\s+[A-Za-z_$][\\w$]*\\s*(?:\\{|extends\\b)', // class Foo { / class Foo extends
|
|
16
|
+
'\\b(?:const|let|var)\\s+[A-Za-z_$][\\w$]*\\s*=', // const x =
|
|
17
|
+
"\\bimport\\s+(?:\\{|[\\w$]+\\s+from\\s+['\"]|['\"])", // import { … } / import x from '…' / import '…'
|
|
18
|
+
'\\bexport\\s+(?:default|const|let|var|function|class|async|\\{)', // export default / export const / …
|
|
19
|
+
].join('|'), 'm');
|
|
4
20
|
// ── Scope redirect (V10.2) — catch "explore my whole codebase / brainstorm features for me" asks and
|
|
5
21
|
// point them at the right door, instead of silently stress-testing the request sentence as an "idea".
|
|
6
22
|
// aiki reviews a DIFF and vets a STATED idea; it does not roam a repo (§3/§22). Pure + deterministic. ──
|
package/dist/tui/timeline.js
CHANGED
|
@@ -56,15 +56,13 @@ export const displayNames = (ps) => ps.map((p) => DISPLAY_NAME[p]).join(', ');
|
|
|
56
56
|
// ── V10 run-screen life: rotating status phrases + progress bar + total time. Pure; unit-tested. ────
|
|
57
57
|
/** Stage-flavored status phrases, rotated every 4s so long stages feel alive (not stuck). */
|
|
58
58
|
const PHRASES = {
|
|
59
|
-
S0: ['
|
|
60
|
-
S1: ['pinning down what you actually asked', 'writing the task contract'],
|
|
61
|
-
S2: ['checking every model read it the same way', 'guarding against a misread'],
|
|
62
|
-
S3: ["writing each seat's brief", 'tailoring the role prompts'],
|
|
59
|
+
S0: ['comparing two readings of your decision', 'sharpening one decision contract'],
|
|
63
60
|
S4: ['council working in separate rooms', 'independent takes incoming'],
|
|
64
61
|
S5: ['checking nobody drifted off-task', 'comparing echoes against the contract'],
|
|
65
62
|
S6: ['boiling the output down to claims', 'extracting the claims'],
|
|
66
63
|
S7: ['mapping where they disagree', 'drawing the disagreement map'],
|
|
67
64
|
S8: ['cross-examining the claims', 'stress-testing the evidence'],
|
|
65
|
+
S8b: ['rebutting only what could flip the verdict', 'testing the decisive conflict'],
|
|
68
66
|
S9: ['the judge is deliberating', 'weighing evidence over confidence'],
|
|
69
67
|
S9b: ['planning decisive validation', 'ordering the next tests'],
|
|
70
68
|
S10: ['writing the report', 'assembling the decision brief'],
|
|
@@ -10,6 +10,7 @@ import { resolve } from 'node:path';
|
|
|
10
10
|
import { runStage } from '../orchestration/context.js';
|
|
11
11
|
import { parseDiffFiles } from '../orchestration/git.js';
|
|
12
12
|
import { s4Review } from '../orchestration/stages/cr-s4-review.js';
|
|
13
|
+
import { mergeCoverageHunt, runCoverageHunts } from '../orchestration/stages/cr-ladder.js';
|
|
13
14
|
import { s8CrossExam } from '../orchestration/stages/cr-s8-crossexam.js';
|
|
14
15
|
import { buildReviewMap } from '../orchestration/stages/cr-map.js';
|
|
15
16
|
import { s9ReviewJudge } from '../orchestration/stages/cr-s9-judge.js';
|
|
@@ -44,7 +45,7 @@ export const CR_STAGES = [
|
|
|
44
45
|
{ id: 'S9', label: 'Judge adjudication', role: 'judge' },
|
|
45
46
|
{ id: 'S10', label: 'Report', role: null },
|
|
46
47
|
];
|
|
47
|
-
export async function runCodeReview(ctx, input) {
|
|
48
|
+
export async function runCodeReview(ctx, input, opts = {}) {
|
|
48
49
|
// `input` is the unified diff. Persist it where the reviewer prompt points; parse the touched files.
|
|
49
50
|
await ctx.writer.writeInput('diff.patch', input);
|
|
50
51
|
const diffPath = resolve(ctx.writer.dir, 'inputs', 'diff.patch');
|
|
@@ -63,10 +64,11 @@ export async function runCodeReview(ctx, input) {
|
|
|
63
64
|
const prompt = buildReviewerPrompt(diffPath, loadSkill('code-review', 'reviewer'));
|
|
64
65
|
await ctx.writer.writePrompt('reviewer.md', prompt);
|
|
65
66
|
const reviewers = await runStage(ctx, 'S4', () => s4Review(ctx, prompt, files));
|
|
67
|
+
const ladder = opts.ladder ? await runStage(ctx, 'L', () => runCoverageHunts(ctx, input, reviewers)) : null;
|
|
66
68
|
const cross = await runStage(ctx, 'S8', () => s8CrossExam(ctx, reviewers));
|
|
67
69
|
// S7 — build + persist the ReviewMap (07), then the cross-exam verifications (08). Order: 07 < 08.
|
|
68
70
|
const map = await runStage(ctx, 'S7', async () => {
|
|
69
|
-
const m = buildReviewMap(reviewers, cross.byKey);
|
|
71
|
+
const m = mergeCoverageHunt(buildReviewMap(reviewers, cross.byKey), ladder);
|
|
70
72
|
await ctx.writer.writeJson('review-map', m);
|
|
71
73
|
await ctx.writer.writeJson('verifications', { verifications: cross.verifications });
|
|
72
74
|
return m;
|
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
// idea-refinement
|
|
2
|
-
//
|
|
3
|
-
// full skill loader + registry, §11, is deferred; it must not register without bench/ + validate.ts).
|
|
4
|
-
//
|
|
5
|
-
// v1 T5 scope: S1 → S2 → S3. S4–S10 are added as later tasks extend this composition.
|
|
1
|
+
// idea-refinement composition. R6 collapses the old S0/S1/S2 model chain into two parallel
|
|
2
|
+
// preflight readings and fills the S4 prompt deterministically; later stages remain typed boundaries.
|
|
6
3
|
import { resolve } from 'node:path';
|
|
7
|
-
import { runStage } from '../orchestration/context.js';
|
|
8
|
-
import { renderGrilledInput, s0Grill } from '../orchestration/stages/s0-grill.js';
|
|
9
|
-
import { s1Intent } from '../orchestration/stages/s1-intent.js';
|
|
10
|
-
import { s2Misread } from '../orchestration/stages/s2-misread.js';
|
|
11
|
-
import { s3Prompts } from '../orchestration/stages/s3-prompts.js';
|
|
4
|
+
import { runStage, StageError } from '../orchestration/context.js';
|
|
12
5
|
import { s4Analyze } from '../orchestration/stages/s4-analyze.js';
|
|
13
6
|
import { s5Drift } from '../orchestration/stages/s5-drift.js';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
7
|
+
import { s6Positions } from '../orchestration/stages/s6-positions.js';
|
|
8
|
+
import { s7DecisionGraph } from '../orchestration/stages/s7-decision-graph.js';
|
|
16
9
|
import { s8Verify } from '../orchestration/stages/s8-verify.js';
|
|
10
|
+
import { s8bRebuttal } from '../orchestration/stages/s8b-rebuttal.js';
|
|
17
11
|
import { s9Judge } from '../orchestration/stages/s9-judge.js';
|
|
18
12
|
import { s9bPlan } from '../orchestration/stages/s9b-plan.js';
|
|
19
13
|
import { s10Render } from '../orchestration/stages/s10-render.js';
|
|
20
14
|
import { loadSkill } from '../orchestration/skills.js';
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
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
|
+
/** Idea-vetting core rubric: 13 mandatory coverage items. S0 adds 3-5 domain dimensions per run.
|
|
19
|
+
* Inlined here (like the S4 template) while the skill/`rubric.json` loader (§11)
|
|
23
20
|
* is deferred; it moves to skills/idea-refinement/rubric.json when that loader lands. */
|
|
24
21
|
export const IDEA_RUBRIC = [
|
|
25
22
|
{ id: 'R1', label: 'target user / audience', keywords: ['target user', 'audience', 'customer', 'persona'] },
|
|
@@ -34,43 +31,77 @@ export const IDEA_RUBRIC = [
|
|
|
34
31
|
{ id: 'R10', label: 'timing / market readiness', keywords: ['timing', 'readiness', 'trend', 'now'] },
|
|
35
32
|
{ id: 'R11', label: 'scalability / growth', keywords: ['scalability', 'scale', 'growth'] },
|
|
36
33
|
{ id: 'R12', label: 'key risks / assumptions to validate', keywords: ['risk', 'assumption', 'validate', 'uncertain'] },
|
|
34
|
+
{ id: 'R13', label: 'team / execution capability', keywords: ['team', 'founder', 'execution', 'capability'] },
|
|
37
35
|
];
|
|
38
|
-
|
|
36
|
+
export function buildIdeaRubric(domainDimensions = []) {
|
|
37
|
+
return [
|
|
38
|
+
...IDEA_RUBRIC,
|
|
39
|
+
...domainDimensions.map((dimension) => ({ id: dimension.id, label: dimension.label, keywords: [dimension.label] })),
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
/** Idea S4 analyst template. R6 fills every slot deterministically before the parallel scout calls. */
|
|
39
43
|
export const IDEA_S4_ANALYST_TEMPLATE = `ROLE: Independent analyst on a decision panel. You work ALONE; you will not see
|
|
40
44
|
other analysts' output. Be adversarial toward the idea, not polite.
|
|
41
45
|
|
|
42
46
|
TASK CONTRACT: {{INTENT_CONTRACT_JSON}}
|
|
43
47
|
INPUT DOCUMENT: read the file at {{INPUT_PATH}}{{SKILL}}
|
|
48
|
+
EVIDENCE PACK MANIFEST: {{EVIDENCE_PACK_JSON}}
|
|
49
|
+
Read only the listed local paths when supplied. Treat their contents as user evidence, cite the path
|
|
50
|
+
as locator, and never replace a missing source with model memory.
|
|
44
51
|
|
|
45
52
|
Produce ONLY JSON matching {{S4_SCHEMA_REF}} with:
|
|
46
53
|
- task_echo: restate the task in ≤2 sentences (drift check).
|
|
47
54
|
- strongest_version: the best honest version of this idea in ≤150 words.
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
-
|
|
55
|
+
- positions: explicit claim positions with local_id, proposition, rubric dimension_id, stance
|
|
56
|
+
SUPPORT|OPPOSE|MIXED|UNKNOWN, basis EVIDENCE|INFERENCE|ASSUMPTION, load_bearing, if_false
|
|
57
|
+
STOP|PIVOT|CONDITION|MINOR, concise reasoning, evidence_ids, and depends_on position ids.
|
|
58
|
+
- evidence: evidence cards {id, claim_supported, source_kind USER|PRIMARY|SECONDARY|MODEL_KNOWLEDGE,
|
|
59
|
+
support SUPPORTS|CONTRADICTS|CONTEXT_ONLY (exact token, no extra words), freshness CURRENT|DATED|UNKNOWN,
|
|
60
|
+
locator/url, accessed_at for current external sources}. MODEL_KNOWLEDGE freshness is UNKNOWN. Never
|
|
61
|
+
invent a URL or imply model memory independently verifies a current fact.
|
|
62
|
+
- calculations: for each derived numeric claim, a ledger {id, claim_id, inputs, steps, result_step}.
|
|
63
|
+
Inputs have {id,name,value,unit,evidence_ids}; steps have {id,operation: ADD|SUBTRACT|MULTIPLY|DIVIDE,
|
|
64
|
+
left,right,result,unit}. Use exact prior input/step ids and explicit units. Otherwise use [].
|
|
65
|
+
- coverage: one entry per rubric dimension {dimension_id, status COVERED|NOT_APPLICABLE,
|
|
66
|
+
position_ids ([] when none), rationale (required for NOT_APPLICABLE)}.
|
|
67
|
+
- decision_questions: questions {question, claim_ids} whose answers could change the verdict.
|
|
68
|
+
Caps: at most 12 positions, 20 evidence cards, 8 calculations, 8 decision_questions.
|
|
52
69
|
Rules: no motivation, no summaries of your own output, no markdown, JSON only.`;
|
|
53
70
|
/**
|
|
54
|
-
* Resolve the {{SKILL}} slot
|
|
55
|
-
*
|
|
56
|
-
* baseline; the S3 deterministic fallback then preserves the embedded playbook verbatim.
|
|
71
|
+
* Resolve the {{SKILL}} slot before deterministic structural fill. An empty skill collapses the slot
|
|
72
|
+
* to the pre-skill baseline.
|
|
57
73
|
*/
|
|
58
74
|
export function buildAnalystTemplate(skill) {
|
|
59
75
|
return IDEA_S4_ANALYST_TEMPLATE.replace('{{SKILL}}', skill ? `\n\n${skill}` : '');
|
|
60
76
|
}
|
|
77
|
+
/** R6 deterministic S4 prompt fill. No model-authored prompt generation remains. */
|
|
78
|
+
export function buildAnalystPrompt(contract, inputPath, evidencePack, mode, skill) {
|
|
79
|
+
const modeRules = mode === 'research'
|
|
80
|
+
? `\n\nMODE: research. Use provider-native read-only source investigation when available. Every current
|
|
81
|
+
fact must have an independently checkable locator and access date. If investigation is unavailable,
|
|
82
|
+
leave the claim unverified; never invent a source.`
|
|
83
|
+
: `\n\nMODE: council. Analyze independently; do not assume another seat will cover your lane.`;
|
|
84
|
+
const prompt = buildAnalystTemplate(skill)
|
|
85
|
+
.replace('{{INTENT_CONTRACT_JSON}}', JSON.stringify(contract))
|
|
86
|
+
.replace('{{INPUT_PATH}}', inputPath)
|
|
87
|
+
.replace('{{EVIDENCE_PACK_JSON}}', JSON.stringify(evidencePack ?? { files: [] }))
|
|
88
|
+
.replace('{{S4_SCHEMA_REF}}', 'the idea-refinement S4 RoleOutput schema')
|
|
89
|
+
+ modeRules;
|
|
90
|
+
if (/\{\{[^}]+\}\}/.test(prompt))
|
|
91
|
+
throw new StageError('S3', 'BAD_OUTPUT', 'deterministic analyst prompt has an unresolved slot');
|
|
92
|
+
return prompt;
|
|
93
|
+
}
|
|
61
94
|
/** Timeline manifest (T8): the stages in order, each with the provider-role its row displays.
|
|
62
95
|
* The TUI draws the pending skeleton from this and resolves chips from `ctx.roles`. Ids match the
|
|
63
96
|
* `runStage` calls below. S7 shows the judge (it makes the grouping call); S5/S6/S10 are pure (—). */
|
|
64
97
|
export const IDEA_STAGES = [
|
|
65
|
-
{ id: 'S0', label: '
|
|
66
|
-
{ id: 'S1', label: 'Intent contract', role: 'analyst' },
|
|
67
|
-
{ id: 'S2', label: 'Misunderstanding guard', role: 'all' },
|
|
68
|
-
{ id: 'S3', label: 'Prompt generation', role: 'analyst' },
|
|
98
|
+
{ id: 'S0', label: 'Two-view preflight', role: 's4' },
|
|
69
99
|
{ id: 'S4', label: 'Parallel analysis', role: 's4' },
|
|
70
100
|
{ id: 'S5', label: 'Drift check', role: null },
|
|
71
|
-
{ id: 'S6', label: '
|
|
72
|
-
{ id: 'S7', label: '
|
|
101
|
+
{ id: 'S6', label: 'Position collection', role: null },
|
|
102
|
+
{ id: 'S7', label: 'Decision graph', role: null },
|
|
73
103
|
{ id: 'S8', label: 'Verifier loop', role: 'verifier' },
|
|
104
|
+
{ id: 'S8b', label: 'Selective rebuttal', role: 's4' },
|
|
74
105
|
{ id: 'S9', label: 'Judge synthesis', role: 'judge' },
|
|
75
106
|
{ id: 'S9b', label: 'Validation plan', role: 'judge' },
|
|
76
107
|
{ id: 'S10', label: 'Report', role: null },
|
|
@@ -79,27 +110,60 @@ export const IDEA_STAGES = [
|
|
|
79
110
|
* `executeRun` wrapper turns that into a graceful failure + meta. Each stage is wrapped in
|
|
80
111
|
* `runStage` so the TUI timeline (T8) gets start/end events; headless, that's a no-op. */
|
|
81
112
|
export async function runIdeaRefinement(ctx, input) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const contract = await runStage(ctx, '
|
|
85
|
-
const
|
|
113
|
+
if (ctx.evidencePack)
|
|
114
|
+
await ctx.writer.writeInput('evidence-pack.json', JSON.stringify(ctx.evidencePack, null, 2));
|
|
115
|
+
const { contract, brief } = await runStage(ctx, 'S0', () => preflight(ctx, input, IDEA_RUBRIC.map((item) => item.label)));
|
|
116
|
+
const grilledInput = renderDecisionInput(input, brief);
|
|
86
117
|
// Persist the input as a file so S4's "read the file at {{INPUT_PATH}}" resolves (not a stage).
|
|
87
118
|
await ctx.writer.writeInput('idea.md', input);
|
|
88
119
|
await ctx.writer.writeInput('idea-brief.md', grilledInput);
|
|
89
120
|
const inputPath = resolve(ctx.writer.dir, 'inputs', 'idea-brief.md');
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
121
|
+
const rubric = buildIdeaRubric(contract.domain_dimensions);
|
|
122
|
+
const analystSkill = loadSkill('idea-refinement', 'analyst');
|
|
123
|
+
if (ctx.mode === 'quick') {
|
|
124
|
+
ctx.addFlag('single_model');
|
|
125
|
+
const quickPrompt = buildQuickPrompt(contract, inputPath, ctx.evidencePack, analystSkill);
|
|
126
|
+
await ctx.writer.writePrompt('quick-analyst.md', quickPrompt);
|
|
127
|
+
const quick = await runStage(ctx, 'S4', () => s4QuickAnalyze(ctx, quickPrompt));
|
|
128
|
+
const { kept } = await runStage(ctx, 'S5', () => s5Drift(ctx, contract, [quick.seat], 1));
|
|
129
|
+
const positions = await runStage(ctx, 'S6', () => s6Positions(ctx, kept));
|
|
130
|
+
const graph = await runStage(ctx, 'S7', () => s7DecisionGraph(ctx, positions, rubric, contract.task));
|
|
131
|
+
const verifications = await runStage(ctx, 'S8', async () => {
|
|
132
|
+
const result = { verifications: [] };
|
|
133
|
+
await ctx.writer.writeJson('verifications', result);
|
|
134
|
+
return result;
|
|
135
|
+
});
|
|
136
|
+
const rebuttals = await runStage(ctx, 'S8b', async () => {
|
|
137
|
+
const result = { round: 1, selected_claim_ids: [], events: [], stop_reason: 'NO_ESCALATIONS' };
|
|
138
|
+
await ctx.writer.writeJson('rebuttals', result);
|
|
139
|
+
return result;
|
|
140
|
+
});
|
|
141
|
+
const judgeReport = await runStage(ctx, 'S9', async () => {
|
|
142
|
+
const report = quickJudgeReport(quick.decision, graph);
|
|
143
|
+
await ctx.writer.writeJson('judge-report', report);
|
|
144
|
+
return report;
|
|
145
|
+
});
|
|
146
|
+
const actionPlan = await runStage(ctx, 'S9b', async () => {
|
|
147
|
+
const plan = quickActionPlan(ctx, quick.seat.provider, quick.decision, graph);
|
|
148
|
+
await ctx.writer.writeJson('action-plan', plan);
|
|
149
|
+
return plan;
|
|
150
|
+
});
|
|
151
|
+
await runStage(ctx, 'S10', () => s10Render(ctx, { contract, seats: kept, graph, verifications, rebuttals, judgeReport, actionPlan, rubric, original: input }));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (ctx.mode === 'research' && !ctx.evidencePack && !ctx.available().includes('codex')) {
|
|
155
|
+
ctx.addFlag('research_ungrounded');
|
|
156
|
+
}
|
|
157
|
+
const analystPrompt = buildAnalystPrompt(contract, inputPath, ctx.evidencePack, ctx.mode, analystSkill);
|
|
158
|
+
await ctx.writer.writePrompt('analyst.md', analystPrompt);
|
|
159
|
+
const lanePrompts = buildLanePrompts(analystPrompt, rubric);
|
|
160
|
+
const seats = await runStage(ctx, 'S4', () => s4Analyze(ctx, lanePrompts));
|
|
98
161
|
const { kept } = await runStage(ctx, 'S5', () => s5Drift(ctx, contract, seats));
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
const verifications = await runStage(ctx, 'S8', () => s8Verify(ctx,
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
await runStage(ctx, '
|
|
162
|
+
const positions = await runStage(ctx, 'S6', () => s6Positions(ctx, kept));
|
|
163
|
+
const graph = await runStage(ctx, 'S7', () => s7DecisionGraph(ctx, positions, rubric, contract.task));
|
|
164
|
+
const verifications = await runStage(ctx, 'S8', () => s8Verify(ctx, graph));
|
|
165
|
+
const rebuttals = await runStage(ctx, 'S8b', () => s8bRebuttal(ctx, graph, verifications, ctx.mode));
|
|
166
|
+
const judgeReport = await runStage(ctx, 'S9', () => s9Judge(ctx, contract, graph, verifications, rubric, rebuttals));
|
|
167
|
+
const actionPlan = await runStage(ctx, 'S9b', () => s9bPlan(ctx, contract, kept, graph, judgeReport));
|
|
168
|
+
await runStage(ctx, 'S10', () => s10Render(ctx, { contract, seats: kept, graph, verifications, rebuttals, judgeReport, actionPlan, rubric, original: input }));
|
|
105
169
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiki-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Local-first
|
|
3
|
+
"version": "0.3.0",
|
|
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",
|
|
7
7
|
"author": "Gaurav Palaspagar",
|
|
@@ -15,14 +15,22 @@
|
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
|
17
17
|
"cli",
|
|
18
|
+
"ai",
|
|
18
19
|
"llm",
|
|
19
20
|
"orchestration",
|
|
21
|
+
"model-council",
|
|
22
|
+
"developer-tools",
|
|
20
23
|
"code-review",
|
|
24
|
+
"ai-code-review",
|
|
21
25
|
"multi-model",
|
|
22
26
|
"claude",
|
|
27
|
+
"claude-code",
|
|
23
28
|
"codex",
|
|
24
29
|
"gemini",
|
|
25
|
-
"
|
|
30
|
+
"antigravity",
|
|
31
|
+
"local-first",
|
|
32
|
+
"no-api-keys",
|
|
33
|
+
"typescript"
|
|
26
34
|
],
|
|
27
35
|
"bin": {
|
|
28
36
|
"aiki": "dist/cli/index.js"
|
|
@@ -37,7 +45,7 @@
|
|
|
37
45
|
"node": ">=20"
|
|
38
46
|
},
|
|
39
47
|
"scripts": {
|
|
40
|
-
"build": "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})\"",
|
|
41
49
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
42
50
|
"test": "vitest run",
|
|
43
51
|
"test:watch": "vitest",
|