@damian87/omp 0.2.0 → 0.4.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.
Files changed (57) hide show
  1. package/.github/skills/weighted-consensus/SKILL.md +120 -0
  2. package/README.md +59 -1
  3. package/catalog/capabilities.json +46 -0
  4. package/catalog/skills-general.json +29 -1
  5. package/dist/src/cli.d.ts +8 -0
  6. package/dist/src/cli.js +147 -3
  7. package/dist/src/cli.js.map +1 -1
  8. package/dist/src/council/config.d.ts +32 -0
  9. package/dist/src/council/config.js +84 -0
  10. package/dist/src/council/config.js.map +1 -0
  11. package/dist/src/council/engine.d.ts +19 -0
  12. package/dist/src/council/engine.js +193 -0
  13. package/dist/src/council/engine.js.map +1 -0
  14. package/dist/src/council/index.d.ts +20 -0
  15. package/dist/src/council/index.js +72 -0
  16. package/dist/src/council/index.js.map +1 -0
  17. package/dist/src/council/prompts.d.ts +32 -0
  18. package/dist/src/council/prompts.js +173 -0
  19. package/dist/src/council/prompts.js.map +1 -0
  20. package/dist/src/council/synth.d.ts +15 -0
  21. package/dist/src/council/synth.js +57 -0
  22. package/dist/src/council/synth.js.map +1 -0
  23. package/dist/src/council/types.d.ts +96 -0
  24. package/dist/src/council/types.js +4 -0
  25. package/dist/src/council/types.js.map +1 -0
  26. package/dist/src/mode-state/paths.d.ts +6 -0
  27. package/dist/src/mode-state/paths.js +12 -0
  28. package/dist/src/mode-state/paths.js.map +1 -1
  29. package/dist/src/team/api.d.ts +60 -1
  30. package/dist/src/team/api.js +101 -0
  31. package/dist/src/team/api.js.map +1 -1
  32. package/dist/src/team/config.d.ts +7 -0
  33. package/dist/src/team/config.js +16 -0
  34. package/dist/src/team/config.js.map +1 -0
  35. package/dist/src/team/mailbox.d.ts +30 -0
  36. package/dist/src/team/mailbox.js +188 -0
  37. package/dist/src/team/mailbox.js.map +1 -0
  38. package/dist/src/team/runtime.d.ts +9 -1
  39. package/dist/src/team/runtime.js +18 -12
  40. package/dist/src/team/runtime.js.map +1 -1
  41. package/dist/src/team/types.d.ts +25 -0
  42. package/dist/src/team/worker-bootstrap.js +29 -0
  43. package/dist/src/team/worker-bootstrap.js.map +1 -1
  44. package/dist/test/catalog.test.d.ts +1 -0
  45. package/dist/test/catalog.test.js +21 -0
  46. package/dist/test/catalog.test.js.map +1 -0
  47. package/dist/test/jira.test.d.ts +1 -0
  48. package/dist/test/jira.test.js +26 -0
  49. package/dist/test/jira.test.js.map +1 -0
  50. package/dist/test/lint.test.d.ts +1 -0
  51. package/dist/test/lint.test.js +9 -0
  52. package/dist/test/lint.test.js.map +1 -0
  53. package/dist/test/sync.test.d.ts +1 -0
  54. package/dist/test/sync.test.js +15 -0
  55. package/dist/test/sync.test.js.map +1 -0
  56. package/docs/plans/2026-05-29-team-messaging-and-nudge-gating-design.md +170 -0
  57. package/package.json +1 -1
