switchman-dev 0.1.3 → 0.1.5

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.
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env bash
2
+ # examples/demo.sh
3
+ #
4
+ # Short, recordable Switchman demo for terminal capture.
5
+ # Run AFTER setup.sh:
6
+ # bash examples/demo.sh
7
+
8
+ set -euo pipefail
9
+
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
12
+ TASKAPI_DIR="$SCRIPT_DIR/taskapi"
13
+ WT_RATE="$SCRIPT_DIR/worktrees/agent-rate-limiting"
14
+ WT_VALID="$SCRIPT_DIR/worktrees/agent-validation"
15
+
16
+ if [ -f "$REPO_ROOT/src/cli/index.js" ]; then
17
+ SWITCHMAN=(node "$REPO_ROOT/src/cli/index.js")
18
+ else
19
+ SWITCHMAN=(switchman)
20
+ fi
21
+
22
+ CYAN='\033[0;36m'
23
+ GREEN='\033[0;32m'
24
+ YELLOW='\033[1;33m'
25
+ BOLD='\033[1m'
26
+ RESET='\033[0m'
27
+
28
+ step() { echo ""; echo -e "${BOLD}── $1 ──────────────────────────────────────${RESET}"; }
29
+ info() { echo -e "${YELLOW}→${RESET} $1"; }
30
+ ok() { echo -e "${GREEN}✓${RESET} $1"; }
31
+
32
+ json_field() {
33
+ local payload="$1"
34
+ local expression="$2"
35
+ node -e "const data = JSON.parse(process.argv[1]); console.log(${expression});" "$payload"
36
+ }
37
+
38
+ ensure_setup() {
39
+ if [ ! -d "$TASKAPI_DIR/.switchman" ]; then
40
+ echo "Switchman example is not set up yet."
41
+ echo "Run: bash examples/setup.sh"
42
+ exit 1
43
+ fi
44
+ }
45
+
46
+ append_demo_change() {
47
+ local file_path="$1"
48
+ local message="$2"
49
+ printf "\n// %s\n" "$message" >> "$file_path"
50
+ }
51
+
52
+ git_commit_files() {
53
+ local repo_dir="$1"
54
+ local message="$2"
55
+ shift 2
56
+ if [ "$#" -gt 0 ]; then
57
+ git -C "$repo_dir" add "$@"
58
+ git -C "$repo_dir" commit -m "$message" -q
59
+ fi
60
+ }
61
+
62
+ ensure_setup
63
+ cd "$TASKAPI_DIR"
64
+
65
+ MAIN_BRANCH="$(git branch --show-current)"
66
+
67
+ echo ""
68
+ echo -e "${BOLD}━━━ Switchman Demo ━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
69
+ echo ""
70
+ echo "This is the short version: two agents, one blocked overlap, safe landing, clean gate."
71
+
72
+ step "1. Repo dashboard"
73
+ "${SWITCHMAN[@]}" status
74
+
75
+ step "2. Agent 1 starts work and locks files"
76
+ TASK1="$("${SWITCHMAN[@]}" lease next --json --worktree agent-rate-limiting --agent cursor)"
77
+ TASK1_ID="$(json_field "$TASK1" "data.task.id")"
78
+ "${SWITCHMAN[@]}" claim "$TASK1_ID" agent-rate-limiting src/middleware/auth.js src/server.js
79
+ append_demo_change "$WT_RATE/src/middleware/auth.js" "demo: rate-limiting agent touched auth middleware"
80
+ append_demo_change "$WT_RATE/src/server.js" "demo: rate-limiting agent touched server"
81
+ git_commit_files "$WT_RATE" "Demo: rate-limiting change" src/middleware/auth.js src/server.js
82
+ ok "Agent 1 has its own files and a committed branch"
83
+
84
+ step "3. Agent 2 tries to overlap and gets blocked"
85
+ TASK2="$("${SWITCHMAN[@]}" lease next --json --worktree agent-validation --agent cursor)"
86
+ TASK2_ID="$(json_field "$TASK2" "data.task.id")"
87
+ "${SWITCHMAN[@]}" claim "$TASK2_ID" agent-validation src/middleware/auth.js src/middleware/validate.js src/routes/tasks.js || true
88
+ info "Switchman blocks the overlapping claim before merge-time pain."
89
+
90
+ step "4. Agent 2 switches to safe files"
91
+ "${SWITCHMAN[@]}" claim "$TASK2_ID" agent-validation src/middleware/validate.js src/routes/tasks.js
92
+ append_demo_change "$WT_VALID/src/middleware/validate.js" "demo: validation agent touched validation middleware"
93
+ append_demo_change "$WT_VALID/src/routes/tasks.js" "demo: validation agent touched tasks route"
94
+ git_commit_files "$WT_VALID" "Demo: validation change" src/middleware/validate.js src/routes/tasks.js
95
+ ok "Agent 2 adapts instead of colliding"
96
+
97
+ step "5. Finish work and watch the repo stay readable"
98
+ "${SWITCHMAN[@]}" task done "$TASK1_ID"
99
+ "${SWITCHMAN[@]}" task done "$TASK2_ID"
100
+ "${SWITCHMAN[@]}" status --watch --max-cycles 1
101
+
102
+ step "6. Queue both finished branches for safe landing"
103
+ "${SWITCHMAN[@]}" queue add --worktree agent-rate-limiting --target "$MAIN_BRANCH"
104
+ "${SWITCHMAN[@]}" queue add --worktree agent-validation --target "$MAIN_BRANCH"
105
+ "${SWITCHMAN[@]}" queue status
106
+
107
+ step "7. Land the work safely"
108
+ "${SWITCHMAN[@]}" queue run --max-items 2 --target "$MAIN_BRANCH"
109
+
110
+ step "8. Final safety check"
111
+ "${SWITCHMAN[@]}" gate ci
112
+
113
+ echo ""
114
+ echo -e "${GREEN}✓ Demo complete.${RESET}"
115
+ echo ""
116
+ echo "What just happened:"
117
+ echo " • agents took different tasks"
118
+ echo " • Switchman blocked an overlapping file claim early"
119
+ echo " • finished branches landed through the queue"
120
+ echo " • the repo safety gate passed"
121
+ echo ""
122
+ echo "Reset and run again:"
123
+ echo " bash examples/teardown.sh && bash examples/setup.sh"
124
+ echo ""
package/examples/setup.sh CHANGED
@@ -15,9 +15,16 @@
15
15
  set -e
