cli-fleet 0.1.0__py3-none-any.whl
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.
- cli_fleet/__init__.py +9 -0
- cli_fleet/cli.py +132 -0
- cli_fleet/scripts/agents/brain-neuron.md +85 -0
- cli_fleet/scripts/agents/brain-pacemaker.md +92 -0
- cli_fleet/scripts/agents/hunter.md +27 -0
- cli_fleet/scripts/agents/researcher.md +18 -0
- cli_fleet/scripts/agents/reviewer.md +21 -0
- cli_fleet/scripts/captain.sh +160 -0
- cli_fleet/scripts/cleanup.sh +72 -0
- cli_fleet/scripts/examples/hunt-layerzero-brainstream.json +34 -0
- cli_fleet/scripts/examples/hunt-layerzero.json +30 -0
- cli_fleet/scripts/examples/openwindows-milestone2.json +34 -0
- cli_fleet/scripts/hooks/check-mailbox.sh +64 -0
- cli_fleet/scripts/hooks/consciousness-bridge.sh +64 -0
- cli_fleet/scripts/hooks/stream-stall-check.sh +27 -0
- cli_fleet/scripts/hooks/task-completed.sh +26 -0
- cli_fleet/scripts/hooks/teammate-idle.sh +49 -0
- cli_fleet/scripts/launch.sh +441 -0
- cli_fleet/scripts/lib/protocol.sh +250 -0
- cli_fleet/scripts/send.sh +24 -0
- cli_fleet/scripts/setup.sh +254 -0
- cli_fleet/scripts/status.sh +42 -0
- cli_fleet/scripts/templates/brain-stream-lead.md +76 -0
- cli_fleet/scripts/templates/team-lead.md +60 -0
- cli_fleet-0.1.0.dist-info/METADATA +67 -0
- cli_fleet-0.1.0.dist-info/RECORD +29 -0
- cli_fleet-0.1.0.dist-info/WHEEL +4 -0
- cli_fleet-0.1.0.dist-info/entry_points.txt +2 -0
- cli_fleet-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta_team": "hunt-lz",
|
|
3
|
+
"project_dir": "/media/phantom-orchestrator/Elements1/Ubuntu/bounty-recon",
|
|
4
|
+
"teams": [
|
|
5
|
+
{
|
|
6
|
+
"name": "team-evm-v1",
|
|
7
|
+
"role": "Hunt V1 EVM contracts — UltraLightNodeV2, Endpoint V1, FPValidator ($15M cap each)",
|
|
8
|
+
"teammates": 3,
|
|
9
|
+
"task": "Create an agent team with 3 teammates to hunt Critical bugs in LayerZero V1 EVM contracts. These are the highest-value targets ($15M cap). Contracts: UltraLightNodeV2 (0x4D73AdB72bC3DD368966edD0f0b2148401A178E2, $412.5M TVL), Endpoint V1 (0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675), FPValidator (0x07245eEa05826F5984c7c3C8F478b04892e4df89). Source: /home/phantom-orchestrator/Documents/Bug Bounty/layerzero/LayerZero/contracts/. Run: /home/phantom-orchestrator/bin/hunt-auto evm on each contract. Chase every finding. Focus on fund theft, permanent DoS, nonce manipulation. Post all findings to cross-team mailbox immediately."
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"name": "team-evm-v2",
|
|
13
|
+
"role": "Hunt V2 EVM protocol contracts — EndpointV2, SendULN302, ReceiveULN302, DVN ($2M cap)",
|
|
14
|
+
"teammates": 3,
|
|
15
|
+
"task": "Create an agent team with 3 teammates to hunt Critical/High bugs in LayerZero V2 EVM contracts. Contracts: EndpointV2 (0x1a44076050125825900e736c501f859c50fE728c), SendULN302 (0xBb2ea70C9E858123480642Cf96acbcCE1372dce1), ReceiveULN302 (0xc02Ab410f0734EFa3F14628780e6e695156024C2), DVN (0x589dEDbD617e0CBcB916A9223F4d1300c294236b), SendULN301 (0xD231084BfB234C107D3eE2b22F97F3346fDAF705), ReceiveULN301 (0x245B6e8FFe9ea5Fc301e32d16F66bD4C2123EeFc). Source: /home/phantom-orchestrator/Documents/Bug Bounty/layerzero/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/. Run: /home/phantom-orchestrator/bin/hunt-auto evm. Focus on DVN verification bypass, payload hash manipulation, fee accounting bugs."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "team-crosschain",
|
|
19
|
+
"role": "Hunt cross-chain exploit chains — encoding mismatches, nonce desync, composed msg attacks ($2M-$15M)",
|
|
20
|
+
"teammates": 4,
|
|
21
|
+
"task": "Create an agent team with 4 teammates to hunt cross-chain exploit chains in LayerZero. This is the highest-value unexplored surface. NO single-chain bugs — ONLY cross-chain vectors. One teammate per attack surface: (1) Address encoding mismatches: EVM 20-byte vs Solana 32-byte vs TON 267-bit — test padding/truncation in bytes32 conversion. Wrong recipient = fund loss = Critical. (2) Nonce desync: V2 lazy inbound nonce + out-of-order delivery. Can you brick a channel by delivering messages out of order across chain pairs? (3) Executor gas: EVM gas vs Solana compute units vs TON gas. Force underpayment causing partial lzReceive execution. (4) Composed messages: lzCompose A→B→C chaining. Circular compose, manipulated composed data, orphaned state. Use tools: /home/phantom-orchestrator/bin/t xchain-abi-check, xchain-fuzz, xchain-tracer. All tests MUST use multi-fork harness (srcFork + dstFork)."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "team-non-evm",
|
|
25
|
+
"role": "Hunt Solana + TON + Aptos contracts ($2M cap)",
|
|
26
|
+
"teammates": 3,
|
|
27
|
+
"task": "Create an agent team with 3 teammates, one per chain. Solana teammate: hunt DVN (4VDjp6XQ), EndpointV2 (76y77prs), SendULN302 (6doghB24), ReceiveULN302 (7a4WjyR8), OFT. Source: /home/phantom-orchestrator/Documents/Bug Bounty/layerzero/LayerZero-v2/packages/layerzero-v2/solana/. Run: /home/phantom-orchestrator/bin/hunt-auto solana. TON teammate: hunt Controller (0:1eb2bb), ULNManager (0:150645), DVNProxy (0:0d122d). Source: .../ton/. Run: /home/phantom-orchestrator/bin/hunt-auto ton. Aptos teammate: hunt Endpoint (0x54ad3d). Source: .../aptos/. Run: /home/phantom-orchestrator/bin/hunt-auto aptos. All: focus on chain-specific bugs that EVM tools miss. Share findings cross-team especially with team-crosschain."
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta_team": "ow-m2",
|
|
3
|
+
"project_dir": "/mnt/win-img/openwindows",
|
|
4
|
+
"teams": [
|
|
5
|
+
{
|
|
6
|
+
"name": "brain-ntdll",
|
|
7
|
+
"role": "Deep analysis and reimplementation of ntdll functions that real apps need",
|
|
8
|
+
"mode": "brain-stream",
|
|
9
|
+
"teammates": 3,
|
|
10
|
+
"task": "Investigate ntdll.dll functions that PowerShell and real Windows apps import. We have 23 of 2,455 exports implemented. The r2 analysis data is at /mnt/win-img/categorized/deep-analysis/tier-0/ntdll.dll-deep.json. The current implementation is at /mnt/win-img/openwindows/src/ntdll/ntdll.c. Focus on: RtlAllocateHeap, RtlFreeHeap (real heap, not stubs), NtCreateFile/NtOpenFile (already stubbed but need real implementation), RtlInitUnicodeString family, exception handling (RtlVirtualUnwind, RtlCaptureContext — these are called by 32 DLLs). The OpenWindows project runs unmodified Windows binaries on Linux by reimplementing the Win32 API. Start neurons on the highest-import-count functions."
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "brain-advapi32",
|
|
14
|
+
"role": "Design and implement advapi32.dll — security, registry, service APIs",
|
|
15
|
+
"mode": "brain-stream",
|
|
16
|
+
"teammates": 3,
|
|
17
|
+
"task": "Investigate advapi32.dll for reimplementation. It has 870 exports and is imported by 1,775 binaries. The r2 analysis is at /mnt/win-img/categorized/deep-analysis/tier-1/advapi32.dll-deep.json. PowerShell needs advapi32 for: RegOpenKeyExW/RegQueryValueExW (registry — we have basic stubs in kernelbase/registry.c), security token functions (OpenProcessToken, GetTokenInformation), service control (OpenSCManager, StartService — can stub for now), crypto basics (CryptAcquireContext). The existing registry implementation is at /mnt/win-img/openwindows/src/kernelbase/registry.c. advapi32 on real Windows mostly forwards to kernelbase, so many functions can be thin wrappers. Start neurons on what PowerShell actually imports from advapi32."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "brain-loader",
|
|
21
|
+
"role": "Improve the PE loader — LoadLibrary, DLL dependencies, thread creation",
|
|
22
|
+
"mode": "brain-stream",
|
|
23
|
+
"teammates": 3,
|
|
24
|
+
"task": "Investigate what the OpenWindows PE loader needs to run PowerShell and real apps. Current loader at /mnt/win-img/openwindows/src/loader/pe_loader.c can load a single .exe and resolve imports against built-in DLLs. It CANNOT: dynamically load DLLs via LoadLibrary (returns NULL), load dependent DLLs that the .exe imports (only resolves against built-in reimplementations), create threads (CreateThread is stubbed). PowerShell.exe imports from ~30 DLLs. Many of these are api-ms-win-* shims that forward to kernelbase (we handle this). But some are real DLLs we'd need to load from the extracted Windows image: clrjit.dll, mscorlib.dll (.NET), or we need to provide our own. Start neurons on: what does LoadLibraryExW need to do, what DLLs does PowerShell actually need, can we load real Windows DLLs from the extracted image and resolve their imports too."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "team-fixes",
|
|
28
|
+
"role": "Fix remaining code review issues and build test infrastructure",
|
|
29
|
+
"mode": "standard",
|
|
30
|
+
"teammates": 3,
|
|
31
|
+
"task": "Fix the remaining issues from the adversarial code review. Issues to fix: (1) _onexit/_initterm callbacks call Win64 function pointers with SysV ABI — need reverse-thunk wrappers in msvcrt.c. (2) ow_signal passes Win64 handler to Linux signal() — make it a no-op stub returning SIG_DFL. (3) Format parser in narrow_format_args() missing %f/%e/%g/%o specifiers and default case doesn't consume args — add float handling and fix arg consumption. (4) thunks.S WIN2LINUX macro can't forward 5+ args — migrate remaining thunks.S functions to use generate_thunk() from thunk_gen.c. (5) Remove startup printf noise from msvcrt registration. All code is at /mnt/win-img/openwindows/. Run bash tests/test_cmd.sh after every fix to verify no regressions."
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hook: check-mailbox.sh
|
|
3
|
+
# Type: UserPromptSubmit — injects cross-team messages as additional context
|
|
4
|
+
# Install: add to settings.json hooks.UserPromptSubmit
|
|
5
|
+
#
|
|
6
|
+
# Env vars expected:
|
|
7
|
+
# META_TEAM_NAME — name of the meta-team (e.g., "hunt-lz")
|
|
8
|
+
# TEAM_NAME — this team's name (e.g., "team-evm-v1")
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
META_DIR="${META_TEAM_DIR:-$HOME/.claude/meta-teams}"
|
|
13
|
+
META_TEAM="${META_TEAM_NAME:-}"
|
|
14
|
+
TEAM="${TEAM_NAME:-}"
|
|
15
|
+
|
|
16
|
+
# Skip if not in a multi-team context
|
|
17
|
+
[[ -z "$META_TEAM" || -z "$TEAM" ]] && exit 0
|
|
18
|
+
|
|
19
|
+
DIR="$META_DIR/$META_TEAM"
|
|
20
|
+
[[ ! -d "$DIR/mailbox" ]] && exit 0
|
|
21
|
+
|
|
22
|
+
CURSOR_FILE="$DIR/status/${TEAM}.cursor"
|
|
23
|
+
LAST_READ="0"
|
|
24
|
+
[[ -f "$CURSOR_FILE" ]] && LAST_READ=$(cat "$CURSOR_FILE")
|
|
25
|
+
|
|
26
|
+
NEW_MESSAGES=""
|
|
27
|
+
LATEST_TS="$LAST_READ"
|
|
28
|
+
|
|
29
|
+
for msg_file in "$DIR/mailbox/"*.json; do
|
|
30
|
+
[[ ! -f "$msg_file" ]] && continue
|
|
31
|
+
|
|
32
|
+
basename=$(basename "$msg_file")
|
|
33
|
+
msg_ts="${basename%%-*}"
|
|
34
|
+
|
|
35
|
+
# Skip already-read
|
|
36
|
+
(( msg_ts <= LAST_READ )) && continue
|
|
37
|
+
|
|
38
|
+
# Check if message is for us or broadcast
|
|
39
|
+
to=$(python3 -c "import json; print(json.load(open('$msg_file'))['to'])" 2>/dev/null || echo "")
|
|
40
|
+
if [[ "$to" == "$TEAM" || "$to" == "all" ]]; then
|
|
41
|
+
from=$(python3 -c "import json; print(json.load(open('$msg_file'))['from'])" 2>/dev/null || echo "unknown")
|
|
42
|
+
msg_type=$(python3 -c "import json; print(json.load(open('$msg_file'))['type'])" 2>/dev/null || echo "message")
|
|
43
|
+
content=$(python3 -c "import json; print(json.load(open('$msg_file'))['content'])" 2>/dev/null || echo "")
|
|
44
|
+
|
|
45
|
+
NEW_MESSAGES+="[CROSS-TEAM ${msg_type^^}] From ${from}: ${content}"$'\n'
|
|
46
|
+
|
|
47
|
+
(( msg_ts > LATEST_TS )) && LATEST_TS="$msg_ts"
|
|
48
|
+
fi
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
# Update cursor
|
|
52
|
+
if (( LATEST_TS > LAST_READ )); then
|
|
53
|
+
mkdir -p "$DIR/status"
|
|
54
|
+
echo "$LATEST_TS" > "$CURSOR_FILE"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# Output new messages as hook context (shows up in Claude's context)
|
|
58
|
+
if [[ -n "$NEW_MESSAGES" ]]; then
|
|
59
|
+
echo "## Cross-Team Mailbox (${META_TEAM})"
|
|
60
|
+
echo ""
|
|
61
|
+
echo "$NEW_MESSAGES"
|
|
62
|
+
echo ""
|
|
63
|
+
echo "Reply to any team with: source multi-team/lib/protocol.sh && meta_send \"$META_TEAM\" \"$TEAM\" \"<target>\" \"<type>\" \"<content>\""
|
|
64
|
+
fi
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hook: consciousness-bridge.sh
|
|
3
|
+
# Type: UserPromptSubmit — bridges consciousness file signals to FleetCode mailbox
|
|
4
|
+
# AND bridges FleetCode mailbox messages into the consciousness stream
|
|
5
|
+
#
|
|
6
|
+
# Two-way bridge:
|
|
7
|
+
# consciousness → mailbox (when neurons find critical stuff)
|
|
8
|
+
# mailbox → consciousness (when other brains send intel)
|
|
9
|
+
|
|
10
|
+
set -uo pipefail
|
|
11
|
+
|
|
12
|
+
META_DIR="${META_TEAM_DIR:-$HOME/.claude/meta-teams}"
|
|
13
|
+
META_TEAM="${META_TEAM_NAME:-}"
|
|
14
|
+
TEAM="${TEAM_NAME:-}"
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
16
|
+
|
|
17
|
+
[[ -z "$META_TEAM" || -z "$TEAM" ]] && exit 0
|
|
18
|
+
|
|
19
|
+
DIR="$META_DIR/$META_TEAM"
|
|
20
|
+
[[ ! -d "$DIR" ]] && exit 0
|
|
21
|
+
|
|
22
|
+
# Find this team's consciousness file
|
|
23
|
+
CONSCIOUSNESS="$DIR/workdirs/$TEAM/consciousness.md"
|
|
24
|
+
[[ ! -f "$CONSCIOUSNESS" ]] && CONSCIOUSNESS="/tmp/brain-stream/$TEAM/consciousness.md"
|
|
25
|
+
[[ ! -f "$CONSCIOUSNESS" ]] && exit 0
|
|
26
|
+
|
|
27
|
+
# === INBOUND: FleetCode mailbox → consciousness stream ===
|
|
28
|
+
# Read unread cross-team messages and inject them as stimuli
|
|
29
|
+
CURSOR_FILE="$DIR/status/${TEAM}-brain.cursor"
|
|
30
|
+
LAST_READ="0"
|
|
31
|
+
[[ -f "$CURSOR_FILE" ]] && LAST_READ=$(cat "$CURSOR_FILE")
|
|
32
|
+
|
|
33
|
+
LATEST_TS="$LAST_READ"
|
|
34
|
+
for msg_file in "$DIR/mailbox/"*.json; do
|
|
35
|
+
[[ ! -f "$msg_file" ]] && continue
|
|
36
|
+
basename=$(basename "$msg_file")
|
|
37
|
+
msg_ts="${basename%%-*}"
|
|
38
|
+
(( msg_ts <= LAST_READ )) && continue
|
|
39
|
+
|
|
40
|
+
to=$(python3 -c "import json; print(json.load(open('$msg_file'))['to'])" 2>/dev/null || echo "")
|
|
41
|
+
if [[ "$to" == "$TEAM" || "$to" == "all" ]]; then
|
|
42
|
+
from=$(python3 -c "import json; print(json.load(open('$msg_file'))['from'])" 2>/dev/null || echo "unknown")
|
|
43
|
+
content=$(python3 -c "import json; print(json.load(open('$msg_file'))['content'])" 2>/dev/null || echo "")
|
|
44
|
+
msg_type=$(python3 -c "import json; print(json.load(open('$msg_file'))['type'])" 2>/dev/null || echo "message")
|
|
45
|
+
|
|
46
|
+
# Skip our own messages
|
|
47
|
+
[[ "$from" == "$TEAM" ]] && continue
|
|
48
|
+
|
|
49
|
+
# Inject into consciousness stream
|
|
50
|
+
echo "[$(date +%H:%M:%S)] CROSS-BRAIN($from): $content" >> "$CONSCIOUSNESS"
|
|
51
|
+
|
|
52
|
+
(( msg_ts > LATEST_TS )) && LATEST_TS="$msg_ts"
|
|
53
|
+
fi
|
|
54
|
+
done
|
|
55
|
+
|
|
56
|
+
if (( LATEST_TS > LAST_READ )); then
|
|
57
|
+
mkdir -p "$DIR/status"
|
|
58
|
+
echo "$LATEST_TS" > "$CURSOR_FILE"
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# === OUTBOUND: Also run the standard mailbox check ===
|
|
62
|
+
# (The regular check-mailbox.sh handles injecting into Claude's context)
|
|
63
|
+
|
|
64
|
+
exit 0
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hook: stream-stall-check.sh
|
|
3
|
+
# Type: TeammateIdle — detects stalled brain streams
|
|
4
|
+
# Exit code 2 = keep teammate working (stream stalled, needs stimulus)
|
|
5
|
+
# Exit code 0 = allow idle
|
|
6
|
+
|
|
7
|
+
set -uo pipefail
|
|
8
|
+
|
|
9
|
+
CF="${CONSCIOUSNESS_FILE:-}"
|
|
10
|
+
[[ -z "$CF" || ! -f "$CF" ]] && exit 0
|
|
11
|
+
|
|
12
|
+
LAST_LINE=$(tail -1 "$CF" 2>/dev/null)
|
|
13
|
+
[[ -z "$LAST_LINE" ]] && exit 0
|
|
14
|
+
|
|
15
|
+
LAST_TIME=$(echo "$LAST_LINE" | grep -oP '\[\K[0-9:]+' 2>/dev/null || echo "")
|
|
16
|
+
[[ -z "$LAST_TIME" ]] && exit 0
|
|
17
|
+
|
|
18
|
+
NOW=$(date +%s)
|
|
19
|
+
LAST_EPOCH=$(date -d "$LAST_TIME" +%s 2>/dev/null || echo 0)
|
|
20
|
+
DIFF=$((NOW - LAST_EPOCH))
|
|
21
|
+
|
|
22
|
+
if [[ $DIFF -gt 120 ]]; then
|
|
23
|
+
echo "Stream stalled for ${DIFF}s. Read $CF and inject a specific stimulus about an unexplored angle." >&2
|
|
24
|
+
exit 2
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
exit 0
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hook: TaskCompleted — quality gate before marking tasks done
|
|
3
|
+
# Exit code 2 = reject completion with feedback
|
|
4
|
+
# Exit code 0 = allow completion
|
|
5
|
+
|
|
6
|
+
set -uo pipefail
|
|
7
|
+
|
|
8
|
+
META_DIR="${META_TEAM_DIR:-$HOME/.claude/meta-teams}"
|
|
9
|
+
META_TEAM="${META_TEAM_NAME:-}"
|
|
10
|
+
TEAM="${TEAM_NAME:-}"
|
|
11
|
+
|
|
12
|
+
# Skip if not in multi-team context
|
|
13
|
+
[[ -z "$META_TEAM" || -z "$TEAM" ]] && exit 0
|
|
14
|
+
|
|
15
|
+
# Notify captain that a task was completed
|
|
16
|
+
DIR="$META_DIR/$META_TEAM"
|
|
17
|
+
[[ ! -d "$DIR" ]] && exit 0
|
|
18
|
+
|
|
19
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
20
|
+
source "$SCRIPT_DIR/lib/protocol.sh" 2>/dev/null || exit 0
|
|
21
|
+
|
|
22
|
+
# Post status update so captain sees task completion in real-time
|
|
23
|
+
meta_send "$META_TEAM" "$TEAM" "captain" "status" "Task completed by $TEAM" 2>/dev/null || true
|
|
24
|
+
|
|
25
|
+
# Allow completion
|
|
26
|
+
exit 0
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hook: TeammateIdle — prevents teammates from quitting early
|
|
3
|
+
# Exit code 2 = send feedback and keep teammate working
|
|
4
|
+
# Exit code 0 = allow idle (teammate is done)
|
|
5
|
+
#
|
|
6
|
+
# Checks: did the teammate post findings? Did they run enough tools?
|
|
7
|
+
# If not, exit 2 to push them back to work.
|
|
8
|
+
|
|
9
|
+
set -uo pipefail
|
|
10
|
+
|
|
11
|
+
META_DIR="${META_TEAM_DIR:-$HOME/.claude/meta-teams}"
|
|
12
|
+
META_TEAM="${META_TEAM_NAME:-}"
|
|
13
|
+
TEAM="${TEAM_NAME:-}"
|
|
14
|
+
|
|
15
|
+
# Skip if not in multi-team context
|
|
16
|
+
[[ -z "$META_TEAM" || -z "$TEAM" ]] && exit 0
|
|
17
|
+
|
|
18
|
+
DIR="$META_DIR/$META_TEAM"
|
|
19
|
+
[[ ! -d "$DIR" ]] && exit 0
|
|
20
|
+
|
|
21
|
+
# Check if this team has posted any findings
|
|
22
|
+
FINDING_COUNT=$(ls "$DIR/findings/${TEAM}-"*.json 2>/dev/null | wc -l)
|
|
23
|
+
|
|
24
|
+
# Check unread messages (teammate might have new directives)
|
|
25
|
+
CURSOR_FILE="$DIR/status/${TEAM}.cursor"
|
|
26
|
+
LAST_READ="0"
|
|
27
|
+
[[ -f "$CURSOR_FILE" ]] && LAST_READ=$(cat "$CURSOR_FILE")
|
|
28
|
+
|
|
29
|
+
UNREAD=0
|
|
30
|
+
for msg_file in "$DIR/mailbox/"*.json; do
|
|
31
|
+
[[ ! -f "$msg_file" ]] && continue
|
|
32
|
+
basename=$(basename "$msg_file")
|
|
33
|
+
msg_ts="${basename%%-*}"
|
|
34
|
+
(( msg_ts <= LAST_READ )) && continue
|
|
35
|
+
to=$(python3 -c "import json; print(json.load(open('$msg_file'))['to'])" 2>/dev/null || echo "")
|
|
36
|
+
if [[ "$to" == "$TEAM" || "$to" == "all" ]]; then
|
|
37
|
+
((UNREAD++))
|
|
38
|
+
fi
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
# If there are unread messages, keep working
|
|
42
|
+
if [[ $UNREAD -gt 0 ]]; then
|
|
43
|
+
echo "You have $UNREAD unread cross-team messages. Check your mailbox before going idle."
|
|
44
|
+
echo "Run: source $(dirname "$0")/../lib/protocol.sh && meta_read_messages \"$META_TEAM\" \"$TEAM\""
|
|
45
|
+
exit 2
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Allow idle — teammate has handled everything
|
|
49
|
+
exit 0
|