@balpal4495/quorum 3.0.2 → 3.0.4

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.
@@ -269,19 +269,20 @@ function summarizeBehaviorMap(map) {
269
269
  // ── Score computation ─────────────────────────────────────────────────────────
270
270
 
271
271
  function computeScore(dims) {
272
+ const d = dims ?? {}
272
273
  const raw =
273
- dims.strategic_fit * 20 +
274
- dims.user_problem_clarity * 15 +
275
- dims.evidence_strength * 20 +
276
- dims.leverage * 10 +
277
- dims.feasibility * 15 +
278
- dims.time_to_signal * 10 +
279
- dims.reversibility * 10 -
280
- dims.complexity_penalty * 10 -
281
- dims.dependency_penalty * 8 -
282
- dims.contradiction_penalty * 15 -
283
- dims.evidence_gap_penalty * 12
284
- return { ...dims, total: Math.max(0, Math.min(100, Math.round(raw))) }
274
+ (d.strategic_fit ?? 0) * 20 +
275
+ (d.user_problem_clarity ?? 0) * 15 +
276
+ (d.evidence_strength ?? 0) * 20 +
277
+ (d.leverage ?? 0) * 10 +
278
+ (d.feasibility ?? 0) * 15 +
279
+ (d.time_to_signal ?? 0) * 10 +
280
+ (d.reversibility ?? 0) * 10 -
281
+ (d.complexity_penalty ?? 0) * 10 -
282
+ (d.dependency_penalty ?? 0) * 8 -
283
+ (d.contradiction_penalty ?? 0) * 15 -
284
+ (d.evidence_gap_penalty ?? 0) * 12
285
+ return { ...d, total: Math.max(0, Math.min(100, Math.round(raw))) }
285
286
  }
286
287
 
287
288
  // ── Prompts ───────────────────────────────────────────────────────────────────
@@ -349,7 +350,7 @@ ${chronicleCtx}
349
350
  ## Current product behaviour
350
351
  ${behaviorCtx}
351
352
 
352
- Return ONLY valid JSON: { "pathways": [ { "id":"<slug>","kind":"product_pathway","title":"<title>","goal":"<goal>","target_user":"<who>","problem":"<problem>","current_behaviors":["<behaviour>"],"opportunity":"<gap>","why_now":"<why>","smallest_useful_version":"<mvp>","phases":[{"name":"<phase>","outcome":"<outcome>","user_value":"<value>","build_notes":["<note>"],"dependencies":["<dep>"],"risks":["<risk>"]}],"dependencies":["<dep>"],"risks":["<risk>"],"assumptions":["<assumption>"],"open_questions":["<question>"],"evidence":[{"id":"<id>","kind":"<kind>","source":"<source>","summary":"<summary>","confidence":<0-1>}],"scores":{"strategic_fit":<0-1>,"user_problem_clarity":<0-1>,"evidence_strength":<0-1>,"leverage":<0-1>,"feasibility":<0-1>,"time_to_signal":<0-1>,"reversibility":<0-1>,"complexity_penalty":<0-1>,"dependency_penalty":<0-1>,"contradiction_penalty":<0-1>,"evidence_gap_penalty":<0-1>,"total":<0-100>},"confidence":<0-1>,"time_to_signal":"<timeframe>","reversibility":"high|medium|low","suggested_next_step":"<step>" } ] }
353
+ Return ONLY valid JSON (no markdown fences, no explanation): { "pathways": [ { "id":"<slug>","kind":"product_pathway","title":"<title>","goal":"<goal>","target_user":"<who>","problem":"<problem>","current_behaviors":["<behaviour>"],"opportunity":"<gap>","why_now":"<why>","smallest_useful_version":"<mvp>","phases":[{"name":"<phase>","outcome":"<outcome>","user_value":"<value>","build_notes":["<note>"],"dependencies":["<dep>"],"risks":["<risk>"]}],"dependencies":["<dep>"],"risks":["<risk>"],"assumptions":["<assumption>"],"open_questions":["<question>"],"evidence":[{"id":"<id>","kind":"<kind>","source":"<source>","summary":"<summary>","confidence":<0-1>}],"scores":{"strategic_fit":<0-1>,"user_problem_clarity":<0-1>,"evidence_strength":<0-1>,"leverage":<0-1>,"feasibility":<0-1>,"time_to_signal":<0-1>,"reversibility":<0-1>,"complexity_penalty":<0-1>,"dependency_penalty":<0-1>,"contradiction_penalty":<0-1>,"evidence_gap_penalty":<0-1>,"total":<0-100>},"confidence":<0-1>,"time_to_signal":"<timeframe>","reversibility":"high|medium|low","suggested_next_step":"<step>" } ] }
353
354
 
354
355
  Sort by scores.total descending. Assumptions must always be present.`
355
356
  }
@@ -367,7 +368,7 @@ ${chronicleCtx}
367
368
  ## Current product behaviour
368
369
  ${behaviorCtx}
369
370
 
370
- Return ONLY valid JSON: { "bets": [ { "id":"<slug>","kind":"product_bet","title":"<title>","thesis":"<falsifiable hypothesis>","why_now":"<why>","target_user":"<who>","upside":"<best case>","downside":"<downside>","assumptions":["<assumption>"],"validation_signals":["<signal>"],"invalidation_signals":["<signal>"],"kill_criteria":["<criteria>"],"first_experiment":"<smallest test>","build_path":["<phase>"],"evidence":[{"id":"<id>","kind":"<kind>","source":"<source>","summary":"<summary>","confidence":<0-1>}],"scores":{"strategic_fit":<0-1>,"user_problem_clarity":<0-1>,"evidence_strength":<0-1>,"leverage":<0-1>,"feasibility":<0-1>,"time_to_signal":<0-1>,"reversibility":<0-1>,"complexity_penalty":<0-1>,"dependency_penalty":<0-1>,"contradiction_penalty":<0-1>,"evidence_gap_penalty":<0-1>,"total":<0-100>},"confidence":<0-1>,"time_to_signal":"<timeframe>","reversibility":"high|medium|low","appetite":"small|medium|large" } ] }
371
+ Return ONLY valid JSON (no markdown fences, no explanation): { "bets": [ { "id":"<slug>","kind":"product_bet","title":"<title>","thesis":"<falsifiable hypothesis>","why_now":"<why>","target_user":"<who>","upside":"<best case>","downside":"<downside>","assumptions":["<assumption>"],"validation_signals":["<signal>"],"invalidation_signals":["<signal>"],"kill_criteria":["<criteria>"],"first_experiment":"<smallest test>","build_path":["<phase>"],"evidence":[{"id":"<id>","kind":"<kind>","source":"<source>","summary":"<summary>","confidence":<0-1>}],"scores":{"strategic_fit":<0-1>,"user_problem_clarity":<0-1>,"evidence_strength":<0-1>,"leverage":<0-1>,"feasibility":<0-1>,"time_to_signal":<0-1>,"reversibility":<0-1>,"complexity_penalty":<0-1>,"dependency_penalty":<0-1>,"contradiction_penalty":<0-1>,"evidence_gap_penalty":<0-1>,"total":<0-100>},"confidence":<0-1>,"time_to_signal":"<timeframe>","reversibility":"high|medium|low","appetite":"small|medium|large" } ] }
371
372
 
372
373
  Kill criteria and invalidation_signals must be present. If no user evidence, evidence_strength ≤ 0.4.`
373
374
  }
