sinapse-ai 1.19.0 → 1.19.1

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.
@@ -1,466 +0,0 @@
1
- #!/bin/bash
2
- # ============================================
3
- # SINAPSE PM Orchestration Script (pm.sh)
4
- # Story 11.2: Bob Terminal Spawning
5
- #
6
- # Spawns agents in separate terminals with clean context
7
- # to avoid context pollution when Bob (PM) orchestrates multiple agents.
8
- #
9
- # Usage: pm.sh <agent> <task> [params] [--context <path>] [--output <path>]
10
- #
11
- # Arguments:
12
- # agent - Agent ID (e.g., dev, architect, qa, pm)
13
- # task - Task to execute (e.g., develop, review, create-story)
14
- # params - Additional parameters for the agent (optional)
15
- # --context - Path to context file (JSON with story, files, instructions)
16
- # --output - Custom output file path (default: /tmp/sinapse-output-{timestamp}.md)
17
- #
18
- # Environment Variables:
19
- # SINAPSE_OUTPUT_DIR - Directory for output files (default: /tmp)
20
- # SINAPSE_DEBUG - Enable debug logging (default: false)
21
- # SINAPSE_TIMEOUT - Timeout in seconds (default: 300)
22
- # CLAUDE_CMD - Claude CLI command (default: claude)
23
- #
24
- # Exit Codes:
25
- # 0 - Success
26
- # 1 - Invalid arguments
27
- # 2 - Unsupported OS
28
- # 3 - No terminal found
29
- # 4 - Spawn failed
30
- #
31
- # Author: @dev (Dex) for Story 11.2
32
- # ============================================
33
-
34
- set -euo pipefail
35
-
36
- # Version
37
- readonly VERSION="1.0.0"
38
- readonly SCRIPT_NAME="$(basename "$0")"
39
-
40
- # Configuration
41
- OUTPUT_DIR="${SINAPSE_OUTPUT_DIR:-/tmp}"
42
- DEBUG="${SINAPSE_DEBUG:-false}"
43
- TIMEOUT="${SINAPSE_TIMEOUT:-300}"
44
- CLAUDE_CMD="${CLAUDE_CMD:-claude}"
45
- INLINE_MODE="${SINAPSE_INLINE_MODE:-false}"
46
-
47
- # Arguments
48
- AGENT=""
49
- TASK=""
50
- PARAMS=""
51
- CONTEXT_FILE=""
52
- CUSTOM_OUTPUT=""
53
-
54
- # Generated paths
55
- OUTPUT_FILE=""
56
- LOCK_FILE=""
57
-
58
- # ============================================
59
- # Logging Functions
60
- # ============================================
61
-
62
- log_debug() {
63
- [[ "$DEBUG" == "true" ]] && echo "[DEBUG] $*" >&2 || true
64
- }
65
-
66
- log_info() {
67
- echo "[INFO] $*" >&2
68
- }
69
-
70
- log_error() {
71
- echo "[ERROR] $*" >&2
72
- }
73
-
74
- # ============================================
75
- # Help and Version
76
- # ============================================
77
-
78
- show_help() {
79
- cat << EOF
80
- SINAPSE Multi-Modal Orchestration Script v${VERSION}
81
-
82
- Usage: ${SCRIPT_NAME} <agent> <task> [params] [options]
83
-
84
- Arguments:
85
- agent Agent ID (dev, architect, qa, pm, po, sm, analyst, devops, etc.)
86
- task Task to execute (develop, review, create-story, etc.)
87
- params Additional parameters (optional, quoted string)
88
-
89
- Options:
90
- --context <path> Path to JSON context file
91
- --output <path> Custom output file path
92
- --help, -h Show this help message
93
- --version, -v Show version
94
-
95
- Environment Variables:
96
- SINAPSE_OUTPUT_DIR Output directory (default: /tmp)
97
- SINAPSE_DEBUG Enable debug mode (default: false)
98
- SINAPSE_TIMEOUT Timeout in seconds (default: 300)
99
- SINAPSE_INLINE_MODE Run without a visual terminal (default: false)
100
- CLAUDE_CMD Claude CLI command (default: claude)
101
-
102
- Examples:
103
- ${SCRIPT_NAME} dev develop "story-11.2"
104
- ${SCRIPT_NAME} architect review --context /tmp/ctx.json
105
- ${SCRIPT_NAME} qa test --output /tmp/qa-result.md
106
-
107
- Exit Codes:
108
- 0 - Success (output file path printed to stdout)
109
- 1 - Invalid arguments
110
- 2 - Unsupported OS
111
- 3 - No terminal found
112
- 4 - Spawn failed
113
- EOF
114
- }
115
-
116
- show_version() {
117
- echo "${SCRIPT_NAME} version ${VERSION}"
118
- }
119
-
120
- # ============================================
121
- # Argument Parsing
122
- # ============================================
123
-
124
- parse_args() {
125
- while [[ $# -gt 0 ]]; do
126
- case "$1" in
127
- --help|-h)
128
- show_help
129
- exit 0
130
- ;;
131
- --version|-v)
132
- show_version
133
- exit 0
134
- ;;
135
- --context)
136
- shift
137
- CONTEXT_FILE="${1:-}"
138
- if [[ -z "$CONTEXT_FILE" ]]; then
139
- log_error "Missing value for --context"
140
- exit 1
141
- fi
142
- ;;
143
- --output)
144
- shift
145
- CUSTOM_OUTPUT="${1:-}"
146
- if [[ -z "$CUSTOM_OUTPUT" ]]; then
147
- log_error "Missing value for --output"
148
- exit 1
149
- fi
150
- ;;
151
- -*)
152
- log_error "Unknown option: $1"
153
- show_help
154
- exit 1
155
- ;;
156
- *)
157
- # Positional arguments
158
- if [[ -z "$AGENT" ]]; then
159
- AGENT="$1"
160
- elif [[ -z "$TASK" ]]; then
161
- TASK="$1"
162
- else
163
- # Remaining args are params
164
- PARAMS="${PARAMS:+$PARAMS }$1"
165
- fi
166
- ;;
167
- esac
168
- shift
169
- done
170
-
171
- # Validate required args
172
- if [[ -z "$AGENT" || -z "$TASK" ]]; then
173
- log_error "Missing required arguments: agent and task"
174
- echo ""
175
- show_help
176
- exit 1
177
- fi
178
-
179
- # Validate context file if provided
180
- if [[ -n "$CONTEXT_FILE" && ! -f "$CONTEXT_FILE" ]]; then
181
- log_error "Context file not found: $CONTEXT_FILE"
182
- exit 1
183
- fi
184
- }
185
-
186
- # ============================================
187
- # OS Detection (Task 1.1)
188
- # ============================================
189
-
190
- detect_os() {
191
- case "$(uname -s)" in
192
- Darwin*)
193
- echo "macos"
194
- ;;
195
- Linux*)
196
- # Check if running in WSL
197
- if grep -qi microsoft /proc/version 2>/dev/null; then
198
- echo "wsl"
199
- else
200
- echo "linux"
201
- fi
202
- ;;
203
- CYGWIN*|MINGW*|MSYS*)
204
- echo "windows"
205
- ;;
206
- *)
207
- echo "unknown"
208
- ;;
209
- esac
210
- }
211
-
212
- # ============================================
213
- # File Path Setup
214
- # ============================================
215
-
216
- setup_paths() {
217
- local timestamp
218
- timestamp="$(date +%s)"
219
-
220
- if [[ -n "$CUSTOM_OUTPUT" ]]; then
221
- OUTPUT_FILE="$CUSTOM_OUTPUT"
222
- else
223
- OUTPUT_FILE="${OUTPUT_DIR}/sinapse-output-${timestamp}.md"
224
- fi
225
-
226
- LOCK_FILE="${OUTPUT_DIR}/sinapse-lock-${timestamp}.lock"
227
-
228
- log_debug "Output file: $OUTPUT_FILE"
229
- log_debug "Lock file: $LOCK_FILE"
230
- }
231
-
232
- # ============================================
233
- # Terminal Spawning - macOS (Task 1.2)
234
- # ============================================
235
-
236
- spawn_macos() {
237
- local cmd="$1"
238
-
239
- log_debug "Spawning on macOS..."
240
-
241
- # Check for iTerm2 first (better AppleScript support)
242
- if [[ -d "/Applications/iTerm.app" ]]; then
243
- log_debug "Using iTerm2"
244
- osascript << EOF
245
- tell application "iTerm"
246
- activate
247
- set newWindow to (create window with default profile)
248
- tell current session of newWindow
249
- write text "${cmd}"
250
- end tell
251
- end tell
252
- EOF
253
- else
254
- # Fallback to Terminal.app
255
- log_debug "Using Terminal.app"
256
- osascript -e "tell application \"Terminal\"
257
- activate
258
- do script \"${cmd}\"
259
- end tell"
260
- fi
261
- }
262
-
263
- # ============================================
264
- # Terminal Spawning - Linux (Task 1.3)
265
- # ============================================
266
-
267
- spawn_linux() {
268
- local cmd="$1"
269
-
270
- log_debug "Spawning on Linux..."
271
-
272
- # Try terminals in order of preference
273
- if command -v gnome-terminal &> /dev/null; then
274
- log_debug "Using gnome-terminal"
275
- gnome-terminal -- bash -c "$cmd; exec bash" &
276
- elif command -v konsole &> /dev/null; then
277
- log_debug "Using konsole"
278
- konsole --hold -e bash -c "$cmd" &
279
- elif command -v xfce4-terminal &> /dev/null; then
280
- log_debug "Using xfce4-terminal"
281
- xfce4-terminal --hold -e "bash -c '$cmd'" &
282
- elif command -v xterm &> /dev/null; then
283
- log_debug "Using xterm"
284
- xterm -hold -e "$cmd" &
285
- elif command -v alacritty &> /dev/null; then
286
- log_debug "Using alacritty"
287
- alacritty -e bash -c "$cmd; exec bash" &
288
- elif command -v kitty &> /dev/null; then
289
- log_debug "Using kitty"
290
- kitty bash -c "$cmd; exec bash" &
291
- else
292
- log_error "No supported terminal found"
293
- log_error "Please install one of: gnome-terminal, konsole, xfce4-terminal, xterm, alacritty, kitty"
294
- return 3
295
- fi
296
- }
297
-
298
- # ============================================
299
- # Terminal Spawning - Windows/WSL (Task 1.4)
300
- # ============================================
301
-
302
- spawn_windows() {
303
- local cmd="$1"
304
-
305
- log_debug "Spawning on Windows/WSL..."
306
-
307
- # When running in WSL, spawn using Windows Terminal or cmd
308
- if command -v wt.exe &> /dev/null; then
309
- log_debug "Using Windows Terminal"
310
- wt.exe new-tab wsl.exe bash -c "$cmd" &
311
- elif command -v cmd.exe &> /dev/null; then
312
- log_debug "Using cmd.exe with wsl"
313
- cmd.exe /c start wsl.exe bash -c "$cmd" &
314
- else
315
- log_error "No Windows terminal method available"
316
- log_error "Please install Windows Terminal or ensure cmd.exe is accessible"
317
- return 3
318
- fi
319
- }
320
-
321
- spawn_wsl() {
322
- # When already in WSL, spawn a new terminal window
323
- spawn_windows "$1"
324
- }
325
-
326
- # ============================================
327
- # Inline Execution (Story 12.10 - No visual terminal)
328
- # ============================================
329
-
330
- spawn_inline() {
331
- log_info "Running in inline mode (no visual terminal)"
332
-
333
- # Build the command
334
- local output=""
335
- output+="=== SINAPSE Agent Session (Inline) ===$(printf '\n')"
336
- output+="Agent: ${AGENT}$(printf '\n')"
337
- output+="Task: ${TASK}$(printf '\n')"
338
- [[ -n "$PARAMS" ]] && output+="Params: ${PARAMS}$(printf '\n')"
339
- [[ -n "$CONTEXT_FILE" ]] && output+="Context: ${CONTEXT_FILE}$(printf '\n')"
340
- output+="$(printf '\n')"
341
- output+="Executing: @${AGENT} *${TASK} ${PARAMS}$(printf '\n')"
342
- output+="Agent execution would happen here...$(printf '\n')"
343
- output+="=== Session Complete ===$(printf '\n')"
344
-
345
- # Write output directly to file
346
- echo "$output" > "${OUTPUT_FILE}"
347
-
348
- # Remove lock file immediately (inline is synchronous)
349
- rm -f "${LOCK_FILE}"
350
-
351
- log_info "Inline execution complete"
352
- log_debug "Output written to: $OUTPUT_FILE"
353
-
354
- return 0
355
- }
356
-
357
- # ============================================
358
- # Main Spawn Logic (Task 1.6 - Lock File)
359
- # ============================================
360
-
361
- spawn_terminal() {
362
- local os
363
- os="$(detect_os)"
364
-
365
- log_info "Detected OS: $os"
366
-
367
- # Create lock file to indicate process is running
368
- touch "$LOCK_FILE"
369
- log_debug "Created lock file: $LOCK_FILE"
370
-
371
- # Check for inline mode (Story 12.10 - fallback for non-visual environments)
372
- if [[ "$INLINE_MODE" == "true" ]]; then
373
- spawn_inline
374
- echo "$OUTPUT_FILE"
375
- return 0
376
- fi
377
-
378
- # Build the command to run in the new terminal
379
- local agent_cmd="${CLAUDE_CMD}"
380
-
381
- # Add agent activation
382
- agent_cmd="${agent_cmd} --print-only" # Just for testing, real impl would use actual claude flags
383
-
384
- # SECURITY (SHELL-INJECTION-PM-SH): AGENT/TASK/PARAMS/CONTEXT_FILE come from
385
- # CLI args and are interpolated into a command string run by a shell in the
386
- # spawned terminal. Escape every interpolated value with `printf %q` so shell
387
- # metacharacters (`;`, `$()`, backticks, quotes) cannot break out and execute.
388
- local q_agent q_task q_params q_context q_output q_lock
389
- printf -v q_agent '%q' "$AGENT"
390
- printf -v q_task '%q' "$TASK"
391
- printf -v q_params '%q' "$PARAMS"
392
- printf -v q_context '%q' "$CONTEXT_FILE"
393
- printf -v q_output '%q' "$OUTPUT_FILE"
394
- printf -v q_lock '%q' "$LOCK_FILE"
395
-
396
- # For now, we'll create a simpler command that demonstrates the concept
397
- # The actual claude CLI integration will depend on how claude accepts agent/task args
398
- local full_cmd="echo '=== SINAPSE Agent Session ===' && "
399
- full_cmd+="echo Agent: ${q_agent} && "
400
- full_cmd+="echo Task: ${q_task} && "
401
- [[ -n "$PARAMS" ]] && full_cmd+="echo Params: ${q_params} && "
402
- [[ -n "$CONTEXT_FILE" ]] && full_cmd+="echo Context: ${q_context} && "
403
- full_cmd+="echo '' && "
404
-
405
- # Actual execution would be something like:
406
- # full_cmd+="${CLAUDE_CMD} @${AGENT} *${TASK} ${PARAMS}"
407
- # For now, simulate the output
408
- full_cmd+="echo Executing: @${q_agent} '*'${q_task} ${q_params} && "
409
- full_cmd+="echo 'Agent execution would happen here...' && "
410
- full_cmd+="echo '=== Session Complete ===' "
411
-
412
- # Redirect output to file and remove lock when done
413
- full_cmd+=" > ${q_output} 2>&1; rm -f ${q_lock}"
414
-
415
- # Spawn based on OS
416
- case "$os" in
417
- macos)
418
- spawn_macos "$full_cmd"
419
- ;;
420
- linux)
421
- spawn_linux "$full_cmd"
422
- ;;
423
- windows|wsl)
424
- spawn_windows "$full_cmd"
425
- ;;
426
- *)
427
- log_error "Unsupported operating system: $os"
428
- rm -f "$LOCK_FILE"
429
- return 2
430
- ;;
431
- esac
432
-
433
- local spawn_result=$?
434
- if [[ $spawn_result -ne 0 ]]; then
435
- log_error "Failed to spawn terminal (exit code: $spawn_result)"
436
- rm -f "$LOCK_FILE"
437
- return 4
438
- fi
439
-
440
- log_info "Terminal spawned successfully"
441
- log_debug "Output will be written to: $OUTPUT_FILE"
442
- log_debug "Lock file: $LOCK_FILE (will be removed when complete)"
443
-
444
- # Return the output file path for polling
445
- echo "$OUTPUT_FILE"
446
- }
447
-
448
- # ============================================
449
- # Main Entry Point
450
- # ============================================
451
-
452
- main() {
453
- parse_args "$@"
454
- setup_paths
455
-
456
- log_info "SINAPSE Multi-Modal Orchestration Script v${VERSION}"
457
- log_info "Agent: $AGENT"
458
- log_info "Task: $TASK"
459
- [[ -n "$PARAMS" ]] && log_info "Params: $PARAMS"
460
- [[ -n "$CONTEXT_FILE" ]] && log_info "Context: $CONTEXT_FILE"
461
-
462
- spawn_terminal
463
- }
464
-
465
- main "$@"
466
-