16
16
 
17
17
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18
+ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
18
19
  TASKAPI_DIR="$SCRIPT_DIR/taskapi"
19
20
  WORKTREES_DIR="$SCRIPT_DIR/worktrees"
20
21
 
22
+ if [ -f "$REPO_ROOT/src/cli/index.js" ]; then
23
+ SWITCHMAN=(node "$REPO_ROOT/src/cli/index.js")
24
+ else
25
+ SWITCHMAN=(switchman)
26
+ fi
27
+
21
28
  echo ""
22
29
  echo "━━━ Switchman Example Setup ━━━━━━━━━━━━━━━━━━"
23
30
  echo ""
@@ -68,26 +75,26 @@ git worktree list
68
75
 
69
76
  echo ""
70
77
  echo "→ Initialising Switchman in taskapi..."
71
- switchman init
78
+ "${SWITCHMAN[@]}" init
72
79
 
73
80
  # ── Step 4: Seed tasks ────────────────────────────────────────────────────────
74
81
 
75
82
  echo ""
76
83
  echo "→ Seeding 4 parallel tasks..."
77
84
 
78
- switchman task add "Add rate limiting to all API routes" \
85
+ "${SWITCHMAN[@]}" task add "Add rate limiting to all API routes" \
79
86
  --priority 8 \
80
87
  --description "Token bucket: 100 req/min per API key. Return 429 with Retry-After header."
81
88
 
82
- switchman task add "Add input validation to POST /tasks and PATCH /tasks/:id" \
89
+ "${SWITCHMAN[@]}" task add "Add input validation to POST /tasks and PATCH /tasks/:id" \
83
90
  --priority 7 \
84
91
  --description "Validate title length, status enum, priority enum. Return 400 with descriptive errors."
85
92
 