@@ -383,7 +384,7 @@ ${chronicleCtx}
383
384
  ## Current product behaviour
384
385
  ${behaviorCtx}
385
386
 
386
- Return ONLY valid JSON: { "idea":"${idea}","summary":"<one sentence>","recommendation":"pursue|pursue-small-test|investigate-more|defer|avoid","scores":{"strategic_fit":<0-1>,"user_problem_clarity":<0-1>,"evidence_strength":<0-1>,"leverage":<0-1>,"feasibility":<0-1>,"time_to_signal":<0-1>,"reversibility":<0-1>,"complexity_penalty":<0-1>,"dependency_penalty":<0-1>,"contradiction_penalty":<0-1>,"evidence_gap_penalty":<0-1>,"total":<0-100>},"evidence":[{"id":"<id>","kind":"<kind>","source":"<source>","summary":"<summary>","confidence":<0-1>}],"supporting_reasons":["<reason>"],"risks":["<risk>"],"assumptions":["<assumption>"],"open_questions":["<question>"],"suggested_next_step":"<action>" }
387
+ Return ONLY valid JSON (no markdown fences, no explanation): { "idea":"${idea}","summary":"<one sentence>","recommendation":"pursue|pursue-small-test|investigate-more|defer|avoid","scores":{"strategic_fit":<0-1>,"user_problem_clarity":<0-1>,"evidence_strength":<0-1>,"leverage":<0-1>,"feasibility":<0-1>,"time_to_signal":<0-1>,"reversibility":<0-1>,"complexity_penalty":<0-1>,"dependency_penalty":<0-1>,"contradiction_penalty":<0-1>,"evidence_gap_penalty":<0-1>,"total":<0-100>},"evidence":[{"id":"<id>","kind":"<kind>","source":"<source>","summary":"<summary>","confidence":<0-1>}],"supporting_reasons":["<reason>"],"risks":["<risk>"],"assumptions":["<assumption>"],"open_questions":["<question>"],"suggested_next_step":"<action>" }
387
388
 
