@damian87/omp 0.6.0 → 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/.github/skills/team/SKILL.md +82 -57
- package/.github/skills/team/scripts/team-launch.sh +140 -42
- package/README.md +31 -0
- package/catalog/skills-general.json +2 -2
- package/dist/src/cli.d.ts +1 -7
- package/dist/src/cli.js +355 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/registry.d.ts +3 -0
- package/dist/src/commands/registry.js +11 -0
- package/dist/src/commands/registry.js.map +1 -0
- package/dist/src/commands/suggest.d.ts +19 -0
- package/dist/src/commands/suggest.js +158 -0
- package/dist/src/commands/suggest.js.map +1 -0
- package/dist/src/commands/types.d.ts +16 -0
- package/dist/src/commands/types.js +2 -0
- package/dist/src/commands/types.js.map +1 -0
- package/dist/src/env/dotenv.d.ts +41 -0
- package/dist/src/env/dotenv.js +112 -0
- package/dist/src/env/dotenv.js.map +1 -0
- package/dist/src/env/init.d.ts +50 -0
- package/dist/src/env/init.js +276 -0
- package/dist/src/env/init.js.map +1 -0
- package/dist/src/gateway/connector.d.ts +37 -0
- package/dist/src/gateway/connector.js +12 -0
- package/dist/src/gateway/connector.js.map +1 -0
- package/dist/src/gateway/connectors/slack.d.ts +69 -0
- package/dist/src/gateway/connectors/slack.js +159 -0
- package/dist/src/gateway/connectors/slack.js.map +1 -0
- package/dist/src/gateway/registry.d.ts +29 -0
- package/dist/src/gateway/registry.js +37 -0
- package/dist/src/gateway/registry.js.map +1 -0
- package/dist/src/gateway/runtime.d.ts +58 -0
- package/dist/src/gateway/runtime.js +105 -0
- package/dist/src/gateway/runtime.js.map +1 -0
- package/dist/src/instructions-memory.js +8 -15
- package/dist/src/instructions-memory.js.map +1 -1
- package/dist/src/jira.js +2 -14
- package/dist/src/jira.js.map +1 -1
- package/dist/src/slack/config.d.ts +32 -0
- package/dist/src/slack/config.js +52 -0
- package/dist/src/slack/config.js.map +1 -0
- package/dist/src/slack/handler.d.ts +48 -0
- package/dist/src/slack/handler.js +68 -0
- package/dist/src/slack/handler.js.map +1 -0
- package/dist/src/slack/serve.d.ts +8 -0
- package/dist/src/slack/serve.js +7 -0
- package/dist/src/slack/serve.js.map +1 -0
- package/dist/src/team/index.d.ts +1 -0
- package/dist/src/team/index.js +1 -0
- package/dist/src/team/index.js.map +1 -1
- package/dist/src/team/pane-monitor.d.ts +39 -0
- package/dist/src/team/pane-monitor.js +128 -0
- package/dist/src/team/pane-monitor.js.map +1 -0
- package/dist/src/team/runtime.js +12 -1
- package/dist/src/team/runtime.js.map +1 -1
- package/dist/src/team/tmux.d.ts +13 -0
- package/dist/src/team/tmux.js +47 -0
- package/dist/src/team/tmux.js.map +1 -1
- package/docs/slack-setup.md +144 -0
- package/package.json +4 -2
|
@@ -1,102 +1,127 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: team
|
|
3
|
-
description: Split an approved plan into parallel tmux panes
|
|
4
|
-
argument-hint: "<number of
|
|
3
|
+
description: Split an approved plan into parallel tmux panes in the current window so the user can watch agents work. Prefer this visual flow by default; use `omp team` only when the user explicitly wants background execution or runtime messaging/status APIs.
|
|
4
|
+
argument-hint: "<number of workers> <task description>"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Team — tmux-based parallel agent execution
|
|
8
8
|
|
|
9
|
-
`/team`
|
|
9
|
+
`/team` launches independent Copilot CLI agents in parallel tmux panes.
|
|
10
|
+
|
|
11
|
+
**Default behavior:** use the **split-window** flow so the user sees agents working in the current tmux window.
|
|
12
|
+
|
|
13
|
+
Use **runtime mode** (`omp team`) only when the user explicitly asks for background execution, detached monitoring, or runtime APIs like status, nudging, or worker messaging.
|
|
14
|
+
|
|
15
|
+
Two modes available:
|
|
16
|
+
|
|
17
|
+
| Mode | Command | Panes visible in | Best for |
|
|
18
|
+
|------|---------|-------------------|----------|
|
|
19
|
+
| **Split** | `team-launch.sh` | Current window | **Default**. Visual demo, watching agents work |
|
|
20
|
+
| **Runtime** | `omp team N:copilot "task"` | Separate tmux session | Explicit background jobs, task tracking, nudging, messaging |
|
|
10
21
|
|
|
11
22
|
## When to use
|
|
12
23
|
|
|
13
24
|
- Work has **independent lanes** (no shared files, no ordering constraints)
|
|
14
|
-
- You want
|
|
25
|
+
- You want parallel execution in split terminals
|
|
15
26
|
|
|
16
|
-
##
|
|
27
|
+
## Default mode — Split window (`team-launch.sh`)
|
|
17
28
|
|
|
18
|
-
|
|
29
|
+
Use this unless the user asks for background execution.
|
|
19
30
|
|
|
20
|
-
###
|
|
31
|
+
### When to choose it
|
|
21
32
|
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
- `prompt`: complete task prompt — must be self-contained with all context the agent needs (files to change, what to do, commit message)
|
|
33
|
+
- The user wants to **see** the agents working
|
|
34
|
+
- You want panes in the **current tmux window**
|
|
35
|
+
- You are demoing or smoke-testing the skill
|
|
26
36
|
|
|
27
|
-
|
|
37
|
+
### Step 1 — Write lanes JSON
|
|
28
38
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
Write a temporary lanes file at `/tmp/team-lanes-<timestamp>.json`:
|
|
39
|
+
Write a temporary file at `/tmp/team-lanes-<timestamp>.json`:
|
|
32
40
|
|
|
33
41
|
```json
|
|
34
42
|
[
|
|
35
|
-
{
|
|
36
|
-
|
|
37
|
-
"name": "Short descriptive name",
|
|
38
|
-
"prompt": "Complete self-contained task prompt for the agent..."
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
"id": "lane-b",
|
|
42
|
-
"name": "Another lane name",
|
|
43
|
-
"prompt": "Another complete task prompt..."
|
|
44
|
-
}
|
|
43
|
+
{ "id": "lane-a", "name": "Short name", "prompt": "Complete self-contained task prompt..." },
|
|
44
|
+
{ "id": "lane-b", "name": "Another lane", "prompt": "Another task prompt..." }
|
|
45
45
|
]
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
### Step
|
|
49
|
-
|
|
50
|
-
Run the launch script, passing the session name and lanes file path:
|
|
48
|
+
### Step 2 — Launch
|
|
51
49
|
|
|
50
|
+
```bash
|
|
51
|
+
bash ~/.copilot/installed-plugins/oh-my-copilot/oh-my-copilot/.github/skills/team/scripts/team-launch.sh \
|
|
52
|
+
--session "team-<name>" --lanes <lanes-file>
|
|
52
53
|
```
|
|
53
|
-
|
|
54
|
+
|
|
55
|
+
The script:
|
|
56
|
+
1. Splits the **current window** into panes
|
|
57
|
+
2. Launches `omp --madmax` in each
|
|
58
|
+
3. Auto-accepts folder trust prompts
|
|
59
|
+
4. Waits for readiness, sends prompts
|
|
60
|
+
5. Monitors completion and prints a results summary
|
|
61
|
+
|
|
62
|
+
### Step 3 — Report
|
|
63
|
+
|
|
64
|
+
The script blocks and prints all results. Relay the output to the user.
|
|
65
|
+
|
|
66
|
+
## Optional mode — Runtime (`omp team`)
|
|
67
|
+
|
|
68
|
+
Choose this only when the user explicitly wants the team to run in the background or needs runtime features.
|
|
69
|
+
|
|
70
|
+
### When to choose it
|
|
71
|
+
|
|
72
|
+
- The user asked for a **background** team
|
|
73
|
+
- You need `omp team status`, shutdown, or runtime task APIs
|
|
74
|
+
- You do **not** need the panes in the current tmux window
|
|
75
|
+
|
|
76
|
+
### Launch
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
omp team <N>:copilot "<task description>"
|
|
54
80
|
```
|
|
55
81
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
|
|
82
|
+
The runtime automatically:
|
|
83
|
+
1. Creates a tmux session with split panes
|
|
84
|
+
2. Launches `copilot --allow-all-tools` in each pane
|
|
85
|
+
3. Auto-accepts folder trust prompts
|
|
86
|
+
4. Waits for readiness, then sends the task prompt
|
|
87
|
+
5. Tracks task state, heartbeats, and supports idle-nudging
|
|
61
88
|
|
|
62
|
-
###
|
|
89
|
+
### Monitor and cleanup
|
|
63
90
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
91
|
+
```bash
|
|
92
|
+
omp team status <team-name> # check progress
|
|
93
|
+
tmux attach -t omp-team-<name> # watch panes live
|
|
94
|
+
omp team shutdown <team-name> # kill when done
|
|
95
|
+
```
|
|
69
96
|
|
|
70
97
|
## Prerequisites
|
|
71
98
|
|
|
72
|
-
- `tmux` installed and running
|
|
73
|
-
- `omp`
|
|
74
|
-
-
|
|
75
|
-
- `jq` for JSON parsing
|
|
99
|
+
- `tmux` installed and session running
|
|
100
|
+
- `omp` on PATH
|
|
101
|
+
- `jq` for JSON parsing (split mode only)
|
|
76
102
|
|
|
77
|
-
##
|
|
103
|
+
## Task / prompt guidelines
|
|
78
104
|
|
|
79
|
-
Each
|
|
105
|
+
Each task must be **self-contained**. The agent has no context from this session. Include:
|
|
80
106
|
- Exact files or directories to work in
|
|
81
|
-
- What to do (fix, upgrade,
|
|
82
|
-
- How to verify (run tests,
|
|
107
|
+
- What to do (fix, upgrade, etc.)
|
|
108
|
+
- How to verify (run tests, etc.)
|
|
83
109
|
- Commit message to use
|
|
84
110
|
|
|
85
|
-
### Good
|
|
111
|
+
### Good example
|
|
86
112
|
|
|
87
|
-
>
|
|
113
|
+
> In src/auth/login.ts, replace bcrypt with argon2. Update the import, change the verify call, run `npm test -- --grep auth`. Commit: "refactor: switch to argon2".
|
|
88
114
|
|
|
89
|
-
### Bad
|
|
115
|
+
### Bad example
|
|
90
116
|
|
|
91
|
-
> Fix the auth module. (Too vague
|
|
117
|
+
> Fix the auth module. (Too vague)
|
|
92
118
|
|
|
93
119
|
## Composition
|
|
94
120
|
|
|
95
|
-
Use `/ralplan` before `/team` to produce the plan
|
|
121
|
+
Use `/ralplan` before `/team` to produce the plan. Use `/verify` after completion.
|
|
96
122
|
|
|
97
123
|
## Limitations
|
|
98
124
|
|
|
99
|
-
- Each pane is an independent
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
- Best for independent, non-conflicting work streams
|
|
125
|
+
- Each pane is an independent session — no shared state
|
|
126
|
+
- Workers can message each other via `omp team api send-message` (runtime mode only)
|
|
127
|
+
- If tasks depend on each other, use `/ralph` instead
|
|
@@ -7,9 +7,11 @@ set -euo pipefail
|
|
|
7
7
|
# Usage:
|
|
8
8
|
# team-launch.sh --session <name> --lanes <lanes.json>
|
|
9
9
|
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# for
|
|
10
|
+
# Flow:
|
|
11
|
+
# 1. Split panes and launch agent CLI in each
|
|
12
|
+
# 2. Wait for each agent to be ready (auto-accept folder trust prompts)
|
|
13
|
+
# 3. Send lane prompts via send-keys
|
|
14
|
+
# 4. Monitor until all agents finish, then print summary
|
|
13
15
|
|
|
14
16
|
SESSION=""
|
|
15
17
|
LANES_FILE=""
|
|
@@ -33,13 +35,11 @@ if [[ ! -f "$LANES_FILE" ]]; then
|
|
|
33
35
|
fi
|
|
34
36
|
|
|
35
37
|
if ! command -v tmux &>/dev/null; then
|
|
36
|
-
echo "tmux not found" >&2
|
|
37
|
-
exit 1
|
|
38
|
+
echo "tmux not found" >&2; exit 1
|
|
38
39
|
fi
|
|
39
40
|
|
|
40
41
|
if [[ -z "${TMUX:-}" ]]; then
|
|
41
|
-
echo "Not inside a tmux session. Run this from within tmux." >&2
|
|
42
|
-
exit 1
|
|
42
|
+
echo "Not inside a tmux session. Run this from within tmux." >&2; exit 1
|
|
43
43
|
fi
|
|
44
44
|
|
|
45
45
|
if command -v omp &>/dev/null; then
|
|
@@ -47,31 +47,60 @@ if command -v omp &>/dev/null; then
|
|
|
47
47
|
elif command -v copilot &>/dev/null; then
|
|
48
48
|
AGENT_CMD="copilot"
|
|
49
49
|
else
|
|
50
|
-
echo "Neither omp nor copilot CLI found" >&2
|
|
51
|
-
exit 1
|
|
50
|
+
echo "Neither omp nor copilot CLI found" >&2; exit 1
|
|
52
51
|
fi
|
|
53
52
|
|
|
54
53
|
LANE_COUNT=$(jq length "$LANES_FILE")
|
|
55
54
|
if [[ "$LANE_COUNT" -lt 1 ]]; then
|
|
56
|
-
echo "No lanes defined in $LANES_FILE" >&2
|
|
57
|
-
exit 1
|
|
55
|
+
echo "No lanes defined in $LANES_FILE" >&2; exit 1
|
|
58
56
|
fi
|
|
59
57
|
|
|
60
58
|
CWD=$(pwd)
|
|
61
|
-
|
|
59
|
+
POLL="${TEAM_POLL_INTERVAL:-2}"
|
|
60
|
+
MAX_READY="${TEAM_MAX_READY_WAIT:-60}"
|
|
61
|
+
MAX_DONE="${TEAM_MAX_COMPLETION_WAIT:-300}"
|
|
62
|
+
|
|
63
|
+
# ── helpers ──────────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
# Capture visible pane content (last N lines)
|
|
66
|
+
pane_text() { tmux capture-pane -t "$1" -p -S "-${2:-20}" 2>/dev/null || true; }
|
|
67
|
+
|
|
68
|
+
# Wait until the agent CLI is fully ready ('/ commands' status bar visible).
|
|
69
|
+
# Auto-accepts the folder-trust dialog if it appears.
|
|
70
|
+
wait_for_ready() {
|
|
71
|
+
local pane="$1" elapsed=0 accepted=0
|
|
72
|
+
while (( elapsed < MAX_READY )); do
|
|
73
|
+
local txt
|
|
74
|
+
txt=$(pane_text "$pane" 25)
|
|
75
|
+
|
|
76
|
+
# Ready: the '/ commands' status bar means the CLI input prompt is active
|
|
77
|
+
if echo "$txt" | grep -q '/ commands'; then
|
|
78
|
+
return 0
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Auto-accept folder trust dialog
|
|
82
|
+
if (( accepted == 0 )) && echo "$txt" | grep -q 'Do you trust'; then
|
|
83
|
+
tmux send-keys -t "$pane" C-m
|
|
84
|
+
accepted=1
|
|
85
|
+
echo " ↳ Auto-accepted folder trust for $pane"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
sleep "$POLL"
|
|
89
|
+
elapsed=$((elapsed + POLL))
|
|
90
|
+
done
|
|
91
|
+
return 1
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# ── step 1: create panes ─────────────────────────────────────────────
|
|
62
95
|
|
|
63
96
|
echo "🚀 Splitting current window into $LANE_COUNT panes ($SESSION)"
|
|
64
97
|
echo ""
|
|
65
98
|
|
|
66
|
-
# Collect pane IDs as we create them
|
|
67
99
|
PANE_IDS=()
|
|
68
|
-
|
|
69
100
|
for i in $(seq 0 $((LANE_COUNT - 1))); do
|
|
70
101
|
LANE_NAME=$(jq -r ".[$i].name" "$LANES_FILE")
|
|
71
|
-
LANE_PROMPT=$(jq -r ".[$i].prompt" "$LANES_FILE")
|
|
72
102
|
LANE_ID=$(jq -r ".[$i].id" "$LANES_FILE")
|
|
73
103
|
|
|
74
|
-
# Split: alternate horizontal/vertical for a grid
|
|
75
104
|
if (( i == 0 )); then
|
|
76
105
|
PANE_ID=$(tmux split-window -h -c "$CWD" -P -F '#{pane_id}')
|
|
77
106
|
elif (( i % 2 == 1 )); then
|
|
@@ -79,54 +108,123 @@ for i in $(seq 0 $((LANE_COUNT - 1))); do
|
|
|
79
108
|
else
|
|
80
109
|
PANE_ID=$(tmux split-window -v -t "${PANE_IDS[$((i-2))]}" -c "$CWD" -P -F '#{pane_id}')
|
|
81
110
|
fi
|
|
82
|
-
|
|
83
111
|
PANE_IDS+=("$PANE_ID")
|
|
84
112
|
|
|
85
|
-
# Set pane title
|
|
86
113
|
tmux select-pane -t "$PANE_ID" -T "$LANE_ID: $LANE_NAME"
|
|
114
|
+
tmux send-keys -t "$PANE_ID" "$AGENT_CMD" C-m
|
|
87
115
|
|
|
88
|
-
|
|
89
|
-
tmux send-keys -t "$PANE_ID" "echo '═══ $LANE_NAME ═══' && $AGENT_CMD" C-m
|
|
90
|
-
|
|
91
|
-
echo " ✅ Pane $PANE_ID → $LANE_NAME (launching agent...)"
|
|
116
|
+
echo " ✅ Pane $PANE_ID → $LANE_NAME"
|
|
92
117
|
done
|
|
93
118
|
|
|
94
|
-
# Rebalance layout
|
|
95
119
|
tmux select-layout tiled
|
|
96
120
|
|
|
97
|
-
#
|
|
121
|
+
# ── step 2: wait for readiness ───────────────────────────────────────
|
|
122
|
+
|
|
98
123
|
echo ""
|
|
99
|
-
echo "⏳ Waiting
|
|
100
|
-
sleep "$WAIT_SECS"
|
|
124
|
+
echo "⏳ Waiting for agents to initialise (up to ${MAX_READY}s)..."
|
|
101
125
|
|
|
102
|
-
|
|
126
|
+
for i in $(seq 0 $((LANE_COUNT - 1))); do
|
|
127
|
+
PANE_ID="${PANE_IDS[$i]}"
|
|
128
|
+
LANE_NAME=$(jq -r ".[$i].name" "$LANES_FILE")
|
|
129
|
+
if wait_for_ready "$PANE_ID"; then
|
|
130
|
+
echo " ✅ $PANE_ID ($LANE_NAME) ready"
|
|
131
|
+
else
|
|
132
|
+
echo " ⚠️ $PANE_ID ($LANE_NAME) not ready after ${MAX_READY}s — sending anyway"
|
|
133
|
+
fi
|
|
134
|
+
done
|
|
135
|
+
|
|
136
|
+
# ── step 3: send prompts (literal text + Enter separately) ───────────
|
|
137
|
+
|
|
138
|
+
echo ""
|
|
139
|
+
echo "📨 Sending prompts..."
|
|
103
140
|
for i in $(seq 0 $((LANE_COUNT - 1))); do
|
|
104
141
|
LANE_PROMPT=$(jq -r ".[$i].prompt" "$LANES_FILE")
|
|
105
142
|
LANE_NAME=$(jq -r ".[$i].name" "$LANES_FILE")
|
|
106
143
|
PANE_ID="${PANE_IDS[$i]}"
|
|
107
144
|
|
|
108
|
-
#
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
# Send via tmux send-keys -l (literal) then Enter
|
|
113
|
-
tmux send-keys -t "$PANE_ID" -l "$(cat "$PROMPT_FILE")"
|
|
145
|
+
# -l = literal (no key interpretation), then C-m = Enter as a separate call
|
|
146
|
+
tmux send-keys -t "$PANE_ID" -l "$LANE_PROMPT"
|
|
147
|
+
sleep 0.3
|
|
114
148
|
tmux send-keys -t "$PANE_ID" C-m
|
|
115
149
|
|
|
116
|
-
echo " 📨 Sent
|
|
150
|
+
echo " 📨 Sent to $PANE_ID ($LANE_NAME)"
|
|
117
151
|
done
|
|
118
152
|
|
|
119
|
-
# Switch focus back to the original (leader) pane
|
|
120
153
|
tmux select-pane -t '{left}'
|
|
121
154
|
|
|
155
|
+
# ── step 4: monitor completion ───────────────────────────────────────
|
|
156
|
+
|
|
122
157
|
echo ""
|
|
123
|
-
echo "
|
|
158
|
+
echo "⏳ Monitoring agents for completion (up to ${MAX_DONE}s)..."
|
|
159
|
+
|
|
160
|
+
# Brief pause so agents start processing before we poll
|
|
161
|
+
sleep 5
|
|
162
|
+
|
|
163
|
+
# State per lane: 0=waiting-for-busy, 1=busy, 2=done
|
|
164
|
+
LANE_STATE=()
|
|
165
|
+
for i in $(seq 0 $((LANE_COUNT - 1))); do LANE_STATE[$i]=0; done
|
|
166
|
+
|
|
167
|
+
COMPLETED=0
|
|
168
|
+
ELAPSED=0
|
|
169
|
+
while (( COMPLETED < LANE_COUNT && ELAPSED < MAX_DONE )); do
|
|
170
|
+
sleep "$POLL"
|
|
171
|
+
ELAPSED=$((ELAPSED + POLL))
|
|
172
|
+
|
|
173
|
+
for i in $(seq 0 $((LANE_COUNT - 1))); do
|
|
174
|
+
[[ "${LANE_STATE[$i]}" == "2" ]] && continue
|
|
175
|
+
|
|
176
|
+
PANE_ID="${PANE_IDS[$i]}"
|
|
177
|
+
LANE_NAME=$(jq -r ".[$i].name" "$LANES_FILE")
|
|
178
|
+
|
|
179
|
+
# Pane died?
|
|
180
|
+
if ! tmux list-panes -a -F '#{pane_id}' 2>/dev/null | grep -q "^${PANE_ID}$"; then
|
|
181
|
+
echo " ❌ $PANE_ID ($LANE_NAME) — pane died"
|
|
182
|
+
LANE_STATE[$i]=2; COMPLETED=$((COMPLETED + 1)); continue
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
local_capture=$(pane_text "$PANE_ID" 15)
|
|
186
|
+
|
|
187
|
+
# State 0→1: agent started working (response marker ● appears)
|
|
188
|
+
if [[ "${LANE_STATE[$i]}" == "0" ]]; then
|
|
189
|
+
if echo "$local_capture" | grep -q '●'; then
|
|
190
|
+
LANE_STATE[$i]=1
|
|
191
|
+
fi
|
|
192
|
+
continue
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
# State 1→2: agent finished (back to idle — '/ commands' in last 5 lines)
|
|
196
|
+
if echo "$local_capture" | tail -5 | grep -q '/ commands'; then
|
|
197
|
+
echo " ✅ $PANE_ID ($LANE_NAME) — agent finished"
|
|
198
|
+
LANE_STATE[$i]=2; COMPLETED=$((COMPLETED + 1))
|
|
199
|
+
fi
|
|
200
|
+
done
|
|
201
|
+
done
|
|
202
|
+
|
|
124
203
|
echo ""
|
|
125
|
-
|
|
204
|
+
if (( COMPLETED == LANE_COUNT )); then
|
|
205
|
+
echo "🎉 All $LANE_COUNT agents completed!"
|
|
206
|
+
else
|
|
207
|
+
echo "⏰ Timeout — $((LANE_COUNT - COMPLETED)) agent(s) still running"
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
# ── summary ──────────────────────────────────────────────────────────
|
|
211
|
+
|
|
126
212
|
echo ""
|
|
127
|
-
echo "
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
213
|
+
echo "═══ Results Summary ═══"
|
|
214
|
+
for i in $(seq 0 $((LANE_COUNT - 1))); do
|
|
215
|
+
PANE_ID="${PANE_IDS[$i]}"
|
|
216
|
+
LANE_NAME=$(jq -r ".[$i].name" "$LANES_FILE")
|
|
217
|
+
LANE_ID=$(jq -r ".[$i].id" "$LANES_FILE")
|
|
218
|
+
echo ""
|
|
219
|
+
echo "── $LANE_ID: $LANE_NAME ($PANE_ID) ──"
|
|
220
|
+
if tmux list-panes -a -F '#{pane_id}' 2>/dev/null | grep -q "^${PANE_ID}$"; then
|
|
221
|
+
pane_text "$PANE_ID" 40 | grep -E '●|✅|❌|⚠|error|Error|FAIL|PASS|done|Done' | tail -10 || echo " (no notable output captured)"
|
|
222
|
+
else
|
|
223
|
+
echo " (pane no longer exists)"
|
|
224
|
+
fi
|
|
225
|
+
done
|
|
226
|
+
|
|
131
227
|
echo ""
|
|
132
|
-
echo "
|
|
228
|
+
echo "Pane IDs: ${PANE_IDS[*]}"
|
|
229
|
+
echo "Navigate: Ctrl-b + arrow keys"
|
|
230
|
+
echo "💡 Agents are interactive — send follow-up prompts to any pane"
|
package/README.md
CHANGED
|
@@ -82,6 +82,7 @@ That's it.
|
|
|
82
82
|
### Developer Experience
|
|
83
83
|
|
|
84
84
|
- **MCP server** ships with `notepad`, `project-memory`, `shared-memory`, `state`, and `trace` tools out of the box
|
|
85
|
+
- **Lightweight Copilot context** — managed instructions keep only the repo goal plus on-demand memory commands; set `OMP_DISABLE_INSTRUCTIONS_MEMORY=1` to skip writing the managed block entirely
|
|
85
86
|
- **File-state coordination** — outbox JSONL + byte cursor, atomic `O_EXCL` task locks, optimistic CAS on claim
|
|
86
87
|
- **Idle nudge** — content-based pane idle detection that pokes stuck workers
|
|
87
88
|
- **Mode-state loops** — single source of truth per loop (Ralph/Ultrawork/UltraQA state files)
|
|
@@ -183,6 +184,7 @@ omp list # show discovered skills and agents
|
|
|
183
184
|
omp setup [--dry-run] [--scope project|user]
|
|
184
185
|
omp launch -- [copilot flags…] # forward arbitrary args to copilot
|
|
185
186
|
omp --madmax -p "edit src/foo.ts" # bare-flag, maps to copilot --yolo
|
|
187
|
+
omp suggest "fix flaky tests" # recommend a slash-skill workflow
|
|
186
188
|
omp team 3:executor "fix all type errors" # spawn tmux workers
|
|
187
189
|
omp team status <name>
|
|
188
190
|
omp team shutdown <name>
|
|
@@ -190,6 +192,12 @@ omp ralph start "<task>" [--max-iterations N]
|
|
|
190
192
|
omp ultrawork start "<objective>" [--task-count N]
|
|
191
193
|
omp ultraqa start "<goal>" [--max-cycles N]
|
|
192
194
|
omp council "<question>" [--models a,b,c] [--context @file] [--json] # multi-model council
|
|
195
|
+
omp comms status | send | recv | ask # drive a running copilot tmux session
|
|
196
|
+
omp gateway serve [--only slack] # run chat connectors (today: slack)
|
|
197
|
+
omp gateway status [--json] # per-connector readiness (no sockets)
|
|
198
|
+
omp slack serve # deprecated alias of `gateway serve --only slack`
|
|
199
|
+
omp slack doctor [--json] # deprecated alias of `gateway status --only slack`
|
|
200
|
+
omp env init [--force] # write ~/.omp/.env (interactive Slack token setup)
|
|
193
201
|
omp schedule add --id <id> --cron "*/15 * * * *" --prompt "<text>" [--allow-all-tools] [--cwd <dir>] [--model <m>] [--timeout <ms>] [--max-runs N] [--ttl-hours H] [--dry-run]
|
|
194
202
|
omp schedule list # registered jobs + OS-install status
|
|
195
203
|
omp schedule status <id> # last run + result summary
|
|
@@ -217,6 +225,29 @@ run results are surfaced automatically at the start of new Copilot sessions. Alw
|
|
|
217
225
|
`omp schedule remove`, never delete `.omp/state/schedule/` by hand, so the OS entry is
|
|
218
226
|
uninstalled cleanly.
|
|
219
227
|
|
|
228
|
+
### Chat bridge: drive Copilot from Slack
|
|
229
|
+
|
|
230
|
+
`omp gateway` runs long-lived chat connectors that forward messages into a running
|
|
231
|
+
Copilot CLI session (via tmux) and post replies back. Today's connector is `slack`
|
|
232
|
+
(WebSocket Socket Mode — no public URL needed); the runtime is generic so future
|
|
233
|
+
connectors (Telegram, Discord, webhooks) drop in as one file each.
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# 1. a Copilot tmux session is running (any `omp-<digits>` name)
|
|
237
|
+
tmux new-session -d -s omp-9999
|
|
238
|
+
|
|
239
|
+
# 2. interactive setup — explains where to grab each token and writes
|
|
240
|
+
# ~/.omp/.env (chmod 600). Re-runnable; masks existing values.
|
|
241
|
+
# `omp` auto-loads ~/.omp/.env every invocation; shell exports still win.
|
|
242
|
+
omp env init
|
|
243
|
+
|
|
244
|
+
# 3. preflight, then run
|
|
245
|
+
omp gateway status # ready=true means tokens + session look good
|
|
246
|
+
omp gateway serve # blocks; ^C stops cleanly
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Full Slack-app setup (manifest + scopes) lives in [`docs/slack-setup.md`](docs/slack-setup.md).
|
|
250
|
+
|
|
220
251
|
---
|
|
221
252
|
|
|
222
253
|
## Roadmap
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
"source": ".github/skills/team/SKILL.md",
|
|
92
92
|
"sourcePath": ".github/skills/team/SKILL.md",
|
|
93
93
|
"canonicalPath": ".github/skills/team/SKILL.md",
|
|
94
|
-
"description": "Split approved plans into
|
|
95
|
-
"summary": "Split approved plans into
|
|
94
|
+
"description": "Split approved plans into visible tmux lanes in the current window by default.",
|
|
95
|
+
"summary": "Split approved plans into visible tmux lanes by default.",
|
|
96
96
|
"support": "project-skill",
|
|
97
97
|
"aliases": [],
|
|
98
98
|
"slashCommands": [
|
package/dist/src/cli.d.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
ok: boolean;
|
|
4
|
-
exitCode?: number;
|
|
5
|
-
output?: unknown;
|
|
6
|
-
message?: string;
|
|
7
|
-
}
|
|
2
|
+
import type { CliResult } from "./commands/types.js";
|
|
8
3
|
export declare function runCli(argv?: string[]): Promise<CliResult>;
|
|
9
4
|
/** Parse a --models value: comma-separated `model` or `model:role:weight` tokens. */
|
|
10
5
|
export declare function parseModelsFlag(value: string): {
|
|
@@ -14,4 +9,3 @@ export declare function parseModelsFlag(value: string): {
|
|
|
14
9
|
}[];
|
|
15
10
|
/** Parse a numeric flag as a finite positive integer; throw on malformed input. */
|
|
16
11
|
export declare function parsePositiveIntFlag(value: string | undefined, flag: string): number | undefined;
|
|
17
|
-
export {};
|