open-coleslaw 0.6.2 โ†’ 0.6.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/README.md CHANGED
@@ -1,140 +1,159 @@
1
1
  # ๐Ÿฅฌ Open Coleslaw
2
2
 
3
- **Just type your prompt. Like coleslaw โ€” it's already prepared, just scoop and eat.**
3
+ [![npm version](https://img.shields.io/npm/v/open-coleslaw.svg?style=flat-square&color=00b894)](https://www.npmjs.com/package/open-coleslaw)
4
+ [![license](https://img.shields.io/npm/l/open-coleslaw.svg?style=flat-square&color=6c5ce7)](LICENSE)
5
+ [![node](https://img.shields.io/node/v/open-coleslaw.svg?style=flat-square&color=0984e3)](package.json)
6
+ [![downloads](https://img.shields.io/npm/dm/open-coleslaw.svg?style=flat-square&color=fdcb6e)](https://www.npmjs.com/package/open-coleslaw)
4
7
 
5
- Open Coleslaw is a multi-agent orchestrator plugin for Claude Code. It gives you an entire AI engineering team โ€” planner, architect, engineer, verifier, product manager, researcher โ€” that organizes itself, runs real round-robin meetings, only ends a meeting when everyone actually agrees, and executes in MVP-sized cycles.
8
+ > **Type a prompt. Get a real multi-agent engineering team. No commands to learn.**
6
9
 
7
- Zero commands to memorize. Zero tools to call manually. Your AI team is already hired.
10
+ Open Coleslaw is a multi-agent orchestrator plugin for [Claude Code](https://claude.com/claude-code). Every prompt runs through a **kickoff meeting โ†’ per-MVP design meeting โ†’ plan mode โ†’ parallel workers โ†’ verification** pipeline โ€” with each speaker turn being a real `Agent` dispatch, not role-play.
8
11
 
9
- ## How It Works
12
+ ![Open Coleslaw dashboard](docs/assets/dashboard.png)
10
13
 
11
- You type a prompt like *"Build me a balance game app"*. That's it.
14
+ ---
15
+
16
+ ## Quick Start
17
+
18
+ In Claude Code:
12
19
 
13
20
  ```
14
- You: "Build me a balance game app"
21
+ /plugin marketplace add sshworld/open-coleslaw
22
+ /plugin install open-coleslaw@sshworld
23
+ ```
15
24
 
16
- The main Claude session (acting as meeting runner) runs the whole pipeline:
25
+ Open a new session, then just type what you want:
17
26
 
18
- โ‘  Kickoff meeting
19
- ยท Dispatches open-coleslaw:planner to decompose request into ordered MVPs
20
- ยท Minutes written to docs/open-coleslaw/
27
+ ```
28
+ Build me a balance-game web app
29
+ ```
21
30
 
22
- โ‘ก Per MVP โ€” Design meeting (round-robin, consensus-based)
23
- ยท Dispatches open-coleslaw:architect โ†’ speech โ†’ add-transcript
24
- ยท Dispatches open-coleslaw:engineer โ†’ speech โ†’ add-transcript
25
- ยท Dispatches open-coleslaw:verifier โ†’ speech โ†’ add-transcript
26
- ยท After each round, planner runs a consensus check (AGREE / DISAGREE)
27
- ยท Repeats until everyone AGREEs (max 10 rounds, then @mention escalation)
28
- ยท Planner synthesizes minutes โ†’ docs/open-coleslaw/
31
+ That's it. Watch the meeting unfold at **http://localhost:35143**.
29
32
 
30
- โ‘ข Plan Mode
31
- ยท EnterPlanMode โ†’ plan from minutes โ†’ user approves
33
+ ---
32
34
 
33
- โ‘ฃ Implementation
34
- ยท Dispatches N ร— open-coleslaw:worker in parallel
35
+ ## What You Type vs What Happens
35
36
 
36
- โ‘ค Verification
37
- ยท open-coleslaw:verifier runs tests / build
38
- ยท PASS โ†’ next MVP ยท FAIL โ†’ verify-retry meeting โ†’ re-plan
37
+ | You type | The pipeline runs |
38
+ |---|---|
39
+ | `Build me a balance-game web app` | Kickoff โ†’ 3 MVPs โ†’ per-MVP design meeting โ†’ plan mode โ†’ workers โ†’ verified |
40
+ | `Fix the flaky login test` | Kickoff (1 MVP) โ†’ design meeting w/ engineer + verifier โ†’ plan โ†’ fix โ†’ green |
41
+ | `Should we migrate from Redux to Zustand?` | Design meeting w/ architect + engineer + researcher โ†’ minutes with recommendation |
39
42
 
40
- โ‘ฅ All MVPs done โ†’ touch .cycle-complete โ†’ final report
41
- ```
43
+ You don't call a tool. You don't pick a department. You don't write prompt templates.
44
+ The main Claude session **dispatches each specialist as a real subagent** and
45
+ collects their actual output into the meeting transcript.
42
46
 
43
- Every speaker turn is a **real** `Agent` dispatch. No role-playing. The
44
- dashboard at `localhost:35143` shows each specialist's actual comment appear
45
- in the thread as the main session dispatches them.
47
+ ---
46
48
 
47
- You never call a tool. You never pick a department. You never manage an agent.
49
+ ## Why Open Coleslaw
48
50
 
49
- Meeting minutes are saved to `docs/open-coleslaw/` in your project, so they persist even if you `/compact` or `/clear` your Claude Code context between MVPs.
51
+ - **Real multi-agent, not one-LLM role-play.** Every speaker turn is a separate `Agent` dispatch with its own context. The dashboard shows the real comments as they stream in.
52
+ - **Consensus, not round count.** A meeting only ends when everyone actually agrees. If 10 rounds pass without consensus, you get an `@mention` to break the tie.
53
+ - **Minutes survive compaction.** Everything is written to `docs/open-coleslaw/` inside your project. `/compact` and `/clear` don't lose meeting history.
54
+ - **Model-agnostic.** No hardcoded model names anywhere. Switch with `/model` and the whole pipeline follows โ€” Opus, Sonnet, Haiku, or whatever ships next.
50
55
 
51
- ## Installation
56
+ ---
52
57
 
53
- In Claude Code:
58
+ ## The Team
54
59
 
55
- ```
56
- /plugin marketplace add sshworld/open-coleslaw
57
- /plugin install open-coleslaw@sshworld
58
- ```
60
+ 7 agents, all dispatched by the main Claude session:
61
+
62
+ | Agent | Role |
63
+ |---|---|
64
+ | `planner` | Chairs the meeting. Runs rounds, checks consensus, synthesises minutes. **Always attends.** |
65
+ | `architect` | System design, API contracts, schemas |
66
+ | `engineer` | Implementation feasibility, code quality |
67
+ | `verifier` | Test strategy at design time; runs tests/build at verify time |
68
+ | `product-manager` | Requirements, user stories, prioritisation |
69
+ | `researcher` | Codebase exploration, prior art, library comparison |
70
+ | `worker` | Writes code (N workers in parallel during implementation) |
59
71
 
60
- Then start a new session. That's it โ€” every prompt now goes through the orchestrator pipeline.
72
+ Planner is mandatory. The other specialists are convened dynamically based on what the task actually needs.
61
73
 
62
- ### Verify It Works
74
+ ---
63
75
 
64
- Start a new session and type anything:
76
+ ## The Pipeline
65
77
 
66
78
  ```
67
- Design a REST API for a todo app
79
+ You type a prompt
80
+ โ”‚
81
+ โ–ผ
82
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
83
+ โ”‚ Main Claude โ”‚
84
+ โ”‚ session (you) โ”‚
85
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
86
+ โ”‚ dispatches
87
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
88
+ โ–ผ โ–ผ โ–ผ
89
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” Design meeting Plan Mode โ†’ approve
90
+ โ”‚ Kickoff โ”‚ planner โ†’ architect โ”‚
91
+ โ”‚ planner โ”‚ โ†’ engineer โ†’ verifier โ”‚
92
+ โ”‚ โ†’ MVPs โ”‚ (consensus check parallel
93
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ every round) workers
94
+ โ”‚ โ”‚
95
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
96
+ โ–ผ
97
+ verifier
98
+ / \
99
+ pass fail
100
+ โ”‚ โ”‚
101
+ next MVP verify-retry meeting
68
102
  ```
69
103
 
70
- You should see the orchestrator agent being dispatched and a kickoff meeting starting automatically.
104
+ When all MVPs pass verification, the main session touches a marker file and the Stop hook checks your context usage โ€” if you're over ~30%, it suggests running `/compact` or `/clear`. Minutes on disk mean you lose nothing.
71
105
 
72
- ## The Pipeline (flat)
106
+ ---
73
107
 
74
- There is no orchestrator subagent any more. The **main Claude session** runs
75
- the whole pipeline โ€” dispatching planner + specialists one-by-one and collecting
76
- their real output into `add-transcript`. This is what makes "multi-agent" mean
77
- multi-agent: each speaker turn is a fresh `Agent` call with its own context, not
78
- one LLM role-playing every role.
108
+ ## Dashboard
79
109
 
80
- ```
81
- Kickoff โ†’ per-MVP design meeting โ†’ Plan Mode โ†’ Workers โ†’ Verify โ†’ (loop)
82
- ```
110
+ A live meeting viewer at **http://localhost:35143**:
83
111
 
84
- Verification failure doesn't abort the cycle โ€” it opens a focused
85
- `verify-retry` meeting and re-plans the fix.
112
+ - **Current meeting as a thread** โ€” speakers post comments, stance badges (AGREE / DISAGREE / SPEAKING) appear inline
113
+ - **MVP progress panel** โ€” pending / in-progress / done
114
+ - **Comment from the browser** โ€” type a note straight into the meeting; it's picked up at the next round boundary
115
+ - **Per-project tabs** โ€” multiple terminals on the same project merge into one tab
116
+ - **Past meetings** โ€” survives MCP restart (rehydrated from markdown minutes on disk)
86
117
 
87
- When the whole cycle ends the orchestrator touches a marker file, and the `Stop` hook checks your context usage. If you're over ~30%, it suggests running `/compact` or `/clear` before the next task. Minutes on disk mean you lose nothing.
118
+ ---
88
119
 
89
- ## The Agent Cast
120
+ ## Philosophy
90
121
 
91
- ```
92
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
93
- โ”‚ Main Claude session โ”‚ โ† You. Runs the pipeline directly.
94
- โ”‚ (dispatches everyone) โ”‚
95
- โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
96
- โ”‚
97
- Kickoff โ†’ per-MVP design loop
98
- โ”‚
99
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
100
- โ–ผ โ–ผ โ–ผ โ–ผ
101
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
102
- โ”‚ Planner โ”‚ โ”‚ Architectโ”‚ โ”‚ Engineer โ”‚ โ”‚ Verifier โ”‚ + product-manager /
103
- โ”‚ (chair) โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ researcher as needed
104
- โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
105
- Always Dynamic Dynamic Dynamic
106
- โ”‚
107
- Plan Mode โ†’ User approves
108
- โ”‚
109
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
110
- โ–ผ โ–ผ โ–ผ
111
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
112
- โ”‚Worker 1โ”‚ โ”‚Worker 2โ”‚ โ€ฆ โ”‚Worker Nโ”‚ โ† Parallel implementation
113
- โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
114
- โ”‚
115
- Verifier runs tests
116
- / \
117
- Pass Fail โ†’ verify-retry meeting
118
- โ†“
119
- Next MVP (or done)
120
- ```
122
+ ### The Coleslaw Principle
123
+
124
+ Coleslaw is a side dish that's already made. You don't prepare it โ€” you just eat it. This plugin works the same way. You don't configure agents, define workflows, or call tools. You describe what you want, and the system figures out the rest.
125
+
126
+ ### Key Decisions
121
127
 
122
- **6 Specialist agents** (you dispatch each one yourself):
123
- Planner, Architect, Engineer, Verifier, Product Manager, Researcher. Plus Worker (parallelized for implementation).
128
+ - **The orchestrator is your proxy, not a CEO.** You are the decision-maker. The orchestrator acts on your behalf but escalates important choices via `@mention`.
129
+ - **Kickoff first.** Every non-trivial request starts by breaking itself into ordered MVPs.
130
+ - **Consensus, not round count.** A meeting ends when everyone actually agrees (or you're asked to break a tie).
131
+ - **Minutes are the real artifact.** They survive `/compact` and `/clear` โ€” your Claude Code context is disposable.
132
+ - **TDD by default.** The engineer and verifier draft tests before workers start writing code.
124
133
 
125
- The **planner always attends** โ€” chairs the meeting, runs the round-robin, drives consensus. Other specialists are convened dynamically based on the task.
134
+ ---
126
135
 
127
- ## Meetings That Actually End on Agreement
136
+ ## Development
137
+
138
+ ```bash
139
+ git clone https://github.com/sshworld/open-coleslaw.git
140
+ cd open-coleslaw
141
+ npm install
142
+ npm run build
143
+ npm test # 260 tests
144
+ npm run lint # type-check only
128
145
 
129
- Rounds are not fixed. After every round the planner asks each participant AGREE or DISAGREE. The meeting only proceeds to synthesis when everyone agrees. If round 10 passes without consensus, the planner escalates via `@mention` for you to decide.
146
+ COLESLAW_MOCK=1 node dist/index.js # run without the Claude CLI
147
+ ```
130
148
 
131
- This is deliberately slower than a fixed-round meeting โ€” but each MVP ends with a real decision, not a paper one.
149
+ See [`CLAUDE.md`](CLAUDE.md) and [`docs/smoke-tests.md`](docs/smoke-tests.md) before shipping a release โ€” unit tests alone don't catch multi-agent regressions.
132
150
 
133
- ## What's Inside
151
+ ---
134
152
 
135
- ### 15 MCP Tools (orchestrator calls these โ€” you never do)
153
+ <details>
154
+ <summary><strong>๐Ÿ›  15 MCP tools</strong> (the pipeline calls these โ€” you don't)</summary>
136
155
 
137
- | Tool | What It Does |
156
+ | Tool | What it does |
138
157
  |------|-------------|
139
158
  | `start-meeting` | Creates a meeting record (kickoff / design / verify-retry) |
140
159
  | `add-transcript` | Saves a speaker's turn |
@@ -145,99 +164,43 @@ This is deliberately slower than a fixed-round meeting โ€” but each MVP ends wit
145
164
  | `get-task-report` | Shows execution results per department |
146
165
  | `get-agent-tree` | Displays the agent hierarchy (bookkeeping) |
147
166
  | `respond-to-mention` | Resolves a pending decision escalated by an agent |
148
- | `get-mentions` | Lists pending @mention decisions |
167
+ | `get-mentions` | Lists pending `@mention` decisions |
149
168
  | `cancel-meeting` | Stops a meeting and cascades to workers |
150
169
  | `list-meetings` | Shows meeting history |
151
170
  | `create-capability` | Self-extends the plugin with new hooks/skills |
152
171
  | `get-cost-summary` | Tracks spend per agent/meeting/department |
153
172
  | `chain-meeting` | Links meetings โ€” previous minutes feed the next |
154
173
 
155
- ### 7 Agents (all dispatched by the main Claude session via the Agent tool)
156
-
157
- | Agent | Role |
158
- |-------|------|
159
- | `planner` | Runs the meeting, chairs rounds, checks consensus, synthesises minutes |
160
- | `architect` | System design, API contracts, schemas |
161
- | `engineer` | Implementation feasibility, code quality |
162
- | `verifier` | Testing strategy at design time; tests/build at verify time |
163
- | `product-manager` | Requirements, user stories, prioritisation |
164
- | `researcher` | Codebase exploration, prior art, library comparison |
165
- | `worker` | Writes code (N workers in parallel) |
174
+ </details>
166
175
 
167
- ### 7 Skills
176
+ <details>
177
+ <summary><strong>๐ŸŽฏ 7 skills</strong> (the plugin registers these in your session)</summary>
168
178
 
169
179
  | Skill | Purpose |
170
180
  |-------|---------|
171
- | `using-open-coleslaw` | Injected at session start โ€” ensures all requests go through the pipeline |
172
- | `meeting` | Dispatches the orchestrator for the meeting โ†’ plan โ†’ implement flow |
173
- | `status` | Shows active meetings, agents, pending mentions |
174
- | `dashboard` | Opens the real-time dashboard |
175
- | `mention` | Handles pending @mention decisions |
176
- | `agents` | Shows the agent hierarchy tree |
177
- | `minutes` | Browses past meeting minutes |
178
-
179
- ### Real-Time Meeting Dashboard
180
-
181
- A live meeting viewer at `http://localhost:35143`:
182
-
183
- - **Current meeting as a thread** โ€” speakers post comments, consensus stances are shown inline
184
- - **MVP progress panel** โ€” which MVPs are pending / in-progress / done
185
- - **User comment box** โ€” type a note straight into the meeting from the browser; the orchestrator picks it up at the next round boundary (file-queue routed to `docs/open-coleslaw/.pending-comments.jsonl`)
186
- - **Terminal comments also work** โ€” if you prompt Claude Code while a meeting is in progress, your prompt becomes a user turn in the thread
187
- - Per-project tabs (multiple terminals โ†’ multiple tabs); duplicate names auto-number: `project`, `project (1)`
188
-
189
- ### Self-Extending
190
-
191
- Ask for a workflow that doesn't exist yet, and the orchestrator creates it โ€” new hooks, skills, or automations โ€” registered for future use.
192
-
193
- ## Agent Tiers
194
-
195
- | Tier | Model | Role |
196
- |------|-------|------|
197
- | Meeting runner | inherits from user session | The main Claude session itself โ€” dispatches everything |
198
- | Specialist subagent | inherits from user session | Dispatched per speaker turn |
199
- | Worker subagent | inherits from user session | Dispatched per implementation task |
200
-
201
- **No model is hard-coded.** Every specialist, every worker runs on whatever
202
- model you've selected in your Claude Code session (Opus, Sonnet, Haiku, or
203
- anything Anthropic ships next). Switch models with `/model` and the whole
204
- pipeline follows.
181
+ | `using-open-coleslaw` | Injected at session start โ€” the full pipeline runbook |
182
+ | `meeting` | Shortcut pointer to the runbook |
183
+ | `status` | Active meetings, agents, pending mentions |
184
+ | `dashboard` | Opens the live dashboard |
185
+ | `mention` | Handle pending `@mention` decisions |
186
+ | `agents` | Show the agent hierarchy |
187
+ | `minutes` | Browse past meeting minutes |
205
188
 
206
- ## Philosophy
207
-
208
- ### The Coleslaw Principle
209
-
210
- Coleslaw is a side dish that's already made. You don't prepare it โ€” you just eat it. This plugin works the same way. You don't configure agents, define workflows, or call tools. You describe what you want, and the system figures out the rest.
211
-
212
- ### Key Decisions
213
-
214
- - **The Orchestrator is your proxy, not a CEO.** You are the decision-maker. The orchestrator acts on your behalf but escalates important choices via @mention.
215
- - **Kickoff first.** Every non-trivial request starts by breaking itself into ordered MVPs.
216
- - **Consensus, not round count.** A meeting ends when everyone actually agrees (or you are asked to break a tie).
217
- - **Minutes are the real artifact.** They survive `/compact` and `/clear` โ€” your Claude Code context is disposable.
218
- - **Agents check before they code.** Every specialist reads the project's state before proposing anything.
189
+ </details>
219
190
 
220
- ## Development
191
+ <details>
192
+ <summary><strong>๐Ÿงฉ Self-extension</strong></summary>
221
193
 
222
- ```bash
223
- git clone https://github.com/sshworld/open-coleslaw.git
224
- cd open-coleslaw
225
- npm install
226
- npm run build
194
+ Ask for a workflow that doesn't exist yet (a new hook, a new skill, a custom automation) and the pipeline creates it, registered for future use. Powered by the `create-capability` MCP tool.
227
195
 
228
- # Run with mock agents (no Claude CLI needed)
229
- COLESLAW_MOCK=1 node dist/index.js
196
+ </details>
230
197
 
231
- # Run tests
232
- npm test
233
-
234
- # Type check
235
- npm run lint
236
- ```
198
+ ---
237
199
 
238
200
  ## Contributing
239
201
 
240
- See [CLAUDE.md](CLAUDE.md) for contributor guidelines.
202
+ See [CLAUDE.md](CLAUDE.md). TDD is the default โ€” write the failing test or
203
+ structural assertion first, then implement.
241
204
 
242
205
  ## License
243
206
 
package/dist/index.js CHANGED
@@ -2500,7 +2500,10 @@ var CostTracker = class {
2500
2500
  byDepartment[leader.department] = (byDepartment[leader.department] ?? 0) + cost;
2501
2501
  }
2502
2502
  }
2503
- } catch {
2503
+ } catch (err) {
2504
+ logger.debug(
2505
+ `Cost tracker: DB aggregation skipped (${err instanceof Error ? err.message : String(err)})`
2506
+ );
2504
2507
  }
2505
2508
  const filteredEntries = meetingId ? this.entries.filter((e) => e.meetingId === meetingId) : this.entries;
2506
2509
  for (const entry of filteredEntries) {
@@ -3810,6 +3813,126 @@ connect();
3810
3813
 
3811
3814
  // src/dashboard/state-bridge.ts
3812
3815
  import { EventEmitter as EventEmitter2 } from "events";
3816
+
3817
+ // src/dashboard/minutes-hydrator.ts
3818
+ import { readdir, readFile } from "fs/promises";
3819
+ import { join as join5 } from "path";
3820
+ var MINUTES_DIR = "docs/open-coleslaw";
3821
+ async function hydratePastMeetings(projectPath, limit = 20) {
3822
+ const dir = join5(projectPath, MINUTES_DIR);
3823
+ let files;
3824
+ try {
3825
+ files = await readdir(dir);
3826
+ } catch {
3827
+ return [];
3828
+ }
3829
+ const minutesFiles = files.filter((f) => f.endsWith(".md")).filter((f) => f !== "INDEX.md").filter((f) => !f.startsWith(".")).sort().reverse();
3830
+ const threads = [];
3831
+ for (const filename of minutesFiles) {
3832
+ if (threads.length >= limit) break;
3833
+ try {
3834
+ const content = await readFile(join5(dir, filename), "utf-8");
3835
+ const parsed = parseMinutesMarkdown(filename, content);
3836
+ if (parsed) threads.push(parsed);
3837
+ } catch (err) {
3838
+ logger.warn(
3839
+ `minutes-hydrator: failed to parse ${filename}: ${err instanceof Error ? err.message : String(err)}`
3840
+ );
3841
+ }
3842
+ }
3843
+ return threads;
3844
+ }
3845
+ function parseMinutesMarkdown(filename, md) {
3846
+ const topic = grabField(md, "Topic") || firstH1(md) || filename.replace(/\.md$/, "");
3847
+ const meetingId = grabField(md, "MeetingId") || grabField(md, "meetingId") || `hydrated:${filename}`;
3848
+ const date = grabField(md, "Date") || inferDateFromFilename(filename) || "";
3849
+ const type = inferTypeFromFilename(filename);
3850
+ const participants = parseParticipants(md);
3851
+ const decisions = extractBulletedSection(md, "Decisions");
3852
+ const actionItems = extractBulletedSection(md, "Action Items");
3853
+ const agenda = extractNumberedSection(md, "Agenda");
3854
+ const startedAt = date ? Date.parse(date) || Date.now() : Date.now();
3855
+ return {
3856
+ meetingId,
3857
+ meetingType: type,
3858
+ topic,
3859
+ agenda,
3860
+ participants,
3861
+ status: "completed",
3862
+ phase: "minutes-generation",
3863
+ comments: [],
3864
+ mvps: [],
3865
+ decisions,
3866
+ actionItems,
3867
+ startedAt,
3868
+ completedAt: startedAt
3869
+ };
3870
+ }
3871
+ function grabField(md, name) {
3872
+ const re = new RegExp(
3873
+ `^\\s*-?\\s*\\*{0,2}\\s*${escapeRegex(name)}\\s*\\*{0,2}\\s*:\\s*\\*{0,2}\\s*(.+?)\\s*\\*{0,2}\\s*$`,
3874
+ "im"
3875
+ );
3876
+ const m = md.match(re);
3877
+ if (!m) return null;
3878
+ return m[1].replace(/^\**/, "").replace(/\**$/, "").trim();
3879
+ }
3880
+ function firstH1(md) {
3881
+ const m = md.match(/^#\s+(.+)$/m);
3882
+ if (!m) return null;
3883
+ return m[1].replace(/^Meeting Minutes\s*[โ€”-]\s*/i, "").trim();
3884
+ }
3885
+ function parseParticipants(md) {
3886
+ const field = grabField(md, "Participants");
3887
+ if (!field) return [];
3888
+ return field.replace(/\*+/g, "").split(/[,ใ€]/).map((s) => s.trim()).filter(Boolean);
3889
+ }
3890
+ function extractBulletedSection(md, heading) {
3891
+ const lines = md.split("\n");
3892
+ const out = [];
3893
+ let inSection = false;
3894
+ for (const line of lines) {
3895
+ const h = line.match(/^#{2,3}\s+(.+)$/);
3896
+ if (h) {
3897
+ inSection = h[1].trim().toLowerCase().startsWith(heading.toLowerCase());
3898
+ continue;
3899
+ }
3900
+ if (!inSection) continue;
3901
+ const m = line.match(/^\s*[-*]\s+(?:\[[ xX]\]\s+)?(.*\S)\s*$/);
3902
+ if (m) out.push(m[1]);
3903
+ }
3904
+ return out;
3905
+ }
3906
+ function extractNumberedSection(md, heading) {
3907
+ const lines = md.split("\n");
3908
+ const out = [];
3909
+ let inSection = false;
3910
+ for (const line of lines) {
3911
+ const h = line.match(/^#{2,3}\s+(.+)$/);
3912
+ if (h) {
3913
+ inSection = h[1].trim().toLowerCase().startsWith(heading.toLowerCase());
3914
+ continue;
3915
+ }
3916
+ if (!inSection) continue;
3917
+ const m = line.match(/^\s*\d+\.\s+(.+\S)\s*$/);
3918
+ if (m) out.push(m[1]);
3919
+ }
3920
+ return out;
3921
+ }
3922
+ function inferTypeFromFilename(filename) {
3923
+ if (filename.includes("_kickoff_")) return "kickoff";
3924
+ if (filename.includes("_verify-retry_") || filename.includes("-verify-retry")) return "verify-retry";
3925
+ return "design";
3926
+ }
3927
+ function inferDateFromFilename(filename) {
3928
+ const m = filename.match(/^(\d{4}-\d{2}-\d{2})_/);
3929
+ return m ? m[1] : null;
3930
+ }
3931
+ function escapeRegex(s) {
3932
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3933
+ }
3934
+
3935
+ // src/dashboard/state-bridge.ts
3813
3936
  var MAX_PAST_MEETINGS = 20;
3814
3937
  var EVENT_DEBOUNCE_MS = 100;
3815
3938
  var StateBridge = class extends EventEmitter2 {
@@ -3852,6 +3975,21 @@ var StateBridge = class extends EventEmitter2 {
3852
3975
  this.projects.set(info.projectPath, state);
3853
3976
  this.sessionToProject.set(info.sessionId, info.projectPath);
3854
3977
  logger.info(`Project registered: ${displayName} (${info.projectPath})`);
3978
+ hydratePastMeetings(info.projectPath).then((past) => {
3979
+ if (past.length === 0) return;
3980
+ const current = this.projects.get(info.projectPath);
3981
+ if (!current) return;
3982
+ if (current.pastMeetings.length > 0) return;
3983
+ current.pastMeetings = past;
3984
+ logger.info(
3985
+ `Hydrated ${past.length} past meeting(s) for ${displayName}`
3986
+ );
3987
+ this.emit("broadcast", JSON.stringify(this.getSnapshot()));
3988
+ }).catch((err) => {
3989
+ logger.warn(
3990
+ `Failed to hydrate past meetings for ${displayName}: ${err instanceof Error ? err.message : String(err)}`
3991
+ );
3992
+ });
3855
3993
  this.emit(
3856
3994
  "broadcast",
3857
3995
  JSON.stringify({
@@ -4084,13 +4222,13 @@ var DashboardClient = class {
4084
4222
 
4085
4223
  // src/dashboard/comment-queue.ts
4086
4224
  import { appendFile, mkdir } from "fs/promises";
4087
- import { join as join5 } from "path";
4225
+ import { join as join6 } from "path";
4088
4226
  var DIR = "docs/open-coleslaw";
4089
4227
  var PENDING = ".pending-comments.jsonl";
4090
4228
  async function enqueueComment(projectPath, entry) {
4091
- const dir = join5(projectPath, DIR);
4229
+ const dir = join6(projectPath, DIR);
4092
4230
  await mkdir(dir, { recursive: true });
4093
- const file = join5(dir, PENDING);
4231
+ const file = join6(dir, PENDING);
4094
4232
  const line = JSON.stringify(entry) + "\n";
4095
4233
  await appendFile(file, line, "utf8");
4096
4234
  }
@@ -4196,7 +4334,10 @@ function startDashboard(options) {
4196
4334
  } else if (msg.type === "ping") {
4197
4335
  ws.send(JSON.stringify({ type: "pong" }));
4198
4336
  }
4199
- } catch {
4337
+ } catch (err) {
4338
+ logger.debug(
4339
+ `Malformed WebSocket message: ${err instanceof Error ? err.message : String(err)}`
4340
+ );
4200
4341
  }
4201
4342
  });
4202
4343
  });
@@ -4225,7 +4366,10 @@ async function main() {
4225
4366
  const sessionId = randomUUID();
4226
4367
  const projectPath = process.cwd();
4227
4368
  const projectName = projectPath.split("/").pop() ?? "unknown";
4228
- startDashboard({ sessionId, projectPath, projectName }).catch(() => {
4369
+ startDashboard({ sessionId, projectPath, projectName }).catch((err) => {
4370
+ logger.warn(
4371
+ `Dashboard startup failed: ${err instanceof Error ? err.message : String(err)}`
4372
+ );
4229
4373
  });
4230
4374
  }
4231
4375
  const server = createServer();
@@ -4233,7 +4377,9 @@ async function main() {
4233
4377
  await server.connect(transport);
4234
4378
  }
4235
4379
  main().catch((error) => {
4236
- console.error("Fatal error:", error);
4380
+ logger.error(
4381
+ `Fatal error: ${error instanceof Error ? error.message : String(error)}`
4382
+ );
4237
4383
  process.exit(1);
4238
4384
  });
4239
4385
  //# sourceMappingURL=index.js.map