388
389
  Score total = strategic_fit*20 + user_problem_clarity*15 + evidence_strength*20 + leverage*10 + feasibility*15 + time_to_signal*10 + reversibility*10 - complexity_penalty*10 - dependency_penalty*8 - contradiction_penalty*15 - evidence_gap_penalty*12. Clamp 0–100.`
389
390
  }
@@ -672,9 +673,21 @@ function renderProductBrief(brief) {
672
673
  }
673
674
  }
674
675
 
675
- // ── Last-run artifact cache (used by --from-last) ─────────────────────────────
676
+ // ── Last-run artifact cache (persisted to disk so propose --from-last works across invocations)
676
677
 
677
- let _lastArtifact = null
678
+ async function saveLastArtifact(chronicleDir, artifact) {
679
+ try {
680
+ await fs.mkdir(chronicleDir, { recursive: true })
681
+ await fs.writeFile(path.join(chronicleDir, "compass-last.json"), JSON.stringify(artifact, null, 2), "utf8")
682
+ } catch { /* best-effort */ }
683
+ }
684
+
685
+ async function loadLastArtifact(chronicleDir) {
686
+ try {
687
+ const raw = await fs.readFile(path.join(chronicleDir, "compass-last.json"), "utf8")
688
+ return JSON.parse(raw)
689
+ } catch { return null }
690
+ }
678
691
 
679
692
  // ── Main ─────────────────────────────────────────────────────────────────────
680
693
 
@@ -718,7 +731,7 @@ export async function run(argv) {
718
731
  process.exit(1)
719
732
  }
720
733
 
721
- const NO_LLM_CMDS = new Set(["map", "opportunities"])
734
+ const NO_LLM_CMDS = new Set(["map", "opportunities", "behavior", "propose", "outcome"])
722
735
  const provider = NO_LLM_CMDS.has(subcommand) ? null : await detectProvider()
723
736
  const llm = provider?.llm
724
737
 
@@ -831,7 +844,7 @@ export async function run(argv) {
831
844
  let parsed
832
845
  try { parsed = parseLLMJson(raw) } catch { throw new Error(`Compass pathways: LLM returned non-JSON. Raw: ${raw.slice(0, 300)}`) }
833
846
  const data = (parsed.pathways ?? []).map(p => ({ ...p, scores: computeScore(p.scores ?? {}) }))
834
- _lastArtifact = { kind: "product_pathway", items: data }
847
+ await saveLastArtifact(chronicleDir, { kind: "product_pathway", items: data })
835
848
  if (jsonMode) { console.log(JSON.stringify(data, null, 2)); break }
836
849
  renderPathways(data)
837
850
  console.log(c.dim("\nTip: run 'quorum compass propose --from-last' to stage a Chronicle entry."))
@@ -844,7 +857,7 @@ export async function run(argv) {
844
857
  let parsed
845
858
  try { parsed = parseLLMJson(raw) } catch { throw new Error(`Compass bets: LLM returned non-JSON. Raw: ${raw.slice(0, 300)}`) }
846
859
  const data = (parsed.bets ?? []).map(b => ({ ...b, scores: computeScore(b.scores ?? {}) }))
847
- _lastArtifact = { kind: "product_bet", items: data }
860
+ await saveLastArtifact(chronicleDir, { kind: "product_bet", items: data })
848
861
  if (jsonMode) { console.log(JSON.stringify(data, null, 2)); break }
849
862
  renderBets(data)
850
863
  console.log(c.dim("\nTip: run 'quorum compass propose --from-last' to stage a Chronicle entry."))
@@ -862,7 +875,7 @@ export async function run(argv) {
862
875
  let data
863
876
  try { data = parseLLMJson(raw) } catch { throw new Error(`Compass score: LLM returned non-JSON. Raw: ${raw.slice(0, 300)}`) }
864
877
  if (data.scores) data.scores = computeScore(data.scores)
865
- _lastArtifact = { kind: "product_idea_score", items: [data] }
878
+ await saveLastArtifact(chronicleDir, { kind: "product_idea_score", items: [data] })
866
879
  if (jsonMode) { console.log(JSON.stringify(data, null, 2)); break }
867
880
  renderScore(data)
868
881
  break
@@ -883,7 +896,7 @@ ${chronicleCtx}
883
896
  ## Current product behaviour
884
897
  ${behaviorCtx}
885
898
 
886
- Return ONLY valid JSON: { "title":"${title}","problem":"<problem>","target_user":"<user>","recommended_solution":"<solution>","smallest_useful_version":"<mvp>","non_goals":["<non-goal>"],"risks":["<risk>"],"open_questions":["<question>"],"suggested_quorum_checks":["<quorum command>"] }`
899
+ Return ONLY valid JSON (no markdown fences, no explanation): { "title":"${title}","problem":"<problem>","target_user":"<user>","recommended_solution":"<solution>","smallest_useful_version":"<mvp>","non_goals":["<non-goal>"],"risks":["<risk>"],"open_questions":["<question>"],"suggested_quorum_checks":["<quorum command>"] }`
887
900
  const raw = await callLLM(llm, specPrompt)
888
901
  let data
889
902
  try { data = parseLLMJson(raw) } catch { throw new Error(`Compass spec: LLM returned non-JSON. Raw: ${raw.slice(0, 300)}`) }
@@ -894,12 +907,13 @@ Return ONLY valid JSON: { "title":"${title}","problem":"<problem>","target_user"
894
907
 
895
908
  case "propose": {
896
909
  if (flags["from-last"]) {
897
- if (!_lastArtifact?.items?.length) {
898
- console.error(c.red("Error: no Compass artifact in memory. Run pathways/bets/score first in the same session."))
910
+ const last = await loadLastArtifact(chronicleDir)
911
+ if (!last?.items?.length) {
912
+ console.error(c.red("Error: no prior Compass artifact found. Run 'quorum compass pathways', 'bets', or 'score' first."))
899
913
  process.exit(1)
900
914
  }
901
- const item = _lastArtifact.items[0]
902
- const res = await stageProposal(chronicleDir, _lastArtifact.kind, item)
915
+ const item = last.items[0]
916
+ const res = await stageProposal(chronicleDir, last.kind, item)
903
917
  console.log(c.green(`\n✓ ${res.message}`))
904
918
  break
905
919
  }
package/bin/shared/llm.js CHANGED
@@ -112,7 +112,7 @@ function createAnthropicProvider(apiKey) {
112
112
  },
113
113
  body: JSON.stringify({
114
114
  model,
115
- max_tokens: 2048,
115
+ max_tokens: 8192,
116
116
  ...(systemMsg ? { system: systemMsg } : {}),
117
117
  messages: userMessages,
118
118
  }),
@@ -140,7 +140,7 @@ function createOpenAICompatProvider(apiKey, baseUrl, fixedModel) {
140
140
  body: JSON.stringify({
141
141
  model: fixedModel ?? model,
142
142
  messages,
143
- max_tokens: 2048,
143
+ max_tokens: 8192,
144
144
  }),
145
145
  })
146
146
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@balpal4495/quorum",
3
- "version": "3.0.2",
3
+ "version": "3.0.4",
4
4
  "description": "Git-backed memory and design review for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",