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
@@ -186,6 +186,7 @@ export const PreflightReading = z.object({
186
186
  missing_evidence: z.array(z.string().min(1)).max(8),
187
187
  domain_dimensions: z.array(DomainDimension).min(3).max(5),
188
188
  questions: z.array(RunBriefQuestion).max(4),
189
+ requested_outputs: z.array(RequestedOutputSchema).max(4).default([]),
189
190
  }).strict().superRefine((reading, ctx) => {
190
191
  checkQuestionIds(reading.questions, ctx);
191
192
  checkDomainDimensionIds(reading.domain_dimensions, ctx);
@@ -236,6 +237,7 @@ export const ClaimPosition = z
236
237
  dimension_id: z.string().min(1),
237
238
  stance: z.enum(['SUPPORT', 'OPPOSE', 'MIXED', 'UNKNOWN']),
238
239
  basis: z.enum(['EVIDENCE', 'INFERENCE', 'ASSUMPTION']),
240
+ nature: z.enum(['FACTUAL', 'JUDGMENT']).default('JUDGMENT'),
239
241
  load_bearing: z.boolean(),
240
242
  if_false: z.enum(['STOP', 'PIVOT', 'CONDITION', 'MINOR']),
241
243
  reasoning: z.string().min(1),
@@ -316,6 +318,14 @@ export const DecisionQuestion = z
316
318
  claim_ids: z.array(z.string().min(1)),
317
319
  })
318
320
  .strict();
321
+ export const DeliverableProposal = z.object({
322
+ output: z.enum(['FEATURE_BACKLOG', 'IMPLEMENTATION_PLAN']),
323
+ title: z.string().min(1),
324
+ detail: z.string().min(1),
325
+ user_value: z.string().min(1),
326
+ why_distinctive: z.string().min(1),
327
+ evidence_ids: z.array(z.string().min(1)).max(6),
328
+ }).strict();
319
329
  const IdeaRoleOutputBase = z
320
330
  .object({
321
331
  workflow: z.literal('idea-refinement'),
@@ -326,6 +336,7 @@ const IdeaRoleOutputBase = z
326
336
  calculations: z.array(CalculationLedger).max(8).default([]),
327
337
  coverage: z.array(CoverageEntry).max(18), // 13 core + up to 5 preflight domain dimensions
328
338
  decision_questions: z.array(DecisionQuestion).max(8),
339
+ deliverable_proposals: z.array(DeliverableProposal).max(8).default([]),
329
340
  })
330
341
  .strict();
331
342
  function checkSubmissionRefs(submission, ctx) {
@@ -395,6 +406,12 @@ function checkSubmissionRefs(submission, ctx) {
395
406
  ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['decision_questions', index, 'claim_ids'], message: `unknown position id: ${id}` });
396
407
  }
397
408
  }
409
+ for (const [index, proposal] of submission.deliverable_proposals.entries()) {
410
+ for (const id of proposal.evidence_ids) {
411
+ if (!evidenceIds.has(id))
412
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['deliverable_proposals', index, 'evidence_ids'], message: `unknown evidence id: ${id}` });
413
+ }
414
+ }
398
415
  }
399
416
  export const IdeaRoleOutput = IdeaRoleOutputBase.superRefine(checkSubmissionRefs);