86
- switchman task add "Write tests for the auth middleware" \
93
+ "${SWITCHMAN[@]}" task add "Write tests for the auth middleware" \
87
94
  --priority 6 \
88
95
  --description "Test requireAuth and requireAdmin: valid key, missing key, bad key, wrong role."
89
96
 
90
- switchman task add "Add pagination to GET /tasks" \
97
+ "${SWITCHMAN[@]}" task add "Add pagination to GET /tasks" \
91
98
  --priority 5 \
92
99
  --description "Add ?page=1&limit=20. Return { tasks, count, page, totalPages }."
93
100
 
@@ -96,7 +103,7 @@ echo "━━━━━━━━━━━━━━━━━━━━━━━━
96
103
  echo "✓ Setup complete."
97
104
  echo ""
98
105
  echo "Tasks ready:"
99
- switchman task list
106
+ "${SWITCHMAN[@]}" task list
100
107
  echo ""
101
108
  echo "→ Next: bash examples/walkthrough.sh"
102
109
  echo ""
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "switchman": {
4
+ "command": "switchman-mcp",
5
+ "args": []
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "switchman": {
4
+ "command": "switchman-mcp",
5
+ "args": []
6
+ }
7
+ }
8
+ }
@@ -94,3 +94,7 @@ function optionalAuth(req, res, next) {
94
94
  }
95
95
 
96
96
  module.exports = { requireAuth, requireRole, optionalAuth };
97
+
98
+ // demo: rate-limiting agent touched auth middleware
99
+
100
+ // demo: rate-limiting agent touched auth middleware
@@ -131,3 +131,7 @@ module.exports = {
131
131
  // Export primitives so routes can build ad-hoc schemas
132
132
  validators: { required, isString, isNumber, isEmail, oneOf, maxLength, minLength, compose },
133
133
  };
134
+
135
+ // demo: validation agent touched validation middleware
136
+
137
+ // demo: validation agent touched validation middleware
@@ -63,3 +63,7 @@ router.delete('/:id', (req, res) => {
63
63
  });
64
64
 
65
65
  module.exports = router;
66
+
67
+ // demo: validation agent touched tasks route
68
+
69
+ // demo: validation agent touched tasks route
@@ -5,3 +5,7 @@ const PORT = process.env.PORT || 3000;
5
5
  app.listen(PORT, () => {
6
6
  console.log(`TaskAPI running on port ${PORT}`);
7
7
  });
8
+
9
+ // demo: rate-limiting agent touched server
10
+
11
+ // demo: rate-limiting agent touched server
@@ -10,11 +10,18 @@
10
10
  set -e
11
11
 
12
12
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
+ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
13
14
  TASKAPI_DIR="$SCRIPT_DIR/taskapi"
14
15
  WT_RATE="$SCRIPT_DIR/worktrees/agent-rate-limiting"
15
16
  WT_VALID="$SCRIPT_DIR/worktrees/agent-validation"
16
17
  WT_TESTS="$SCRIPT_DIR/worktrees/agent-tests"
17
18
 
19
+ if [ -f "$REPO_ROOT/src/cli/index.js" ]; then
20
+ SWITCHMAN=(node "$REPO_ROOT/src/cli/index.js")
21
+ else
22
+ SWITCHMAN=(switchman)
23
+ fi
24
+
18
25
  # Colours
19
26
  CYAN='\033[0;36m'
20
27
  GREEN='\033[0;32m'
@@ -44,7 +51,7 @@ read -r
44
51
  step "1. Starting state"
45
52
  info "4 tasks waiting in the queue, 3 worktrees ready"
46
53
  echo ""
47
- switchman status
54
+ "${SWITCHMAN[@]}" status
48
55
 
49
56
  read -r
50
57
 
@@ -54,7 +61,7 @@ step "2. Agent 1 picks up the highest-priority task"
54
61
  agent "agent-rate-limiting" "calling: switchman lease next --json"
55
62
  echo ""
56
63
 
57
- TASK1=$(switchman lease next --json --worktree agent-rate-limiting --agent claude-code 2>/dev/null || echo "null")
64
+ TASK1=$("${SWITCHMAN[@]}" lease next --json --worktree agent-rate-limiting --agent claude-code 2>/dev/null || echo "null")
58
65
  TASK1_ID=$(echo "$TASK1" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['task']['id'])" 2>/dev/null || echo "")
