aiki-cli 0.3.1 → 0.3.2
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 +12 -5
- package/README.md +9 -11
- package/dist/bench/idea-v3-rating.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/run.js +1 -1
- package/dist/council/view.js +52 -12
- package/dist/orchestration/context.js +3 -3
- package/dist/orchestration/decision-dossier.js +417 -88
- package/dist/orchestration/decision-graph.js +31 -0
- package/dist/orchestration/legacy-idea-adapter.js +3 -0
- package/dist/orchestration/modes.js +15 -9
- package/dist/orchestration/preflight.js +17 -3
- package/dist/orchestration/quick-analysis.js +21 -4
- package/dist/orchestration/stages/s10-render.js +167 -79
- package/dist/orchestration/stages/s4-analyze.js +3 -1
- package/dist/orchestration/stages/s6-positions.js +18 -0
- package/dist/orchestration/stages/s7-decision-graph.js +3 -0
- package/dist/orchestration/stages/s8-verify.js +26 -9
- package/dist/orchestration/stages/s8b-rebuttal.js +11 -4
- package/dist/orchestration/stages/s9-judge.js +36 -13
- package/dist/orchestration/stages/s9b-plan.js +192 -42
- package/dist/schemas/index.js +67 -3
- package/dist/skills/idea-refinement/analyst.md +5 -5
- package/dist/skills/idea-refinement/chair.md +18 -0
- package/dist/skills/idea-refinement/economics-delivery.md +11 -0
- package/dist/skills/idea-refinement/market-adoption.md +12 -0
- package/dist/skills/idea-refinement/planner.md +25 -19
- package/dist/skills/idea-refinement/rebuttal.md +15 -0
- package/dist/skills/idea-refinement/verifier.md +17 -0
- package/dist/workflows/idea-refinement.js +42 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 0.3.2 — 2026-07-17
|
|
4
4
|
|
|
5
5
|
### Added
|
|
6
6
|
- Public URL snapshots for idea prompts, including an npm registry adapter, private-network rejection,
|
|
7
|
-
auditable `FETCHED` / `BLOCKED` / `FAILED` status, and a
|
|
7
|
+
auditable `FETCHED` / `BLOCKED` / `FAILED` status, and a full-council gate that stops before model calls
|
|
8
8
|
when a supplied source cannot be read.
|
|
9
9
|
- Requested-output planning: prompts that ask for a feature list or implementation plan now carry that
|
|
10
10
|
requirement through the decision contract, the existing planner call, machine JSON, Markdown, and HTML.
|
|
11
11
|
|
|
12
12
|
### Changed
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
- **Report v4 answer-first decisions** — reports now lead with the requested deliverables and chair reasoning,
|
|
14
|
+
substitute readable claim labels for internal ids, dedupe and cap claim-named conditions, frame/cap risks,
|
|
15
|
+
summarize each council seat (including a plain-language `weak_seat` warning), and distinguish FACTUAL
|
|
16
|
+
claims from JUDGMENT calls so verification priority and coverage describe checkable facts honestly.
|
|
17
|
+
Deliverable detection now combines model-backed readings with a widened fallback that hears requests for
|
|
18
|
+
standout or "ultra-level" features.
|
|
19
|
+
- `council` now includes the complete source-investigation path, 8–10-call allowance, 12-call repair budget,
|
|
20
|
+
and 45-minute deadline. `research` remains accepted as a compatibility alias with identical behavior.
|
|
21
|
+
Preflight asks zero to four questions and may not repeat facts already present in the user prompt or a
|
|
22
|
+
fetched source.
|
|
16
23
|
- Reader-facing report sections use human claim text instead of internal graph ids such as `G1`; raw ids
|
|
17
24
|
remain in machine artifacts and the Markdown technical audit.
|
|
18
25
|
|
package/README.md
CHANGED
|
@@ -50,9 +50,8 @@ stop copy-pasting between them by hand.
|
|
|
50
50
|
- **Evidence-grounded decisions.** Supply local sources with `--evidence`; Aiki records their paths and
|
|
51
51
|
hashes, checks freshness and citations, independently verifies selected load-bearing claims, and shows the
|
|
52
52
|
remaining coverage gaps before the chair.
|
|
53
|
-
- **
|
|
54
|
-
|
|
55
|
-
deterministically; `--mode` always overrides it.
|
|
53
|
+
- **Two bounded behaviors.** Use `quick` for one structured analyst or `council` for the full multi-model
|
|
54
|
+
decision council with source investigation. `research` remains accepted as an alias for `council`.
|
|
56
55
|
- **A decision dossier, not an essay.** Reports lead with the recommendation, verified evidence coverage,
|
|
57
56
|
decisive facts, first action, strongest counter-case, and critical unknowns. Financial and threshold-heavy
|
|
58
57
|
decisions can include graph-anchored numbers, payback, option commitments, and a go/no-go tripwire.
|
|
@@ -236,7 +235,7 @@ Plain text is never charged silently — you get a confirm step before any run s
|
|
|
236
235
|
aiki run idea-refinement "a fridge-photo-to-recipe app for busy parents"
|
|
237
236
|
aiki run idea-refinement "an early idea" --mode quick # one structured analyst; no council claim
|
|
238
237
|
aiki run idea-refinement ./idea.md
|
|
239
|
-
aiki run idea-refinement ./idea.md --mode
|
|
238
|
+
aiki run idea-refinement ./idea.md --mode council --evidence ./research/ # grounded, source-verifying council
|
|
240
239
|
aiki run code-review --base main # review this branch vs main
|
|
241
240
|
aiki run code-review --diff ./changes.patch # review a patch file
|
|
242
241
|
aiki run code-review --cheap # Gemini+Codex review, Claude judges only disputes (~⅓ the Opus)
|
|
@@ -251,7 +250,7 @@ reads provider credential directories.
|
|
|
251
250
|
|
|
252
251
|
Public `http(s)` links in an idea are snapshotted once before model calls and stored in
|
|
253
252
|
`00a-url-sources.json`; every preflight reader and analyst sees that same text. npm package links use the
|
|
254
|
-
registry metadata API. A snapshot records `FETCHED`, `BLOCKED`, or `FAILED` honestly. In
|
|
253
|
+
registry metadata API. A snapshot records `FETCHED`, `BLOCKED`, or `FAILED` honestly. In full council mode,
|
|
255
254
|
an unreadable supplied link stops before paid calls and asks for pasted text or a public export instead of
|
|
256
255
|
letting the council guess or grill you for facts that should have come from the link.
|
|
257
256
|
|
|
@@ -269,10 +268,9 @@ only the disputes → report.
|
|
|
269
268
|
complementary analyst lanes → deterministic claim/evidence graph audit → only decision-critical verification
|
|
270
269
|
or rebuttal → evidence-linked chair → validation planner. The report is a graph-backed **decision dossier**,
|
|
271
270
|
not an essay.
|
|
272
|
-
Choose `--mode quick` for one structured analyst
|
|
273
|
-
`--mode research`
|
|
274
|
-
|
|
275
|
-
deterministic, and an explicit flag wins:
|
|
271
|
+
Choose `--mode quick` for one structured analyst or `--mode council` for the full source-investigating decision
|
|
272
|
+
council. `--mode research` is retained as a compatibility alias and runs the same council. Without a flag, the
|
|
273
|
+
default is the full council:
|
|
276
274
|
|
|
277
275
|
- a **reader-first decision card** — recommendation, verified evidence coverage, decisive facts, first action,
|
|
278
276
|
strongest counter-case, and critical unknowns before audit detail
|
|
@@ -360,8 +358,8 @@ This is the part that makes aiki trustworthy to point at a real repo:
|
|
|
360
358
|
## Costs & limits
|
|
361
359
|
|
|
362
360
|
- **Runs cost real model calls** against your existing CLI subscriptions/quota. Idea refinement is nominally
|
|
363
|
-
**3 calls in quick
|
|
364
|
-
mode-aware budget); code review is about **5**. `aiki run` shows the mode, range, budget, and reserved
|
|
361
|
+
**3 calls in quick** or **8–10 in the full council** (`research` is the same behavior; schema repairs can add
|
|
362
|
+
calls within the mode-aware budget); code review is about **5**. `aiki run` shows the mode, range, budget, and reserved
|
|
365
363
|
chair/planner calls before asking to confirm (skip with `--yes`).
|
|
366
364
|
- **Not a general assistant.** Questions and "explore my whole codebase" requests are redirected, not answered
|
|
367
365
|
— aiki reviews a *diff* and vets a *stated idea*.
|
|
@@ -118,7 +118,7 @@ function blindId(seed) {
|
|
|
118
118
|
return createHash('sha256').update(seed).digest('hex').slice(0, 12).toUpperCase();
|
|
119
119
|
}
|
|
120
120
|
/** Remove the explicit identifiers forbidden by BENCHMARK-IDEA-V3.md §4 before human rating. §4 bars
|
|
121
|
-
* provider/model names, run ids, arm labels, AND costs — so the
|
|
121
|
+
* provider/model names, run ids, arm labels, AND costs — so the dossier's "Run details" cost
|
|
122
122
|
* block (mode, call counts, categories, per-provider calls, model time, degradation flags) and the
|
|
123
123
|
* inline `> ⚠ DEGRADED: <flag tokens>` callouts are redacted too; the DEGRADED marker and any prose
|
|
124
124
|
* note stay, since those are quality self-assessments raters legitimately read. */
|
package/dist/cli/index.js
CHANGED
|
@@ -51,7 +51,7 @@ program
|
|
|
51
51
|
.option('--head <ref>', 'code-review: head git ref to diff to (default HEAD)')
|
|
52
52
|
.option('--diff <file>', 'code-review: review a patch file instead of computing a git diff')
|
|
53
53
|
.option('--evidence <path>', 'idea-refinement: local source file/directory (stores paths + hashes, not copies)')
|
|
54
|
-
.option('--mode <mode>', 'idea-refinement: quick | council
|
|
54
|
+
.option('--mode <mode>', 'idea-refinement: quick | council (research is an alias for council)')
|
|
55
55
|
.option('--cheap', 'code-review: Gemini+Codex review, Claude judges only disputes (~⅓ the Opus; experimental)')
|
|
56
56
|
.option('--yes', 'skip the run-cost confirmation prompt')
|
|
57
57
|
.action(async (workflow, input, opts) => {
|
package/dist/cli/run.js
CHANGED
|
@@ -21,7 +21,7 @@ export function estimateRun(workflow, opts = {}) {
|
|
|
21
21
|
return {
|
|
22
22
|
calls: plan.maxCalls,
|
|
23
23
|
opus: mode === 'quick' ? 1 : 2,
|
|
24
|
-
minCalls:
|
|
24
|
+
minCalls: plan.maxCalls - plan.reservedCalls,
|
|
25
25
|
reserved: plan.reservedCalls,
|
|
26
26
|
};
|
|
27
27
|
}
|
package/dist/council/view.js
CHANGED
|
@@ -3,7 +3,7 @@ import { basename, join } from 'node:path';
|
|
|
3
3
|
import { DISPLAY_NAME } from '../providers/types.js';
|
|
4
4
|
import { RoleOutput as RoleOutputSchema } from '../schemas/index.js';
|
|
5
5
|
import { deriveAudit, deriveScorecard, mergeOpenQuestions } from '../orchestration/stages/s10-render.js';
|
|
6
|
-
import { readerClaimLabel, readerClaimRefs, renderDecisionDossierMarkdown, stripReaderClaimIds } from '../orchestration/decision-dossier.js';
|
|
6
|
+
import { buildReaderProjection, claimLookup, readerClaimLabel, readerClaimRefs, renderDecisionDossierMarkdown, stripReaderClaimIds } from '../orchestration/decision-dossier.js';
|
|
7
7
|
import { IDEA_RUBRIC } from '../workflows/idea-refinement.js';
|
|
8
8
|
import { listArtifacts, readJsonArtifact } from '../storage/runs-read.js';
|
|
9
9
|
import { adaptIdeaOutput, adaptLegacyDecisionGraph } from '../orchestration/legacy-idea-adapter.js';
|
|
@@ -377,12 +377,16 @@ function renderDossierIdeaBody(report) {
|
|
|
377
377
|
const criticalUnknowns = report.criticalUnknowns?.length ? report.criticalUnknowns : report.openQuestions.slice(0, 3);
|
|
378
378
|
const tone = dossier.recommendation.status === 'ACCEPTED' ? 'good'
|
|
379
379
|
: dossier.recommendation.status === 'REJECTED' ? 'risk' : 'caution';
|
|
380
|
-
const
|
|
381
|
-
|
|
380
|
+
const labelFor = claimLookup(report);
|
|
381
|
+
// Substitute ids then dedupe before escaping, mirroring the markdown renderer: old stored artifacts
|
|
382
|
+
// may carry duplicate / bare-G# condition strings.
|
|
383
|
+
const conditionItems = [...new Set(dossier.recommendation.conditions.map((condition) => stripReaderClaimIds(condition.text, labelFor)))];
|
|
384
|
+
const conditions = conditionItems.length
|
|
385
|
+
? `<details class="decision-details"><summary>Conditions and decision state</summary><div><p><strong>Internal state:</strong> ${escapeHtml(dossier.recommendation.status)}</p><ul>${conditionItems.map((item) => `<li>${escapeHtml(item)}</li>`).join('')}</ul></div></details>`
|
|
382
386
|
: '';
|
|
383
387
|
const startHere = dossier.experiments.actions[0]?.action ?? 'No executable next step was produced.';
|
|
384
|
-
const recommendationLead = stripReaderClaimIds(dossier.recommendation.reason);
|
|
385
|
-
const recommendationDetail = stripReaderClaimIds(dossier.recommendation.summary);
|
|
388
|
+
const recommendationLead = stripReaderClaimIds(dossier.recommendation.reason, labelFor);
|
|
389
|
+
const recommendationDetail = stripReaderClaimIds(dossier.recommendation.summary, labelFor);
|
|
386
390
|
const factLabels = ['Decisive result', 'Consequence', 'Supporting signal'];
|
|
387
391
|
const facts = keyFindings.slice(0, 3).map((finding, index) => `<article class="decision-fact"><span>${factLabels[index]}</span><p>${escapeHtml(finding)}</p></article>`).join('');
|
|
388
392
|
const snapshot = report.decisionSnapshot;
|
|
@@ -470,7 +474,10 @@ function renderDossierIdeaBody(report) {
|
|
|
470
474
|
<span>by provider ${escapeHtml(Object.entries(report.receipt.byProvider).map(([provider, count]) => `${providerName(provider)} ${count}`).join(', ') || 'none')}</span>
|
|
471
475
|
<span>model time ${(report.receipt.modelTimeMs / 1000).toFixed(1)}s</span>
|
|
472
476
|
</div>${report.flags.length ? `<div class="warns">${report.flags.map((flag) => `<span class="warn">⚑ ${escapeHtml(flag)}</span>`).join('')}</div>` : '<p class="muted">No degradation flags.</p>'}`;
|
|
473
|
-
const
|
|
477
|
+
const shownRisks = report.risks.slice(0, 8);
|
|
478
|
+
const risks = `${dossierTable(['Risk', 'Severity'], shownRisks.map((item) => [item.risk, item.severity]))}${report.risks.length > shownRisks.length
|
|
479
|
+
? `<p class="muted">${report.risks.length - shownRisks.length} lower-severity items — more in the technical audit (full list in the stored JSON).</p>`
|
|
480
|
+
: ''}`;
|
|
474
481
|
const questions = report.openQuestions.length
|
|
475
482
|
? `<ul class="checks">${report.openQuestions.map((question) => `<li>${escapeHtml(question)}</li>`).join('')}</ul>`
|
|
476
483
|
: '<p class="muted">No verdict-flipping open question was recorded.</p>';
|
|
@@ -500,7 +507,37 @@ function renderDossierIdeaBody(report) {
|
|
|
500
507
|
section('08', 'What the council added', `${shared}${unique}<h3>Verified unique contributions</h3>${contributions}`, 340),
|
|
501
508
|
section('09', 'Run details', runDetails, 380),
|
|
502
509
|
].join('');
|
|
503
|
-
return `${stripReaderClaimIds(readerBody)}${section('10', 'Technical audit', technical, 420)}`;
|
|
510
|
+
return `${stripReaderClaimIds(readerBody, labelFor)}${section('10', 'Technical audit', technical, 420)}`;
|
|
511
|
+
}
|
|
512
|
+
function renderReaderBriefIdeaBody(report) {
|
|
513
|
+
const dossier = report.dossier;
|
|
514
|
+
const projection = buildReaderProjection(report);
|
|
515
|
+
const tone = dossier.recommendation.status === 'ACCEPTED' ? 'good'
|
|
516
|
+
: dossier.recommendation.status === 'REJECTED' ? 'risk' : 'caution';
|
|
517
|
+
const hero = `<section class="verdict tone-${tone} reveal" style="animation-delay:60ms">
|
|
518
|
+
<span class="pill">Recommendation</span>
|
|
519
|
+
<p class="verdict-text">${escapeHtml(projection.headline)}</p>
|
|
520
|
+
<p class="verdict-detail">${escapeHtml(projection.bottomLine)}</p>
|
|
521
|
+
</section>`;
|
|
522
|
+
const warnings = projection.warnings.length || projection.notices.length
|
|
523
|
+
? `<div class="warns">${projection.warnings.map((warning) => `<span class="warn">⚑ ${escapeHtml(warning.message)}</span>`).join('')}${projection.notices.map((notice) => `<span class="warn">ⓘ ${escapeHtml(notice.message)}</span>`).join('')}</div>`
|
|
524
|
+
: '';
|
|
525
|
+
const snapshot = projection.snapshot ? section('', 'Decision numbers', `${dossierTable(['Metric', 'Value', 'What it means'], projection.snapshot.decisiveNumbers.map((item) => [item.label, item.value, item.meaning]))}${projection.snapshot.payback ? `<div class="action-callout"><span>Payback · ${escapeHtml(projection.snapshot.payback.status.replaceAll('_', ' '))}</span><p>${escapeHtml(projection.snapshot.payback.result)} — ${escapeHtml(projection.snapshot.payback.basis)}</p></div>` : ''}<h3>Options at a glance</h3>${dossierTable(['Path', 'Commitment', 'Basis', 'Trade-off'], projection.snapshot.options.map((item) => [item.label, item.commitment, item.commitmentKind.replace('_', ' '), item.tradeoff]))}${projection.snapshot.tripwire ? `<div class="action-callout"><span>Go/no-go tripwire</span><p><strong>${escapeHtml(projection.snapshot.tripwire.metric)}: ${escapeHtml(projection.snapshot.tripwire.threshold)}</strong> — ${escapeHtml(projection.snapshot.tripwire.decisionRule)}</p></div>` : ''}`, 80) : '';
|
|
526
|
+
const editorial = projection.sections.map((item, index) => section(String(index + 1).padStart(2, '0'), item.heading, `<p class="lede">${escapeHtml(item.summary)}</p>${item.bullets.length
|
|
527
|
+
? `<ul class="reasons">${item.bullets.map((bullet) => `<li>${escapeHtml(bullet)}</li>`).join('')}</ul>`
|
|
528
|
+
: ''}`, 100 + index * 40)).join('');
|
|
529
|
+
const backlog = projection.featureBacklog;
|
|
530
|
+
const features = backlog ? section('', 'Feature priorities', `<div class="feature-groups">${[
|
|
531
|
+
['MUST', 'Build for the first useful release', backlog.must],
|
|
532
|
+
['SHOULD', 'Add after the golden path is stable', backlog.should],
|
|
533
|
+
['LATER', 'Keep outside the current build', backlog.later],
|
|
534
|
+
].filter(([, , items]) => items.length).map(([priority, description, items]) => `<section class="feature-group priority-${priority.toLowerCase()}"><header><div><span>${priority}</span><h4>${description}</h4></div><strong>${items.length}</strong></header><ul>${items.map((item) => `<li><div class="feature-title"><strong>${escapeHtml(item.feature)}</strong><span>${item.effort}</span></div><p>${escapeHtml(item.user_value)}</p><small>${escapeHtml(item.rationale)}</small></li>`).join('')}</ul></section>`).join('')}</div>${backlog.wont.length ? `<h3>Not in this scope</h3><ul class="checks">${backlog.wont.map((item) => `<li><strong>${escapeHtml(item.feature)}</strong> — ${escapeHtml(item.reason)}</li>`).join('')}</ul>` : ''}`, 340) : '';
|
|
535
|
+
const buildPlan = projection.implementationPlan ? section('', 'Build plan', `<ol class="milestone-list">${projection.implementationPlan.milestones.map((milestone) => `<li><div class="milestone-marker"><span>${String(milestone.order).padStart(2, '0')}</span><small>${escapeHtml(milestone.timebox)}</small></div><article><h4>${escapeHtml(milestone.outcome)}</h4><ul>${milestone.tasks.map((task) => `<li>${escapeHtml(task)}</li>`).join('')}</ul><div class="acceptance"><span>Done when</span><p>${escapeHtml(milestone.acceptance_test)}</p></div></article></li>`).join('')}</ol>`, 380) : '';
|
|
536
|
+
const caveats = projection.caveats.length ? section('', 'Top caveats', `<ul class="checks">${projection.caveats.map((item) => `<li>${escapeHtml(item)}</li>`).join('')}</ul>`, 420) : '';
|
|
537
|
+
const sources = projection.sources.length ? section('', 'Sources', `<ul class="agree">${projection.sources.map((source) => `<li><p>${source.url ? `<a href="${escapeHtml(source.url)}" rel="noopener noreferrer">${escapeHtml(source.label)}</a>` : escapeHtml(source.label)}</p>${source.citedFor.length ? `<small>Cited for: ${source.citedFor.map(escapeHtml).join('; ')}</small>` : ''}</li>`).join('')}</ul>`, 460) : '';
|
|
538
|
+
const nextStep = section('', 'Next step', `<div class="action-callout"><span>Do this now</span><p>${escapeHtml(projection.nextStep)}</p></div>`, 500);
|
|
539
|
+
const audit = `<details class="fold council-audit"><summary>Council audit — reasoning, evidence, dissent, and run receipt</summary><div class="fold-body">${renderDossierIdeaBody(report)}</div></details>`;
|
|
540
|
+
return `${hero}${warnings}${snapshot}${editorial}${features}${buildPlan}${caveats}${sources}${nextStep}${audit}`;
|
|
504
541
|
}
|
|
505
542
|
function renderLegacyIdeaBody(view) {
|
|
506
543
|
const risks = view.risks ?? [];
|
|
@@ -891,19 +928,22 @@ function renderTechnical(view) {
|
|
|
891
928
|
export function renderCouncilHtml(view) {
|
|
892
929
|
const isIdea = view.workflow !== 'code-review';
|
|
893
930
|
const quick = isIdea && view.mode === 'quick';
|
|
931
|
+
const hasReaderBrief = Boolean(view.decisionReport?.dossier.readerBrief);
|
|
894
932
|
const kicker = quick ? 'aiki · quick analysis' : isIdea ? 'aiki · idea refinement' : 'aiki · code review';
|
|
895
933
|
const title = isIdea && view.topic ? cleanTopic(view.topic) : (isIdea ? 'Idea refinement' : 'Code review');
|
|
896
934
|
const panel = view.columns.map((c) => c.title);
|
|
897
|
-
const metaBits = [
|
|
935
|
+
const metaBits = hasReaderBrief ? [] : [
|
|
898
936
|
panel.length ? `${quick ? 'Analyst' : 'Panel'}: ${panel.join(' · ')}` : '',
|
|
899
937
|
!quick && view.moderator ? `Chair: ${view.moderator}` : '',
|
|
900
938
|
view.calls,
|
|
901
939
|
].filter(Boolean);
|
|
902
|
-
const flags = view.flags.length
|
|
940
|
+
const flags = !hasReaderBrief && view.flags.length
|
|
903
941
|
? `<div class="warns">${view.flags.map((f) => `<span class="warn">⚑ ${escapeHtml(f.replaceAll('_', ' '))}</span>`).join('')}</div>`
|
|
904
942
|
: '';
|
|
905
943
|
const body = isIdea && view.decisionReport?.dossier
|
|
906
|
-
?
|
|
944
|
+
? view.decisionReport.dossier.readerBrief
|
|
945
|
+
? renderReaderBriefIdeaBody(view.decisionReport)
|
|
946
|
+
: renderDossierIdeaBody(view.decisionReport)
|
|
907
947
|
: quick ? renderQuickIdeaBody(view) : isIdea ? renderIdeaBody(view) : renderReviewBody(view);
|
|
908
948
|
// Embed the report as Markdown for the Copy button. Escape "<" so a "</script>" in content can't break out.
|
|
909
949
|
const md = JSON.stringify(councilMarkdown(view)).replace(/</g, '\\u003c');
|
|
@@ -928,14 +968,14 @@ html{-webkit-text-size-adjust:100%;}
|
|
|
928
968
|
body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--sans);font-size:16px;line-height:1.6;}
|
|
929
969
|
main{max-width:940px;margin:0 auto;padding:34px 24px 90px;}
|
|
930
970
|
a{color:var(--accent);}
|
|
931
|
-
h1{font-family:var(--
|
|
971
|
+
h1{font-family:var(--sans);font-weight:650;letter-spacing:-.01em;}
|
|
932
972
|
h2,h3,h4{font-family:var(--sans);font-weight:650;letter-spacing:-.01em;}
|
|
933
973
|
p{margin:0 0 .6em;}
|
|
934
974
|
|
|
935
975
|
/* masthead */
|
|
936
976
|
.mast{border-bottom:1px solid var(--ink);padding-bottom:22px;margin-bottom:30px;}
|
|
937
977
|
.kicker{font-family:var(--mono);font-size:11.5px;letter-spacing:.22em;text-transform:uppercase;color:var(--accent);}
|
|
938
|
-
.mast h1{font-size:clamp(
|
|
978
|
+
.mast h1{font-size:clamp(28px,4.6vw,42px);line-height:1.12;margin:12px 0 16px;}
|
|
939
979
|
.mmeta{display:flex;flex-wrap:wrap;gap:7px;}
|
|
940
980
|
.mmeta span{font-family:var(--mono);font-size:11.5px;color:var(--soft);border:1px solid var(--line);background:var(--panel);border-radius:100px;padding:3px 10px;}
|
|
941
981
|
.warns{margin-top:12px;display:flex;flex-wrap:wrap;gap:8px;}
|
|
@@ -15,7 +15,7 @@ import { extractJson } from '../providers/adapter-core.js';
|
|
|
15
15
|
import { detect } from '../providers/detect.js';
|
|
16
16
|
import { probeFlags } from '../providers/probe.js';
|
|
17
17
|
import { replayKey } from '../storage/replay.js';
|
|
18
|
-
import { callCategory, defaultBudgetFor, IDEA_MODE_PLANS, isOptionalStage, LEGACY_DEFAULT_BUDGET } from './modes.js';
|
|
18
|
+
import { callCategory, defaultBudgetFor, defaultDeadlineFor, IDEA_MODE_PLANS, isOptionalStage, LEGACY_DEFAULT_BUDGET } from './modes.js';
|
|
19
19
|
/** Bracket a stage call with the TUI's start/end events (no-op headless). A thrown StageError marks
|
|
20
20
|
* the row `failed` and re-propagates unchanged — the engine's failure handling is untouched. */
|
|
21
21
|
export async function runStage(ctx, id, fn) {
|
|
@@ -100,7 +100,7 @@ export class RunCtx {
|
|
|
100
100
|
this.budget = { limit: opts.budget ?? defaultBudgetFor(opts.workflow, this.mode), used: 0 };
|
|
101
101
|
this.handles = new Map(opts.handles.map((h) => [h.id, h]));
|
|
102
102
|
this.signal = opts.signal;
|
|
103
|
-
this.deadlineMs = opts.deadlineMs ??
|
|
103
|
+
this.deadlineMs = opts.deadlineMs ?? defaultDeadlineFor(opts.workflow, this.mode);
|
|
104
104
|
this.now = opts.now ?? Date.now;
|
|
105
105
|
this.deadlineAt = this.now() + this.deadlineMs;
|
|
106
106
|
this.replay = opts.replay;
|
|
@@ -174,7 +174,7 @@ export class RunCtx {
|
|
|
174
174
|
timeoutMs: req.timeoutMs ?? DEFAULT_CALL_TIMEOUT_MS,
|
|
175
175
|
expectJson: req.expectJson,
|
|
176
176
|
readOnly: true,
|
|
177
|
-
research: this.
|
|
177
|
+
research: this.workflow === 'idea-refinement' && this.mode !== 'quick' && stage.startsWith('S4'),
|
|
178
178
|
signal: this.signal, // Ctrl+C kills the in-flight child (T8); undefined headless
|
|
179
179
|
}, handle.flags);
|
|
180
180
|
// Only REAL calls count toward the ledger/budget; a replayed call is free and already recorded in
|