400
417
  /** Defect categories a finding (and a seeded bug, T11) can carry. BENCHMARK.md's "defect class" match
@@ -527,6 +544,17 @@ export function salvageIdeaRoleOutputModel(input) {
527
544
  && calc.inputs.every((input) => input.evidence_ids.every((id) => keptEvidence.has(id))))
528
545
  .slice(0, 8)
529
546
  : output.calculations;
547
+ const deliverableProposals = parseOrDrop(output.deliverable_proposals, (item) => {
548
+ if (!item || typeof item !== 'object' || Array.isArray(item))
549
+ return DeliverableProposal.safeParse(item);
550
+ const proposal = item;
551
+ return DeliverableProposal.strip().safeParse({
552
+ ...proposal,
553
+ evidence_ids: Array.isArray(proposal.evidence_ids)
554
+ ? proposal.evidence_ids.filter((id) => keptEvidence.has(id))
555
+ : proposal.evidence_ids,
556
+ });
557
+ });
530
558
  return {
531
559
  ...output,
532
560
  evidence,
@@ -534,6 +562,7 @@ export function salvageIdeaRoleOutputModel(input) {
534
562
  calculations,
535
563
  coverage: parseOrDrop(scrubIds(output.coverage, 'position_ids'), (item) => CoverageEntryBase.strip().superRefine(checkCoverageEntry).safeParse(item)),
536
564
  decision_questions: parseOrDrop(scrubIds(output.decision_questions, 'claim_ids'), (item) => DecisionQuestion.strip().safeParse(item)),
565
+ deliverable_proposals: deliverableProposals,
537
566
  };
538
567
  }
539
568
  /** The model-facing S4 shape. Exact known enum aliases are canonicalized, then the strict schema validates
@@ -588,6 +617,7 @@ export const DecisionClaim = z.object({
588
617
  position_ids: z.array(z.string().min(1)).min(1),
589
618
  state: z.enum(['CONSENSUS', 'SHARED_CONCERN', 'DISAGREEMENT', 'UNIQUE', 'UNCERTAIN']),
590
619
  evidence_state: z.enum(['SUPPORTED', 'CONFLICTED', 'UNVERIFIED']),
620
+ nature: z.enum(['FACTUAL', 'JUDGMENT']).default('JUDGMENT'),
591
621
  load_bearing: z.boolean(),
592
622
  if_false: z.enum(['STOP', 'PIVOT', 'CONDITION', 'MINOR']),
593
623
  sensitivity: z.enum(['DECISIVE', 'MATERIAL', 'LOW']),
@@ -635,8 +665,27 @@ export const ClaimVerification = z.object({
635
665
  calculation_check: z.enum(['PASS', 'FAIL', 'NOT_APPLICABLE']).optional(),
636
666
  missing_evidence: z.array(z.string().min(1)),
637
667
  }).strict();
668
+ /** v6 semantic claim join: S8 may group claims that assert the same proposition in different
669
+ * words (SAME) or directly contradict each other (OPPOSES). `.catch(undefined)` keeps a
670
+ * malformed grouping from ever costing the verification set — groups are a bonus, never a risk. */
671
+ export const ClaimGroup = z.object({
672
+ ids: z.array(z.string().min(1)).min(2).max(8),
673
+ relation: z.enum(['SAME', 'OPPOSES']),
674
+ }).strict();
638
675
  export const ClaimVerificationSet = z.object({
639
676
  verifications: z.array(ClaimVerification),
677
+ claim_groups: z.array(ClaimGroup).max(12).optional().catch(undefined),
678
+ }).strict();
679
+ // ── v7 Phase D: targeted auto-mode challenge delta ─────────────────────────
680
+ export const ChallengeDelta = z.object({
681
+ claimId: z.string().min(1),
682
+ response: z.enum(['CONFIRM', 'COUNTER', 'NARROW', 'REPLACE', 'UNRESOLVED']),
683
+ reasoning: z.string().min(1),
684
+ newEvidenceIds: z.array(z.string().min(1)),
685
+ changedDecisionImpact: z.string().min(1),
686
+ }).strict();
687
+ export const ChallengeDeltaSet = z.object({
688
+ deltas: z.array(ChallengeDelta).max(3),
640
689
  }).strict();
641
690
  // ── R5: bounded, append-only rebuttal events ───────────────────────────────
642
691
  const RebuttalResponseBase = z.object({
@@ -899,7 +948,32 @@ export const ImplementationPlan = z.object({
899
948
  acceptance_test: z.string().min(1),
900
949
  }).strict()).min(1).max(7),
901
950
  }).strict();