59
66
 
60
67
  if [ -z "$TASK1_ID" ]; then
@@ -73,7 +80,7 @@ step "3. Agent 1 claims the files it needs"
73
80
  agent "agent-rate-limiting" "I'll be editing the middleware and server files"
74
81
  echo ""
75
82
 
76
- switchman claim "$TASK1_ID" agent-rate-limiting \
83
+ "${SWITCHMAN[@]}" claim "$TASK1_ID" agent-rate-limiting \
77
84
  src/middleware/auth.js \
78
85
  src/server.js
79
86
 
@@ -87,7 +94,7 @@ step "4. Agent 2 picks up the next task"
87
94
  agent "agent-validation" "calling: switchman lease next --json"
88
95
  echo ""
89
96
 
90
- TASK2=$(switchman lease next --json --worktree agent-validation --agent claude-code 2>/dev/null || echo "null")
97
+ TASK2=$("${SWITCHMAN[@]}" lease next --json --worktree agent-validation --agent claude-code 2>/dev/null || echo "null")
91
98
  TASK2_ID=$(echo "$TASK2" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['task']['id'])" 2>/dev/null || echo "")
92
99
  ok "Task + lease assigned to agent-validation"
93
100
 
@@ -100,7 +107,7 @@ agent "agent-validation" "Input validation also touches auth.js..."
100
107
  echo ""
101
108
 
102
109
  # This should warn about the conflict
103
- switchman claim "$TASK2_ID" agent-validation \
110
+ "${SWITCHMAN[@]}" claim "$TASK2_ID" agent-validation \
104
111
  src/middleware/auth.js \
105
112
  src/middleware/validate.js \
106
113
  src/routes/tasks.js || true
@@ -117,7 +124,7 @@ step "6. Agent 2 claims only the files that aren't taken"
117
124
  agent "agent-validation" "Claiming only validate.js and routes/tasks.js instead"
118
125
  echo ""
119
126
 
120
- switchman claim "$TASK2_ID" agent-validation \
127
+ "${SWITCHMAN[@]}" claim "$TASK2_ID" agent-validation \
121
128
  src/middleware/validate.js \
122
129
  src/routes/tasks.js
123
130
 
@@ -131,7 +138,7 @@ step "7. Full conflict scan across all worktrees"
131
138
  info "This is what you'd run before any merge"
132
139
  echo ""
133
140
 
134
- switchman scan
141
+ "${SWITCHMAN[@]}" scan
135
142
 
136
143
  read -r
137
144
 
@@ -141,7 +148,7 @@ step "8. Agent 1 finishes — marks task done and releases files"
141
148
  agent "agent-rate-limiting" "Rate limiting implemented and committed."
142
149
  echo ""
143
150
 
144
- switchman task done "$TASK1_ID"
151
+ "${SWITCHMAN[@]}" task done "$TASK1_ID"
145
152
  ok "Task done. src/middleware/auth.js and src/server.js are now free."
146
153
 
147
154
  read -r
@@ -149,7 +156,7 @@ read -r
149
156
  # ── Step 9: Final status ──────────────────────────────────────────────────────
150
157
 
151
158
  step "9. Final status"
152
- switchman status
159
+ "${SWITCHMAN[@]}" status
153
160
 
154
161
  echo ""
155
162
  echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "switchman-dev",
3
- "version": "0.1.3",
4
- "description": "Route your AI agents so they don't collide",
3
+ "version": "0.1.5",
4
+ "description": "Project manager for AI coding assistants running safely on one codebase",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
7
7
  "bin": {
@@ -15,7 +15,7 @@
15
15
  "scripts": {
16
16
  "start": "node src/cli/index.js",
17
17
  "mcp": "node src/mcp/server.js",
18
- "test": "node tests/test.js"
18
+ "test": "NODE_NO_WARNINGS=1 node tests/test.js"
19
19
  },
20
20
  "dependencies": {
21
21
  "@modelcontextprotocol/sdk": "^1.27.1",