@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.
- package/bin/commands/compass.js +40 -26
- package/bin/shared/llm.js +2 -2
- package/package.json +1 -1
package/bin/commands/compass.js
CHANGED
|
@@ -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
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
return { ...
|
|
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 (
|
|
676
|
+
// ── Last-run artifact cache (persisted to disk so propose --from-last works across invocations) ─
|
|
676
677
|
|
|
677
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
898
|
-
|
|
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 =
|
|
902
|
-
const res = await stageProposal(chronicleDir,
|
|
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:
|
|
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:
|
|
143
|
+
max_tokens: 8192,
|
|
144
144
|
}),
|
|
145
145
|
})
|
|
146
146
|
|