902
- export const ActionPlan = z
951
+ const ReaderBriefBase = z.object({
952
+ headline: z.string().min(1).max(160),
953
+ bottom_line: z.string().min(1).max(1200),
954
+ sections: z.array(z.object({
955
+ heading: z.string().min(1).max(120),
956
+ summary: z.string().min(1).max(1000),
957
+ bullets: z.array(z.string().min(1).max(500)).max(6),
958
+ }).strict()).min(2).max(6),
959
+ next_step: z.string().min(1).max(600),
960
+ caveats: z.array(z.string().min(1).max(500)).max(3),
961
+ source_ids: z.array(z.string().min(1)).max(8),
962
+ }).strict();
963
+ const READER_AUDIT_ENUM = /\b(?:UNVERIFIED|UNVERIFIABLE|PARTIAL|CONFLICTED)\b/;
964
+ const READER_AUDIT_LANGUAGE = /\b(?:structural score|evidence coverage|verification coverage|claim ids?|graph ids?|provider calls?|model calls?|answer editor|reader_brief)\b/i;
965
+ export const ReaderBrief = ReaderBriefBase.superRefine((brief, ctx) => {
966
+ const text = JSON.stringify(brief);
967
+ if (READER_AUDIT_ENUM.test(text) || READER_AUDIT_LANGUAGE.test(text)) {
968
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'reader_brief contains internal audit language' });
969
+ }
970
+ });
971
+ /** Contextual reader-language check: only reject IDs that actually exist in this run. */
972
+ export function readerBriefIssues(brief, knownIds) {
973
+ const text = JSON.stringify(brief);
974
+ return [...knownIds].filter((id) => new RegExp(`\\b${id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(text));
975
+ }
976
+ const ActionPlanBase = z
903
977
  .object({
904
978
  actions: z
905
979
  .array(z
@@ -912,13 +986,19 @@ export const ActionPlan = z
912
986
  kill_signal: z.string().min(1),
913
987
  })
914
988
  .strict())
915
- .min(1)
916
989
  .max(7),
917
990
  sequencing_note: z.string().min(1),
918
991
  feature_backlog: FeatureBacklog.optional(),
919
992
  implementation_plan: ImplementationPlan.optional(),
993
+ // Optional only so pre-v5 run artifacts remain replayable. New decision contracts require it in S9b.
994
+ reader_brief: ReaderBrief.optional(),
920
995
  })
921
996
  .strict();
997
+ export const ActionPlan = ActionPlanBase.superRefine((plan, ctx) => {
998
+ if (plan.actions.length === 0 && !plan.reader_brief) {
999
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['actions'], message: 'an empty action plan requires reader_brief' });
1000
+ }
1001
+ });
922
1002
  export const PlannerUnavailable = z.object({
923
1003
  kind: z.literal('PlannerUnavailable'),
924
1004
  reason: z.enum(['budget_exhausted', 'planner_failed']),
@@ -934,7 +1014,7 @@ export const QuickDecisionModel = z.object({
934
1014
  key_points: z.array(z.string().min(1)).min(2).max(8),
935
1015
  dissent: z.array(z.string().min(1)).min(1).max(4),
936
1016
  confidence_notes: z.string().min(1),
937
- action_plan: ActionPlan,
1017
+ action_plan: ActionPlanBase.extend({ reader_brief: ReaderBrief }),
938
1018
  }).strict().superRefine((decision, ctx) => {
939
1019
  const hasConditions = decision.conditions.length > 0;
940
1020
  if (decision.recommendation === 'PROCEED_WITH_CONDITIONS' && !hasConditions) {
@@ -947,6 +1027,16 @@ export const QuickDecisionModel = z.object({
947
1027
  // ── RunMeta (§15, §16) ──────────────────────────────────────────────────────
948
1028
  //
949
1029
  // Written by the artifact writer; assembled by the engine's RunCtx (T5). Internal → not strict.
1030
+ /** Per-call token accounting. `estimated:true` = local chars/4 estimate, never blended
1031
+ * silently with provider-reported numbers. */
1032
+ export const NormalizedUsageSchema = z.object({
1033
+ inputTokens: z.number().int().nonnegative().optional(),
1034
+ outputTokens: z.number().int().nonnegative().optional(),
1035
+ cacheReadTokens: z.number().int().nonnegative().optional(),
1036
+ cacheWriteTokens: z.number().int().nonnegative().optional(),
1037
+ estimated: z.boolean(),
1038
+ reportedCostUsd: z.number().nonnegative().optional(),
1039
+ });
950
1040
  /** One provider call's accounting entry (§15 "per-call timings"). */
951
1041
  export const CallRecord = z.object({
952
1042
  provider: ProviderIdSchema,
@@ -954,6 +1044,7 @@ export const CallRecord = z.object({
954
1044
  category: z.enum(['discovery', 'verification', 'repair', 'planning']).optional(),
955
1045
  durationMs: z.number().nonnegative(),
956
1046
  error: z.enum(['NOT_FOUND', 'AUTH', 'QUOTA', 'TIMEOUT', 'BAD_OUTPUT', 'CRASH']).optional(),
1047
+ usage: NormalizedUsageSchema.optional(),
957
1048
  });
958
1049
  /** How read-only was actually enforced per provider (§15, §19). Mirrors providers ReadOnlyFlag. */
959
1050
  const ReadOnlyFlagSchema = z.enum(['plan', 'sandbox', 'none']);
@@ -981,17 +1072,35 @@ export const RunMeta = z.object({
981
1072
  repair: z.number().int().nonnegative(),
982
1073
  planning: z.number().int().nonnegative(),
983
1074
  }).optional(),
1075
+ usage_totals: z.object({
1076
+ inputTokens: z.number().int().nonnegative(),
1077
+ outputTokens: z.number().int().nonnegative(),
1078
+ reportedCalls: z.number().int().nonnegative(),
1079
+ estimatedCalls: z.number().int().nonnegative(),
1080
+ reportedCostUsd: z.number().nonnegative().optional(),
1081
+ }).optional(),
1082
+ // v7 Phase B: present only when the user ran `--mode auto`; records the resolved mode + why.
1083
+ auto_decision: z.object({
1084
+ resolved: z.enum(['quick', 'council']),
1085
+ reasons: z.array(z.string()),
1086
+ fast_path: z.boolean().optional(),
1087
+ escalation_reasons: z.array(z.string().min(1)).optional(),
1088
+ }).optional(),
984
1089
  exit_status: z.enum(['ok', 'failed', 'aborted', 'partial']),
985
1090
  aborted: z.boolean(), // §16: Ctrl+C finalizes meta with aborted:true
986
1091
  // §16 report-header flags; absent = none.
987
1092
  flags: z.array(z.enum([
988
1093
  'synthesis_suspect',
989
1094
  'low_diversity',
1095
+ 'weak_seat',
990
1096
  'plan_skipped',
991
1097
  'plan_fallback',
1098
+ 'plan_partial',
992
1099
  'headless_intent',
993
1100
  'verification_skipped',
994
1101
  'research_ungrounded',
1102
+ 'source_fallback_search',
1103
+ 'deliverable_gap',
995
1104
  'single_model',
996
1105
  ])).optional(),
997
1106
  });