ai-whisper 0.6.1 → 0.8.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/README.md +2 -2
- package/dist/bin/broker-daemon.js +266 -17
- package/dist/bin/companion-agent.js +272 -48
- package/dist/bin/relay-monitor.js +231 -7
- package/dist/bin/whisper.js +474 -119
- package/package.json +2 -2
- package/skills/ai-whisper-deliberation/SKILL.md +167 -0
- package/skills/ai-whisper-deliberation-craft/SKILL.md +39 -0
package/README.md
CHANGED
|
@@ -99,7 +99,7 @@ whisper collab mount claude
|
|
|
99
99
|
whisper collab mount codex
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
The first `mount` creates the collab and starts the broker daemon for the workspace; the second binds the other agent. From either session, start a workflow against a spec or goal file
|
|
102
|
+
The first `mount` creates the collab and starts the broker daemon for the workspace; the second binds the other agent. From either session, start a workflow against a spec or goal file — `spec-driven-development` for a spec, `ralph-loop` for an open-ended goal, plus `complex-bug-fixing` and `deliberation` (see [Workflows](docs/workflows.md)). Watch it run with:
|
|
103
103
|
|
|
104
104
|
```bash
|
|
105
105
|
whisper collab dashboard
|
|
@@ -121,7 +121,7 @@ For the full mental model, read [Concepts](docs/concepts.md).
|
|
|
121
121
|
|
|
122
122
|
## Learn more
|
|
123
123
|
|
|
124
|
-
- [Workflows](docs/workflows.md) — how to use the workflows well: choosing between `spec-driven-development
|
|
124
|
+
- [Workflows](docs/workflows.md) — how to use the four workflows well: choosing between `spec-driven-development`, `ralph-loop`, `complex-bug-fixing`, and `deliberation`, and authoring the spec, goal, bug report, or seed that drives the run.
|
|
125
125
|
- [Concepts](docs/concepts.md) — the mental model: baton handoff, real mounted sessions, supervised autonomy, workflow-first execution.
|
|
126
126
|
- [Relay & handoff flows](docs/relay-handoff-flows.md) — the complete handoff state machine, capture-status table, hotkey reference, per-step verdicts, and troubleshooting.
|
|
127
127
|
- [Evaluator configuration](docs/evaluator-configuration.md) — required credentials and options for the LLM evaluator that gates workflows.
|
|
@@ -1998,6 +1998,7 @@ function buildCollabSummary(db, collabId2) {
|
|
|
1998
1998
|
return {
|
|
1999
1999
|
collabId: e.collabId,
|
|
2000
2000
|
label,
|
|
2001
|
+
workspaceRoot: collab2?.workspaceRoot ?? "",
|
|
2001
2002
|
workflowId: wf?.workflowId ?? null,
|
|
2002
2003
|
workflowType: wf?.workflowType ?? null,
|
|
2003
2004
|
workflowStatus: wf?.status ?? null,
|
|
@@ -2211,11 +2212,51 @@ Findings: (omit this block entirely if none)
|
|
|
2211
2212
|
|
|
2212
2213
|
<verdict line: "Approved. <one or two sentences>" OR, when blocked/cannot-proceed, state you cannot proceed and why>
|
|
2213
2214
|
|
|
2215
|
+
Non-blocking risks:
|
|
2216
|
+
- <risk that does NOT block this gate, or "None.">
|
|
2217
|
+
--- end protocol ---`;
|
|
2218
|
+
var WORKFLOW_DELIBERATION_PROTOCOL = `--- ai-whisper deliberation review protocol ---
|
|
2219
|
+
You are the Challenger at an ai-whisper Deliberation layer gate. No human is in the loop. The Explorer has proposed this layer's output; your job is to produce GENUINE adversarial pressure, not to rubber-stamp. The gate stays shut until the layer's output survives real attack \u2014 OR the only remaining material questions are preference-dependent forks, which you RECORD rather than resolve.
|
|
2220
|
+
|
|
2221
|
+
Decision-materiality is the bar. Sort every finding four ways:
|
|
2222
|
+
- BLOCKING (drives not-approved): it would change a reasonable decision-maker's choice.
|
|
2223
|
+
- OPEN QUESTION (non-blocking): material but depends on the human's private preference \u2014 surface it, do not resolve it, do not block on it.
|
|
2224
|
+
- NON-BLOCKING RISK (non-blocking): a real but non-decision-changing risk \u2014 surface it under the Non-blocking risks section (always last), never gag it.
|
|
2225
|
+
- SUPPRESS: pure noise (style/taste) only.
|
|
2226
|
+
|
|
2227
|
+
Required procedure:
|
|
2228
|
+
1. Independent derivation (skin in the game): on this layer's FIRST review, derive your OWN candidate (your own objectives / approach set / tradeoff map) BEFORE reading the Explorer's, then diff. Report the material gap. On fix-rounds, re-audit the revision.
|
|
2229
|
+
2. Forbid recall-based verification: you may NOT clear a material claim with "that matches what I know" \u2014 you and the Explorer share priors and therefore blind spots. Verify every material claim against an EXTERNAL source (re-run the grep, open the cited file, fetch the source, check the actual API) and tag it "verified against <source>". A material claim you cannot externally verify becomes an Open Question marked "could not verify \u2014 you should".
|
|
2230
|
+
3. Verify by materiality and surface, not by felt uncertainty: verify what is load-bearing and what is a specific or suspiciously-convenient fact (version numbers, API signatures, file paths, citations, benchmarks), regardless of how confident it sounds.
|
|
2231
|
+
4. Steelman, then attack, with coverage: state the strongest version of the Explorer's position, then surface at least one unexamined assumption, one missing alternative, and one material risk \u2014 or explicitly certify that each lens was run and why none is decision-material. "Looks good" is not a legal handback.
|
|
2232
|
+
5. Generative mandate: beyond auditing the Explorer, independently GENERATE angles and alternatives it did not raise.
|
|
2233
|
+
6. Distrust your own agreement: treat your own "yeah, that's right" as a red flag to verify, not a green light.
|
|
2234
|
+
|
|
2235
|
+
Per-layer attack weighting: objectives -> framing + assumption (is the QUESTION itself right?); approaches -> alternative + evidence (is the set complete, is each grounded and feasible?); tradeoffs -> feasibility + second-order (honest, or cherry-picked / buried costs?); synthesis -> faithfulness (does the findings doc match the deliberation; are the Open Questions the right ones?).
|
|
2236
|
+
|
|
2237
|
+
You emit approved / not-approved + findings ONLY. You do NOT label the workflow outcome (advance / loop / escalate) \u2014 whether the gate result causes the run to advance, loop, or escalate is the evaluator's job. Approve only when the layer survived real attack with the work shown. If a required input is missing and the Explorer cannot supply it, do NOT approve \u2014 name the missing input and state you cannot proceed (so the gate escalates). If exploring this layer reveals that an EARLIER ratified layer is wrong, state you cannot proceed and why (the run escalates; it does not silently re-open the earlier layer).
|
|
2238
|
+
|
|
2239
|
+
Never reply with only a bare verdict; your full reply must be well over 100 characters.
|
|
2240
|
+
|
|
2241
|
+
Output format \u2014 the verdict line MUST come before the Non-blocking risks section, which is always LAST:
|
|
2242
|
+
Deliberation review matrix:
|
|
2243
|
+
| Claim / candidate | My independent derivation | Material gap | Verified against | Result |
|
|
2244
|
+
| ... |
|
|
2245
|
+
|
|
2246
|
+
Findings: (omit this block entirely if none)
|
|
2247
|
+
- <blocking finding tied to a decision-material gap, with external-verification evidence>
|
|
2248
|
+
|
|
2249
|
+
Open Questions: (omit if none)
|
|
2250
|
+
- <material but preference-dependent fork, or "could not verify X \u2014 you should">
|
|
2251
|
+
|
|
2252
|
+
<verdict line: "Approved. <one or two sentences>" OR, when blocked/cannot-proceed, state you cannot proceed and why>
|
|
2253
|
+
|
|
2214
2254
|
Non-blocking risks:
|
|
2215
2255
|
- <risk that does NOT block this gate, or "None.">
|
|
2216
2256
|
--- end protocol ---`;
|
|
2217
2257
|
var CODE_REVIEW_SKILL_GUIDANCE = "Use the ai-whisper-code-review skill to evaluate the delivered code. The workflow review protocol below controls your output format and evaluator semantics; the skill controls how you inspect code and decide which code-quality issues are blocking.\n\n";
|
|
2218
2258
|
var PLAN_EXECUTION_SKILL_GUIDANCE = "Use the ai-whisper-plan-execution skill to structure HOW you execute this plan: subagent fan-out with model allocation where your harness supports it, disciplined inline execution otherwise. The handback contract above remains authoritative \u2014 settle all delegated work before handing back, and state which execution mode you used.";
|
|
2259
|
+
var DELIBERATION_CRAFT_SKILL_GUIDANCE = "Use the ai-whisper-deliberation-craft skill for HOW to do the research and the attack \u2014 the Explorer's research contract and the Challenger's attack taxonomy. The deliberation review protocol below remains authoritative for the gate contract and output format; the craft skill is how-to only and does not restate it.\n\n";
|
|
2219
2260
|
var SDD_SPEC_REVIEW = "Review the spec at {specPath}. This is an autonomous workflow with no human in the loop.\n\n" + WORKFLOW_REVIEW_PROTOCOL;
|
|
2220
2261
|
var SDD_CODE_REVIEW = "Review the implementer's changes for this phase \u2014 the commits in {commitRange}. The upper bound is a LIVE `HEAD`: resolve it against the current repository at review time and INCLUDE any commits added during this review round (e.g. fixes for your prior findings); do not pin the review to an earlier tip. Verify against the spec's acceptance criteria and run the project's verification/tests. This is an autonomous workflow with no human in the loop.\n\n" + CODE_REVIEW_SKILL_GUIDANCE + WORKFLOW_REVIEW_PROTOCOL;
|
|
2221
2262
|
var SDD_PLAN_EXECUTION = "Execute the plan at {planPath} now: make all changes it specifies, run the verification command the plan or spec defines and ensure it passes, then commit. This is an autonomous workflow \u2014 no human will respond. Do the work yourself; never ask for confirmation, permission, or clarification. Hand back the commit SHAs and the verification output, plus a 1-2 sentence summary; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.\n\n" + PLAN_EXECUTION_SKILL_GUIDANCE;
|
|
@@ -2425,6 +2466,129 @@ var COMPLEX_BUG_FIXING = {
|
|
|
2425
2466
|
}
|
|
2426
2467
|
]
|
|
2427
2468
|
};
|
|
2469
|
+
var DELIB_REVIEW = "You are the Challenger reviewing the Explorer's output for the current Deliberation layer, grounded in the seed at {specPath}. The Explorer's working notes are under {deliberationDir}. This is an autonomous workflow with no human in the loop.\n\n" + DELIBERATION_CRAFT_SKILL_GUIDANCE + WORKFLOW_DELIBERATION_PROTOCOL;
|
|
2470
|
+
var DELIB_SYNTHESIS_REVIEW = "You are the Challenger reviewing the Explorer's SYNTHESIS layer \u2014 the committed findings document at {findingsPath}. Read {findingsPath}: it is the deliverable under review. It must faithfully collapse the ratified objectives/approaches/tradeoffs (the working notes under {deliberationDir}) into the findings skeleton \u2014 verify that faithfulness and that the Open Questions are the right ones (no material decision silently resolved, none invented). Grounded in the seed at {specPath}. This is an autonomous workflow with no human in the loop.\n\n" + DELIBERATION_CRAFT_SKILL_GUIDANCE + WORKFLOW_DELIBERATION_PROTOCOL;
|
|
2471
|
+
var DELIB_FIX = `Apply the Challenger's findings to your working notes under {deliberationDir} now, re-grounding against the seed at {specPath}. This is an autonomous workflow \u2014 no human will respond. Do the research/edits yourself; never ask for confirmation, permission, or clarification. Append one JSON line to {deliberationDir}/metrics.jsonl with the two signals spec \xA712.6 requires \u2014 "materialFindings" (the count of decision-material findings you are addressing this round) and "revisionMagnitude" (how much your output changed: "none"/"minor"/"moderate"/"major") \u2014 plus "layer" and "round". End your handback with a 1-2 sentence summary of what you changed; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.
|
|
2472
|
+
|
|
2473
|
+
` + DELIBERATION_CRAFT_SKILL_GUIDANCE;
|
|
2474
|
+
var DELIB_OBJECTIVES = `You are the Explorer in an autonomous Deliberation workflow \u2014 no human is in the loop; never ask for confirmation, permission, or clarification, and do the work yourself.
|
|
2475
|
+
|
|
2476
|
+
LAYER 1 of 4: OBJECTIVES. Read the seed at {specPath}. Research the REAL situation it points at \u2014 current state, the actual pain, the constraints. Ground every claim in the project (code, tests, git history, docs) where the seed is project-anchored; use web research only where the question reaches beyond the project. Do NOT restate the seed \u2014 DERIVE the objectives and success criteria from evidence.
|
|
2477
|
+
|
|
2478
|
+
Write your objectives working notes to {deliberationDir}/objectives.md: each derived objective with why-it-matters and its grounding source; the interpretation you took (and any you discarded) when the seed was vague; and an explicit list of known-unknowns. Append one JSON line to {deliberationDir}/metrics.jsonl with the two signals spec \xA712.6 requires \u2014 "materialFindings" (0 on this initial proposal) and "revisionMagnitude" ("initial" on the first proposal) \u2014 plus "layer" and "round". Example: {"layer":"objectives","round":1,"materialFindings":0,"revisionMagnitude":"initial"}.
|
|
2479
|
+
|
|
2480
|
+
${DELIBERATION_CRAFT_SKILL_GUIDANCE}End your handback with a 1-2 sentence summary; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.`;
|
|
2481
|
+
var DELIB_APPROACHES = `You are the Explorer in an autonomous Deliberation workflow \u2014 no human is in the loop; do the work yourself.
|
|
2482
|
+
|
|
2483
|
+
LAYER 2 of 4: APPROACHES. The objectives in {deliberationDir}/objectives.md are ratified \u2014 treat them as ground truth. Research and propose AT LEAST THREE genuinely distinct approaches to reach them. Survey the space first (prior art + in-repo idioms + candidate techniques) before evaluating any candidate; ground each approach in a real precedent. You MAY NOT pick a winner in this layer \u2014 that is the guard against premature convergence.
|
|
2484
|
+
|
|
2485
|
+
Write your approaches working notes to {deliberationDir}/approaches.md: one section per approach (gist, grounding/precedent, why it is distinct), plus the known-unknowns each carries. Append one JSON line to {deliberationDir}/metrics.jsonl with "materialFindings" and "revisionMagnitude" (plus "layer" and "round"), the two per-round signals spec \xA712.6 requires.
|
|
2486
|
+
|
|
2487
|
+
${DELIBERATION_CRAFT_SKILL_GUIDANCE}End your handback with a 1-2 sentence summary; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.`;
|
|
2488
|
+
var DELIB_TRADEOFFS = `You are the Explorer in an autonomous Deliberation workflow \u2014 no human is in the loop; do the work yourself.
|
|
2489
|
+
|
|
2490
|
+
LAYER 3 of 4: TRADEOFFS & DIFFICULTY. The approaches in {deliberationDir}/approaches.md are ratified. For EACH surviving approach, map the tradeoffs, difficulty, blast radius, and material risks \u2014 stress-tested against reality (feasibility checks and blast radius in the ACTUAL codebase, named risks, not hand-waving). Do not bury costs or cherry-pick.
|
|
2491
|
+
|
|
2492
|
+
Write your tradeoffs working notes to {deliberationDir}/tradeoffs.md: a per-approach tradeoff/difficulty/risk breakdown, with the grounding for each claim. Append one JSON line to {deliberationDir}/metrics.jsonl with "materialFindings" and "revisionMagnitude" (plus "layer" and "round"), the two per-round signals spec \xA712.6 requires.
|
|
2493
|
+
|
|
2494
|
+
${DELIBERATION_CRAFT_SKILL_GUIDANCE}End your handback with a 1-2 sentence summary; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.`;
|
|
2495
|
+
var DELIB_SYNTHESIS_FIX = 'Apply the Challenger\'s findings by RE-WRITING the corrected findings document to {findingsPath} (keep the \xA79 skeleton). Then RE-COMMIT it: `git add {findingsPath} && git commit` (do NOT commit {deliberationDir}; it is gitignored). Re-ground against the seed at {specPath} to confirm the revision is consistent. Append one JSON line to {deliberationDir}/metrics.jsonl with the two signals spec \xA712.6 requires \u2014 "materialFindings" (the count of decision-material findings you are addressing this round) and "revisionMagnitude" (how much your output changed: "none"/"minor"/"moderate"/"major") \u2014 plus "layer" and "round". End your handback with a 1-2 sentence summary of what you changed; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.\n\n' + DELIBERATION_CRAFT_SKILL_GUIDANCE;
|
|
2496
|
+
var DELIB_SYNTHESIS = `You are the Explorer in an autonomous Deliberation workflow \u2014 no human is in the loop; do the work yourself.
|
|
2497
|
+
|
|
2498
|
+
LAYER 4 of 4: SYNTHESIS. The objectives, approaches, and tradeoffs working notes under {deliberationDir} are all ratified. Collapse them into a single findings document optimized for fast human review, and WRITE it to {findingsPath} (create the directory if needed). Use exactly this skeleton:
|
|
2499
|
+
|
|
2500
|
+
# Deliberation: <topic>
|
|
2501
|
+
seed: {specPath} \xB7 <date> \xB7 <implementer>/<challenger>
|
|
2502
|
+
|
|
2503
|
+
## TL;DR
|
|
2504
|
+
- Recommended direction: <one line> (PROPOSAL)
|
|
2505
|
+
- Decisions that need you: <the 1-2 top Open Questions>
|
|
2506
|
+
|
|
2507
|
+
## Objectives (ratified)
|
|
2508
|
+
- <objective> \u2014 why it matters [source]
|
|
2509
|
+
- interpretation taken: ...; discarded: ... (only when the seed was vague)
|
|
2510
|
+
|
|
2511
|
+
## Approaches considered
|
|
2512
|
+
| Approach | Gist | Grounding/precedent | Key tradeoff | Difficulty |
|
|
2513
|
+
(one short paragraph per surviving approach only)
|
|
2514
|
+
|
|
2515
|
+
## Recommendation (PROPOSAL \u2014 overridable)
|
|
2516
|
+
<which, why over the others, and what the Challenger attacked + how it held>
|
|
2517
|
+
|
|
2518
|
+
## Risks
|
|
2519
|
+
- <material risk to the recommended direction>
|
|
2520
|
+
|
|
2521
|
+
## Open Questions (for you)
|
|
2522
|
+
- <decision> \u2014 what is at stake / why it was not settled
|
|
2523
|
+
- <"could not verify X \u2014 you should">
|
|
2524
|
+
|
|
2525
|
+
## Grounding & confidence (footer)
|
|
2526
|
+
verified against source: ... \xB7 assumed (unverified): ... \xB7 couldn't verify: ...
|
|
2527
|
+
|
|
2528
|
+
The recommendation is a clearly-marked PROPOSAL the human may override \u2014 do NOT present it as settled. Then COMMIT the findings doc: \`git add {findingsPath} && git commit\` (do NOT commit {deliberationDir}; it is gitignored). Append one JSON line to {deliberationDir}/metrics.jsonl with "materialFindings" and "revisionMagnitude" (plus "layer" and "round"), the two per-round signals spec \xA712.6 requires.
|
|
2529
|
+
|
|
2530
|
+
${DELIBERATION_CRAFT_SKILL_GUIDANCE}End your handback with a 1-2 sentence summary; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.`;
|
|
2531
|
+
var DELIBERATION = {
|
|
2532
|
+
type: "deliberation",
|
|
2533
|
+
displayName: "Deliberation",
|
|
2534
|
+
description: "Paired-agent pre-spec exploration: the Explorer proposes and the Challenger adversarially stress-tests across Objectives -> Approaches -> Tradeoffs -> Synthesis, producing a findings doc for human review",
|
|
2535
|
+
defaultImplementer: "claude",
|
|
2536
|
+
defaultReviewer: "codex",
|
|
2537
|
+
phases: [
|
|
2538
|
+
{
|
|
2539
|
+
name: "objectives",
|
|
2540
|
+
implementerRole: "implementer",
|
|
2541
|
+
reviewerRole: "reviewer",
|
|
2542
|
+
maxRounds: 6,
|
|
2543
|
+
initialHandoffStep: "implement",
|
|
2544
|
+
kickoffTemplate: DELIB_OBJECTIVES,
|
|
2545
|
+
stepTemplates: { implement: DELIB_OBJECTIVES, review: DELIB_REVIEW, fix: DELIB_FIX },
|
|
2546
|
+
reviewMode: "phase-review",
|
|
2547
|
+
evaluatorPromptKey: "deliberation-loop",
|
|
2548
|
+
artifactOut: { kind: "spec", pathTemplate: "{deliberationDir}/objectives.md" },
|
|
2549
|
+
renderFixTemplateOnFindings: true
|
|
2550
|
+
},
|
|
2551
|
+
{
|
|
2552
|
+
name: "approaches",
|
|
2553
|
+
implementerRole: "implementer",
|
|
2554
|
+
reviewerRole: "reviewer",
|
|
2555
|
+
maxRounds: 10,
|
|
2556
|
+
initialHandoffStep: "implement",
|
|
2557
|
+
kickoffTemplate: DELIB_APPROACHES,
|
|
2558
|
+
stepTemplates: { implement: DELIB_APPROACHES, review: DELIB_REVIEW, fix: DELIB_FIX },
|
|
2559
|
+
reviewMode: "phase-review",
|
|
2560
|
+
evaluatorPromptKey: "deliberation-loop",
|
|
2561
|
+
artifactOut: { kind: "spec", pathTemplate: "{deliberationDir}/approaches.md" },
|
|
2562
|
+
renderFixTemplateOnFindings: true
|
|
2563
|
+
},
|
|
2564
|
+
{
|
|
2565
|
+
name: "tradeoffs",
|
|
2566
|
+
implementerRole: "implementer",
|
|
2567
|
+
reviewerRole: "reviewer",
|
|
2568
|
+
maxRounds: 10,
|
|
2569
|
+
initialHandoffStep: "implement",
|
|
2570
|
+
kickoffTemplate: DELIB_TRADEOFFS,
|
|
2571
|
+
stepTemplates: { implement: DELIB_TRADEOFFS, review: DELIB_REVIEW, fix: DELIB_FIX },
|
|
2572
|
+
reviewMode: "phase-review",
|
|
2573
|
+
evaluatorPromptKey: "deliberation-loop",
|
|
2574
|
+
artifactOut: { kind: "spec", pathTemplate: "{deliberationDir}/tradeoffs.md" },
|
|
2575
|
+
renderFixTemplateOnFindings: true
|
|
2576
|
+
},
|
|
2577
|
+
{
|
|
2578
|
+
name: "synthesis",
|
|
2579
|
+
implementerRole: "implementer",
|
|
2580
|
+
reviewerRole: "reviewer",
|
|
2581
|
+
maxRounds: 5,
|
|
2582
|
+
initialHandoffStep: "implement",
|
|
2583
|
+
kickoffTemplate: DELIB_SYNTHESIS,
|
|
2584
|
+
stepTemplates: { implement: DELIB_SYNTHESIS, review: DELIB_SYNTHESIS_REVIEW, fix: DELIB_SYNTHESIS_FIX },
|
|
2585
|
+
reviewMode: "phase-review",
|
|
2586
|
+
evaluatorPromptKey: "deliberation-loop",
|
|
2587
|
+
artifactOut: { kind: "spec", pathTemplate: "{findingsPath}" },
|
|
2588
|
+
renderFixTemplateOnFindings: true
|
|
2589
|
+
}
|
|
2590
|
+
]
|
|
2591
|
+
};
|
|
2428
2592
|
function withOperatorControl(def) {
|
|
2429
2593
|
return {
|
|
2430
2594
|
...def,
|
|
@@ -2439,7 +2603,8 @@ ${WORKFLOW_OPERATOR_CONTROL}`
|
|
|
2439
2603
|
var REGISTRY = {
|
|
2440
2604
|
[SPEC_DRIVEN_DEVELOPMENT.type]: withOperatorControl(SPEC_DRIVEN_DEVELOPMENT),
|
|
2441
2605
|
[RALPH_LOOP.type]: withOperatorControl(RALPH_LOOP),
|
|
2442
|
-
[COMPLEX_BUG_FIXING.type]: withOperatorControl(COMPLEX_BUG_FIXING)
|
|
2606
|
+
[COMPLEX_BUG_FIXING.type]: withOperatorControl(COMPLEX_BUG_FIXING),
|
|
2607
|
+
[DELIBERATION.type]: withOperatorControl(DELIBERATION)
|
|
2443
2608
|
};
|
|
2444
2609
|
function ralphRunDir(workspaceRoot, workflowId) {
|
|
2445
2610
|
return join(workspaceRoot, ".ai-whisper", "ralph", workflowId);
|
|
@@ -2455,6 +2620,19 @@ function bugfixPaths(workspaceRoot, workflowId) {
|
|
|
2455
2620
|
postmortemPath: join(bugfixDir, "postmortem.md")
|
|
2456
2621
|
};
|
|
2457
2622
|
}
|
|
2623
|
+
function deliberationRunDir(workspaceRoot, workflowId) {
|
|
2624
|
+
return join(workspaceRoot, ".ai-whisper", "deliberation", workflowId);
|
|
2625
|
+
}
|
|
2626
|
+
function deriveFindingsPath(specPath, dateIso) {
|
|
2627
|
+
if (!/^\d{4}-\d{2}-\d{2}/.test(dateIso)) {
|
|
2628
|
+
throw new Error(`deriveFindingsPath: dateIso must start with YYYY-MM-DD, got "${dateIso}"`);
|
|
2629
|
+
}
|
|
2630
|
+
const basename3 = specPath.split("/").pop() ?? "";
|
|
2631
|
+
const withoutExt = basename3.replace(/\.[^.]+$/, "");
|
|
2632
|
+
const slug = withoutExt.replace(/^\d{4}-\d{2}-\d{2}-/, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "deliberation";
|
|
2633
|
+
const date = dateIso.slice(0, 10);
|
|
2634
|
+
return `docs/superpowers/deliberations/${date}-${slug}.md`;
|
|
2635
|
+
}
|
|
2458
2636
|
function getWorkflowDefinition(type) {
|
|
2459
2637
|
return REGISTRY[type];
|
|
2460
2638
|
}
|
|
@@ -2514,6 +2692,13 @@ function safeDerivePlanPath(specPath, createdAt) {
|
|
|
2514
2692
|
return `${dir}${stem}.plan.md`;
|
|
2515
2693
|
}
|
|
2516
2694
|
}
|
|
2695
|
+
function safeDeriveFindingsPath(specPath, createdAt) {
|
|
2696
|
+
try {
|
|
2697
|
+
return deriveFindingsPath(specPath, createdAt);
|
|
2698
|
+
} catch {
|
|
2699
|
+
return specPath;
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2517
2702
|
function composeResumeNotice(input) {
|
|
2518
2703
|
const hasFiles = input.changedFiles.length > 0;
|
|
2519
2704
|
const hasMessage = !!input.message && input.message.trim().length > 0;
|
|
@@ -2724,7 +2909,9 @@ function createWorkflowControl(deps) {
|
|
|
2724
2909
|
reviewMode,
|
|
2725
2910
|
bugfixDir: bf.bugfixDir,
|
|
2726
2911
|
diagnosisPath: bf.diagnosisPath,
|
|
2727
|
-
postmortemPath: bf.postmortemPath
|
|
2912
|
+
postmortemPath: bf.postmortemPath,
|
|
2913
|
+
deliberationDir: collab2 ? deliberationRunDir(collab2.workspaceRoot, input.workflow.workflowId) : "",
|
|
2914
|
+
findingsPath: safeDeriveFindingsPath(input.workflow.specPath, input.workflow.createdAt)
|
|
2728
2915
|
});
|
|
2729
2916
|
}
|
|
2730
2917
|
function consumeResumeNotice(input) {
|
|
@@ -2790,7 +2977,9 @@ ${requestText}` : requestText;
|
|
|
2790
2977
|
reviewMode: phase.reviewMode ?? "phase-review",
|
|
2791
2978
|
bugfixDir: bf.bugfixDir,
|
|
2792
2979
|
diagnosisPath: bf.diagnosisPath,
|
|
2793
|
-
postmortemPath: bf.postmortemPath
|
|
2980
|
+
postmortemPath: bf.postmortemPath,
|
|
2981
|
+
deliberationDir: collab2 ? deliberationRunDir(collab2.workspaceRoot, input.workflow.workflowId) : "",
|
|
2982
|
+
findingsPath: safeDeriveFindingsPath(input.workflow.specPath, input.workflow.createdAt)
|
|
2794
2983
|
});
|
|
2795
2984
|
const chainId = `relay_ch_${randomUUID().replace(/-/g, "").slice(0, 16)}`;
|
|
2796
2985
|
const phaseRunId = `wfp_${randomUUID().replace(/-/g, "").slice(0, 16)}`;
|
|
@@ -3062,7 +3251,9 @@ ${requestText}` : requestText;
|
|
|
3062
3251
|
ralphDir,
|
|
3063
3252
|
bugfixDir: bf.bugfixDir,
|
|
3064
3253
|
diagnosisPath: bf.diagnosisPath,
|
|
3065
|
-
postmortemPath: bf.postmortemPath
|
|
3254
|
+
postmortemPath: bf.postmortemPath,
|
|
3255
|
+
deliberationDir: collab2 ? deliberationRunDir(collab2.workspaceRoot, workflow.workflowId) : "",
|
|
3256
|
+
findingsPath: safeDeriveFindingsPath(workflow.specPath, workflow.createdAt)
|
|
3066
3257
|
});
|
|
3067
3258
|
fixRequestText = `${fixTmpl}
|
|
3068
3259
|
|
|
@@ -5255,6 +5446,23 @@ function ensureBugfixWorkspace(workspaceRoot, workflowId) {
|
|
|
5255
5446
|
return dir;
|
|
5256
5447
|
}
|
|
5257
5448
|
|
|
5449
|
+
// ../broker/dist/runtime/deliberation-setup.js
|
|
5450
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, existsSync as existsSync4 } from "node:fs";
|
|
5451
|
+
import { join as join5 } from "node:path";
|
|
5452
|
+
function ensureDeliberationWorkspace(workspaceRoot, workflowId) {
|
|
5453
|
+
const dir = deliberationRunDir(workspaceRoot, workflowId);
|
|
5454
|
+
mkdirSync3(dir, { recursive: true });
|
|
5455
|
+
const ignorePath = join5(workspaceRoot, ".ai-whisper", ".gitignore");
|
|
5456
|
+
if (!existsSync4(ignorePath)) {
|
|
5457
|
+
writeFileSync3(ignorePath, "*\n");
|
|
5458
|
+
}
|
|
5459
|
+
const deliberationIgnorePath = join5(workspaceRoot, ".ai-whisper", "deliberation", ".gitignore");
|
|
5460
|
+
if (!existsSync4(deliberationIgnorePath)) {
|
|
5461
|
+
writeFileSync3(deliberationIgnorePath, "*\n");
|
|
5462
|
+
}
|
|
5463
|
+
return dir;
|
|
5464
|
+
}
|
|
5465
|
+
|
|
5258
5466
|
// ../broker/dist/runtime/workflow-driver.js
|
|
5259
5467
|
function createWorkflowDriver(deps) {
|
|
5260
5468
|
const { broker: broker2, headReader } = deps;
|
|
@@ -5357,6 +5565,20 @@ function createWorkflowDriver(deps) {
|
|
|
5357
5565
|
}
|
|
5358
5566
|
}
|
|
5359
5567
|
const bugfix = bugfixPaths(collab2.workspaceRoot, workflowId);
|
|
5568
|
+
if (workflow.workflowType === "deliberation") {
|
|
5569
|
+
try {
|
|
5570
|
+
ensureDeliberationWorkspace(collab2.workspaceRoot, workflowId);
|
|
5571
|
+
} catch (err) {
|
|
5572
|
+
broker2.control.haltWorkflow({ workflowId, reason: `deliberation setup failed: ${String(err)}`, now });
|
|
5573
|
+
return;
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
const deliberationDir = deliberationRunDir(collab2.workspaceRoot, workflowId);
|
|
5577
|
+
let findingsPath = workflow.specPath;
|
|
5578
|
+
try {
|
|
5579
|
+
findingsPath = deriveFindingsPath(workflow.specPath, workflow.createdAt);
|
|
5580
|
+
} catch {
|
|
5581
|
+
}
|
|
5360
5582
|
const ctx = workflow.workflowContext;
|
|
5361
5583
|
let planPath = workflow.specPath;
|
|
5362
5584
|
try {
|
|
@@ -5371,7 +5593,9 @@ function createWorkflowDriver(deps) {
|
|
|
5371
5593
|
reviewMode: phase.reviewMode ?? "phase-review",
|
|
5372
5594
|
bugfixDir: bugfix.bugfixDir,
|
|
5373
5595
|
diagnosisPath: bugfix.diagnosisPath,
|
|
5374
|
-
postmortemPath: bugfix.postmortemPath
|
|
5596
|
+
postmortemPath: bugfix.postmortemPath,
|
|
5597
|
+
deliberationDir,
|
|
5598
|
+
findingsPath
|
|
5375
5599
|
});
|
|
5376
5600
|
try {
|
|
5377
5601
|
broker2.control.beginPhaseRun({
|
|
@@ -5536,7 +5760,7 @@ var EVENT_PROTOCOL_VERSION = "1";
|
|
|
5536
5760
|
|
|
5537
5761
|
// ../broker/dist/runtime/event-socket-server.js
|
|
5538
5762
|
import { createServer } from "node:net";
|
|
5539
|
-
import { existsSync as
|
|
5763
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, unlinkSync as unlinkSync2 } from "node:fs";
|
|
5540
5764
|
import { dirname as dirname2 } from "node:path";
|
|
5541
5765
|
var EVENT_NAME_TABLE = {
|
|
5542
5766
|
"chain.resolved": true,
|
|
@@ -5555,8 +5779,8 @@ var ALL_BROKER_EVENT_NAMES = Object.keys(EVENT_NAME_TABLE);
|
|
|
5555
5779
|
async function createEventSocketServer(input) {
|
|
5556
5780
|
const now = input.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
5557
5781
|
const clients = /* @__PURE__ */ new Set();
|
|
5558
|
-
|
|
5559
|
-
if (
|
|
5782
|
+
mkdirSync4(dirname2(input.socketPath), { recursive: true });
|
|
5783
|
+
if (existsSync5(input.socketPath)) {
|
|
5560
5784
|
try {
|
|
5561
5785
|
unlinkSync2(input.socketPath);
|
|
5562
5786
|
} catch {
|
|
@@ -5612,7 +5836,7 @@ async function createEventSocketServer(input) {
|
|
|
5612
5836
|
dropClient(conn);
|
|
5613
5837
|
server.close(() => {
|
|
5614
5838
|
try {
|
|
5615
|
-
if (
|
|
5839
|
+
if (existsSync5(input.socketPath))
|
|
5616
5840
|
unlinkSync2(input.socketPath);
|
|
5617
5841
|
} catch {
|
|
5618
5842
|
}
|
|
@@ -5750,6 +5974,24 @@ var REVIEW_JSON_SCHEMA = {
|
|
|
5750
5974
|
},
|
|
5751
5975
|
required: ["verdict", "confidence", "reason"]
|
|
5752
5976
|
};
|
|
5977
|
+
var DELIBERATION_REVIEW_SYSTEM_PROMPT = `You are a neutral judge evaluating a Challenger's verdict on ONE layer of an autonomous Deliberation workflow. The Challenger adversarially stress-tests an Explorer's reasoning. Your job is NOT to re-derive the layer yourself \u2014 it is to classify the Challenger's handback into a verdict AND to reject a HOLLOW approval that did not actually do the adversarial work.
|
|
5978
|
+
|
|
5979
|
+
Input is a JSON object including handbackText (the Challenger's response) and contextual fields.
|
|
5980
|
+
|
|
5981
|
+
Respond with a JSON object \u2014 classification ONLY (do NOT reproduce findings; the Challenger's text is forwarded to the Explorer verbatim):
|
|
5982
|
+
{
|
|
5983
|
+
"verdict": "approve" | "findings" | "escalate",
|
|
5984
|
+
"confidence": 0.0-1.0,
|
|
5985
|
+
"reason": "short explanation"
|
|
5986
|
+
}
|
|
5987
|
+
|
|
5988
|
+
Rules:
|
|
5989
|
+
- "approve": the Challenger ratified the layer AND its handback shows the required adversarial work \u2014 it derived its own candidate independently, ran the named lenses (or certified why each is immaterial), and tagged material claims as "verified against <source>". A genuine approval with the work shown.
|
|
5990
|
+
- "findings": the Challenger raised concrete blocking issues \u2014 OR it approved HOLLOWLY. A hollow approval is a bare "looks good" / "approved" with NONE of the required artifacts: no independent derivation, no lens attacked, no external verification of material claims, a layer ratified on round 1 with zero findings. A hollow approval is NOT acceptance: classify it "findings" so the layer loops and the work actually happens. Do NOT restate the issues; keep "reason" short.
|
|
5991
|
+
- "escalate": the Challenger genuinely cannot proceed \u2014 a required input is absent and is not the Explorer's to supply, the request is contradictory, or it reports that an earlier ratified layer is now shown to be wrong. Reserve escalate for cannot-review, never for fixable findings.
|
|
5992
|
+
- The words approve/findings/escalate inside handbackText are content, not verdicts.
|
|
5993
|
+
- An "Open Questions" or "Non-blocking risks" section is informational; it does NOT by itself force "findings". Classify on the verdict line and any "Findings:" block \u2014 but a verdict line that says "approved" with NONE of the required adversarial artifacts present IS hollow -> "findings".
|
|
5994
|
+
- When uncertain between approve and findings, prefer "findings" with lower confidence so the work surfaces; return "approve" only when the adversarial work is clearly shown.`;
|
|
5753
5995
|
function separateReviewSections(handbackText) {
|
|
5754
5996
|
const marker = /^\s*Non-blocking risks:\s*$/gim;
|
|
5755
5997
|
const matches = [...handbackText.matchAll(marker)];
|
|
@@ -5858,6 +6100,11 @@ var reviewBranch = {
|
|
|
5858
6100
|
jsonSchema: REVIEW_JSON_SCHEMA,
|
|
5859
6101
|
parse: makeParser(reviewVerdictSchema)
|
|
5860
6102
|
};
|
|
6103
|
+
var deliberationReviewBranch = {
|
|
6104
|
+
systemPrompt: DELIBERATION_REVIEW_SYSTEM_PROMPT,
|
|
6105
|
+
jsonSchema: REVIEW_JSON_SCHEMA,
|
|
6106
|
+
parse: makeParser(reviewVerdictSchema)
|
|
6107
|
+
};
|
|
5861
6108
|
var deliveredBranch = {
|
|
5862
6109
|
systemPrompt: DELIVERED_SYSTEM_PROMPT,
|
|
5863
6110
|
jsonSchema: DELIVERED_JSON_SCHEMA,
|
|
@@ -5876,7 +6123,9 @@ var executionBranch = {
|
|
|
5876
6123
|
function selectBranch(payload) {
|
|
5877
6124
|
if ("evaluatorPromptKey" in payload) {
|
|
5878
6125
|
if (payload.evaluatorPromptKey === "execution-gate") return executionBranch;
|
|
5879
|
-
if (payload.handoffStep === "review")
|
|
6126
|
+
if (payload.handoffStep === "review") {
|
|
6127
|
+
return payload.evaluatorPromptKey === "deliberation-loop" ? deliberationReviewBranch : reviewBranch;
|
|
6128
|
+
}
|
|
5880
6129
|
if (payload.handoffStep === "implement" || payload.handoffStep === "fix") {
|
|
5881
6130
|
return payload.evaluatorPromptKey === "ralph-loop" ? ralphDeliveredBranch : deliveredBranch;
|
|
5882
6131
|
}
|
|
@@ -6031,7 +6280,7 @@ function createRelayOrchestratorEvaluator(input) {
|
|
|
6031
6280
|
return async function evaluateRelayHandoff(call) {
|
|
6032
6281
|
const callGroupId = crypto3.randomUUID();
|
|
6033
6282
|
const branch = selectBranch(call.payload);
|
|
6034
|
-
const branchName = branch === legacyBranch ? "legacy" : branch === reviewBranch ? "review" : branch === deliveredBranch || branch === ralphDeliveredBranch ? "delivered" : "execution";
|
|
6283
|
+
const branchName = branch === legacyBranch ? "legacy" : branch === reviewBranch || branch === deliberationReviewBranch ? "review" : branch === deliveredBranch || branch === ralphDeliveredBranch ? "delivered" : "execution";
|
|
6035
6284
|
const effectivePayload = branch === reviewBranch && "handbackText" in call.payload ? {
|
|
6036
6285
|
...call.payload,
|
|
6037
6286
|
handbackText: separateReviewSections(call.payload.handbackText).body
|
|
@@ -6437,7 +6686,7 @@ function writeOwnPidToBrokerDaemon(db, input) {
|
|
|
6437
6686
|
|
|
6438
6687
|
// src/runtime/evaluator-config.ts
|
|
6439
6688
|
import { readFileSync as readFileSync2, statSync as statSync3 } from "node:fs";
|
|
6440
|
-
import { join as
|
|
6689
|
+
import { join as join6 } from "node:path";
|
|
6441
6690
|
|
|
6442
6691
|
// src/runtime/state-root.ts
|
|
6443
6692
|
import os from "node:os";
|
|
@@ -6499,15 +6748,15 @@ function loadEvaluatorConfig() {
|
|
|
6499
6748
|
const root = getStateRoot();
|
|
6500
6749
|
let dotenv = {};
|
|
6501
6750
|
try {
|
|
6502
|
-
dotenv = parseDotEnv(readFileSync2(
|
|
6751
|
+
dotenv = parseDotEnv(readFileSync2(join6(root, ".env"), "utf8"));
|
|
6503
6752
|
} catch (err) {
|
|
6504
6753
|
if (err.code !== "ENOENT") throw err;
|
|
6505
6754
|
}
|
|
6506
6755
|
const envGet = (k) => process.env[k] ?? dotenv[k];
|
|
6507
|
-
const authPath =
|
|
6756
|
+
const authPath = join6(root, "auth.json");
|
|
6508
6757
|
warnIfLoosePerms(authPath);
|
|
6509
6758
|
const auth = readJsonFile(authPath, "auth.json");
|
|
6510
|
-
const config = readJsonFile(
|
|
6759
|
+
const config = readJsonFile(join6(root, "config.json"), "config.json");
|
|
6511
6760
|
const evalCfg = config?.evaluator ?? {};
|
|
6512
6761
|
const evalOllama = evalCfg.ollama ?? {};
|
|
6513
6762
|
const provider = (envGet("AI_WHISPER_EVALUATOR_PROVIDER") ?? evalCfg.provider) === "ollama" ? "ollama" : "anthropic";
|
|
@@ -6554,7 +6803,7 @@ function recordEvaluatorStatus(db, input) {
|
|
|
6554
6803
|
|
|
6555
6804
|
// src/bin/broker-daemon.ts
|
|
6556
6805
|
import { execFile as execFile2 } from "node:child_process";
|
|
6557
|
-
import { join as
|
|
6806
|
+
import { join as join7 } from "node:path";
|
|
6558
6807
|
|
|
6559
6808
|
// src/runtime/cli-package-info.ts
|
|
6560
6809
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
@@ -6604,7 +6853,7 @@ if (collabId) {
|
|
|
6604
6853
|
});
|
|
6605
6854
|
workflowEventBridge.start();
|
|
6606
6855
|
eventSocket = await createEventSocketServer({
|
|
6607
|
-
socketPath:
|
|
6856
|
+
socketPath: join7(getStateSocketsDir(), `events-${collabId}.sock`),
|
|
6608
6857
|
events: [broker.events, externalEvents],
|
|
6609
6858
|
engineVersion: resolveCliVersion()
|
|
6610
6859
|
});
|