@@ -0,0 +1,170 @@
1
+ # Design: Team messaging (worker↔worker / worker↔leader) + nudge gating
2
+
3
+ > Status: **Design only — no implementation yet.** Target repo: `oh-my-copilot`.
4
+ > Date: 2026-05-29
5
+
6
+ ## 1. Problem & evidence
7
+
8
+ Two related gaps in `src/team`:
9
+
10
+ **A. Workers cannot message anyone.** The entire `team api` surface (`src/cli.ts:35`) is:
11
+
12
+ - `team api claim-task`
13
+ - `team api transition-task-status`
14
+
15
+ There is **no `send-message`, `broadcast`, or mailbox** anywhere in `src`. The only
16
+ worker→lead signal is an outbox line auto-appended on task transition
17
+ (`src/team/api.ts:55-65`), consumed by the monitor (`readNewOutbox`). So a worker
18
+ cannot ask the lead a question, hand off to a peer, or nudge a teammate. This is the
19
+ "teams says limitation can't message" behavior.
20
+
21
+ This must work **without MCP** (Copilot CLI; MCP is disabled in the target org). The
22
+ existing design is already file + CLI based, so this is the natural fit.
23
+
24
+ **B. Nudge is ungated.** `NudgeTracker` runs only inside `monitorTeam`
25
+ (`src/team/runtime.ts:224`) and is **default-on** (`:213`). `monitorTeam` is not yet
26
+ wired into any command, so nudge effectively never fires today — but when it is wired
27
+ in, default-on would nudge every monitored team run (including read-only polling).
28
+ Desired: **off by default, but ON for `/team` orchestration runs and for active
29
+ ralph/loop modes.** Plain read-only polling (`team status`) and library/one-shot use
30
+ stay quiet.
31
+
32
+ ## 2. What already exists (reuse, don't rebuild)
33
+
34
+ - `state-paths.ts` already defines `mailboxDir` (`.omp/state/team/<team>/mailbox`) and
35
+ `dispatchDir`, and `ensureTeamDirs` already creates them. Workers already have
36
+ `inboxFile` (`workers/<name>/inbox.md`), `outboxFile`, `heartbeatFile`, pane id in
37
+ config (`Worker.paneId`).
38
+ - `tmux.ts` exposes `sendToWorker(api, paneId, text, …)` — the nudge transport.
39
+ - `outbox.ts` has a robust byte-cursor JSONL reader we can mirror for mailbox reads.
40
+
41
+ ## 3. Feature A — messaging
42
+
43
+ ### 3.1 Data model
44
+
45
+ New file `src/team/mailbox.ts`. One JSONL file per recipient:
46
+ `.omp/state/team/<team>/mailbox/<recipient>.jsonl`, plus a `.<recipient>.offset` cursor
47
+ (mirror `outbox.ts`). `leader` is the reserved recipient name for the lead.
48
+
49
+ ```ts
50
+ export interface MailboxMessage {
51
+ id: string; // uuid
52
+ from: string; // worker name or "leader"
53
+ to: string; // worker name or "leader"
54
+ body: string;
55
+ timestamp: string; // ISO
56
+ deliveredAt?: string;
57
+ }
58
+ ```
59
+
60
+ Functions: `appendMailbox`, `readNewMailbox`/`peekMailbox` (cursor-based),
61
+ `listMailbox`, `markDelivered`.
62
+
63
+ ### 3.2 API surface (additions to `src/team/api.ts` + `cli.ts`)
64
+
65
+ - `team api send-message --input '{team_name, from, to, body, cwd?}'`
66
+ → validates `to` is `leader` or a registered worker (`config.workers`), rejects
67
+ unknown recipients with `unknown_recipient` (no phantom mailbox), appends to the
68
+ recipient mailbox, then **nudges the recipient pane** (see 3.3).
69
+ - `team api broadcast --input '{team_name, from, body, cwd?}'`
70
+ → fans out to **every worker except `from`, PLUS the `leader` mailbox**.
71
+ Reuses oh-my-claudecode's mechanism (`teamBroadcast`, `team-ops.ts:604`: loop
72
+ recipients → `send` to each), but oh-my-claudecode skips the lead (it only iterates
73
+ `cfg.workers`); here we additionally append `leader` to the recipient set so the lead
74
+ receives broadcasts too. Sender is always excluded (no self-message, no echo loop).
75
+ - `team api mailbox-list --input '{team_name, worker, cwd?}'` → list (optionally
76
+ undelivered only).
77
+ - `team api mailbox-mark-delivered --input '{team_name, worker, message_id, cwd?}'`.
78
+
79
+ All pure file ops, callable directly in tests (no MCP, no tmux required for persistence).
80
+
81
+ ### 3.3 Delivery / nudge
82
+
83
+ After persisting, look up the recipient's `paneId` from `config.workers` (or
84
+ `leader_pane_id` in config). If present and a tmux session is live, call
85
+ `sendToWorker(...)` with a short trigger. If no pane (worker not spawned / headless
86
+ test), persistence still succeeds — delivery is pull-based via `mailbox-list`.
87
+ **Nudge-on-send reuses the same `sendToWorker` transport, independent of the
88
+ idle-`NudgeTracker`.**
89
+
90
+ **Throttle/coalesce — reuse what already exists, build nothing new:**
91
+ - The idle `NudgeTracker` (`idle-nudge.ts`) already carries the same throttle as
92
+ oh-my-claudecode (`scanIntervalMs: 5000`, `maxCount: 3`) — unchanged.
93
+ - For send-nudge, mirror oh-my-claudecode's `generateMailboxTriggerMessage(count)`:
94
+ the trigger states the **unread count** (`listMailbox(...).filter(!deliveredAt).length`)
95
+ — "N new msg(s): read your mailbox …". Multiple messages arriving before the worker
96
+ reads simply raise the count in the next poke rather than spamming distinct triggers.
97
+ No separate coalescing/debounce machinery.
98
+
99
+ ### 3.4 Worker overlay (`worker-bootstrap.ts buildInboxMarkdown`)
100
+
101
+ Add a "Messaging" section teaching workers they may message the **lead OR any teammate**:
102
+
103
+ ```
104
+ omp team api send-message --input '{"team_name":…,"from":"<me>","to":"leader","body":"…"}' --json
105
+ omp team api send-message --input '{"team_name":…,"from":"<me>","to":"<teammate>","body":"…"}' --json
106
+ omp team api mailbox-list --input '{"team_name":…,"worker":"<me>"}' --json
107
+ ```
108
+
109
+ State that the recipient is auto-nudged, and that unknown names return `unknown_recipient`.
110
+
111
+ ### 3.5 Tests (Vitest, file-based, no MCP)
112
+
113
+ `test/team/mailbox.test.ts` + `test/team/api.messaging.test.ts`:
114
+ worker→leader, worker→peer, broadcast-excludes-sender, mailbox-list/mark-delivered,
115
+ unknown-recipient rejection, cursor advance. A nudge unit test mocks `tmux`/`sendToWorker`
116
+ to assert the recipient pane is poked.
117
+
118
+ ## 4. Feature B — nudge gating
119
+
120
+ Change `monitorTeam` so nudge is **off by default**, but **ON for `/team`
121
+ orchestration runs and active ralph/loop modes**:
122
+
123
+ - Default `opts.nudge?.enabled` to **`false`** (flip current `!== false`).
124
+ - Add `resolveNudgeEnabled(opts, cwd)` → `true` when ANY of:
125
+ 1. `opts.nudge?.enabled === true` — set by the **`/team` command's monitor loop**
126
+ (the orchestration spawn+monitor path in `cli.ts` passes `nudge:{enabled:true}`).
127
+ This is what makes nudge ON for `/team`.
128
+ 2. A loop-mode state file is active: `readRalph(cwd)?.active`, or the equivalent
129
+ `ultrawork`/`ultraqa` state (modes live at `.omp/state/<mode>.json`,
130
+ `src/mode-state/paths.ts`).
131
+ 3. Falls back to `false` otherwise.
132
+ - Add a small `isLoopModeActive(cwd)` helper in `mode-state` (reads the three mode
133
+ files) so condition 2 is one source of truth.
134
+
135
+ Result:
136
+ - **`/team` orchestration** → nudge ON (condition 1).
137
+ - **ralph / ultrawork / ultraqa loops** → nudge ON (condition 2).
138
+ - **Read-only `team status` / library one-shot use** → nudge OFF (no `enabled:true`,
139
+ no active loop mode).
140
+
141
+ ### Tests
142
+
143
+ `test/team/runtime.test.ts` additions: nudge off by default; ON when `enabled:true`
144
+ (the `/team` path); ON when a ralph/loop mode state is active; OFF when neither signal
145
+ is present (e.g. `team status` polling).
146
+
147
+ ## 5. Build sequence
148
+
149
+ 1. `mailbox.ts` + tests (red→green).
150
+ 2. `api.ts` messaging fns + `cli.ts` wiring + tests.
151
+ 3. `worker-bootstrap.ts` overlay docs + test.
152
+ 4. Nudge gating in `runtime.ts` + `mode-state` helper + tests.
153
+ 5. Update `.github/skills/team/SKILL.md` to document messaging + nudge gating.
154
+
155
+ ## 6. Out of scope (YAGNI)
156
+
157
+ - No dispatch-queue/retry state machine (the richer oh-my-claudecode design) — pull-based
158
+ mailbox + best-effort nudge is enough here.
159
+ - No leader registered as a team member; `leader` stays a reserved mailbox name.
160
+ - No cross-team messaging.
161
+
162
+ ## 7. Resolved decisions
163
+
164
+ - **Broadcast reaches workers AND the lead** (every worker except sender + the `leader`
165
+ mailbox). Extends oh-my-claudecode's workers-only `teamBroadcast`.
166
+ - **Nudge throttling reuses existing mechanisms** (idle `NudgeTracker` scan/maxCount +
167
+ an unread-count in the send trigger, mirroring `generateMailboxTriggerMessage`).
168
+ No new debounce/coalesce layer.
169
+ - **Nudge gating:** off by default; ON for `/team` orchestration runs and active
170
+ ralph/ultrawork/ultraqa loop modes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damian87/omp",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "GitHub Copilot project skills catalog and Jira handoff tools.",
5
5
  "type": "module",
6
6
  "publishConfig": {