sisyphi 0.1.2 → 0.1.4

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 (74) hide show
  1. package/README.md +103 -33
  2. package/dist/{chunk-FWHTKXN5.js → chunk-N2BPQOO2.js} +23 -3
  3. package/dist/chunk-N2BPQOO2.js.map +1 -0
  4. package/dist/cli.js +85 -162
  5. package/dist/cli.js.map +1 -1
  6. package/dist/daemon.js +603 -186
  7. package/dist/daemon.js.map +1 -1
  8. package/dist/templates/CLAUDE.md +50 -0
  9. package/dist/templates/agent-plugin/.claude/agents/debug.md +39 -0
  10. package/dist/templates/agent-plugin/.claude/agents/plan.md +101 -0
  11. package/dist/templates/agent-plugin/.claude/agents/review-plan.md +81 -0
  12. package/dist/templates/agent-plugin/.claude/agents/review.md +56 -0
  13. package/dist/templates/agent-plugin/.claude/agents/spec-draft.md +73 -0
  14. package/dist/templates/agent-plugin/.claude/agents/test-spec.md +56 -0
  15. package/dist/templates/agent-plugin/.claude-plugin/plugin.json +5 -0
  16. package/dist/templates/agent-plugin/agents/CLAUDE.md +52 -0
  17. package/dist/templates/agent-plugin/agents/debug.md +39 -0
  18. package/dist/templates/agent-plugin/agents/operator.md +56 -0
  19. package/dist/templates/agent-plugin/agents/plan.md +101 -0
  20. package/dist/templates/agent-plugin/agents/review-plan.md +81 -0
  21. package/dist/templates/agent-plugin/agents/review.md +56 -0
  22. package/dist/templates/agent-plugin/agents/spec-draft.md +73 -0
  23. package/dist/templates/agent-plugin/agents/test-spec.md +56 -0
  24. package/dist/templates/agent-suffix.md +3 -1
  25. package/dist/templates/banner.txt +24 -6
  26. package/dist/templates/orchestrator-plugin/.claude/commands/begin.md +62 -0
  27. package/dist/templates/orchestrator-plugin/.claude/skills/orchestration/SKILL.md +40 -0
  28. package/dist/templates/orchestrator-plugin/.claude/skills/orchestration/task-patterns.md +222 -0
  29. package/dist/templates/orchestrator-plugin/.claude/skills/orchestration/workflow-examples.md +208 -0
  30. package/dist/templates/orchestrator-plugin/.claude-plugin/plugin.json +5 -0
  31. package/dist/templates/orchestrator-plugin/hooks/hooks.json +25 -0
  32. package/dist/templates/orchestrator-plugin/scripts/block-task.sh +4 -0
  33. package/dist/templates/orchestrator-plugin/scripts/stop-suggest.sh +4 -0
  34. package/dist/templates/orchestrator-plugin/skills/git-management/SKILL.md +111 -0
  35. package/dist/templates/orchestrator-plugin/skills/orchestration/SKILL.md +40 -0
  36. package/dist/templates/orchestrator-plugin/skills/orchestration/task-patterns.md +248 -0
  37. package/dist/templates/orchestrator-plugin/skills/orchestration/workflow-examples.md +237 -0
  38. package/dist/templates/orchestrator-settings.json +2 -0
  39. package/dist/templates/orchestrator.md +56 -49
  40. package/dist/templates/resources/.claude/agents/debug.md +39 -0
  41. package/dist/templates/resources/.claude/agents/plan.md +101 -0
  42. package/dist/templates/resources/.claude/agents/review-plan.md +81 -0
  43. package/dist/templates/resources/.claude/agents/review.md +56 -0
  44. package/dist/templates/resources/.claude/agents/spec-draft.md +73 -0
  45. package/dist/templates/resources/.claude/agents/test-spec.md +56 -0
  46. package/dist/templates/resources/.claude/commands/begin.md +62 -0
  47. package/dist/templates/resources/.claude/skills/orchestration/SKILL.md +40 -0
  48. package/dist/templates/resources/.claude/skills/orchestration/task-patterns.md +222 -0
  49. package/dist/templates/resources/.claude/skills/orchestration/workflow-examples.md +208 -0
  50. package/dist/templates/resources/.claude-plugin/plugin.json +8 -0
  51. package/package.json +2 -2
  52. package/templates/CLAUDE.md +50 -0
  53. package/templates/agent-plugin/.claude-plugin/plugin.json +5 -0
  54. package/templates/agent-plugin/agents/CLAUDE.md +52 -0
  55. package/templates/agent-plugin/agents/debug.md +39 -0
  56. package/templates/agent-plugin/agents/operator.md +56 -0
  57. package/templates/agent-plugin/agents/plan.md +101 -0
  58. package/templates/agent-plugin/agents/review-plan.md +81 -0
  59. package/templates/agent-plugin/agents/review.md +56 -0
  60. package/templates/agent-plugin/agents/spec-draft.md +73 -0
  61. package/templates/agent-plugin/agents/test-spec.md +56 -0
  62. package/templates/agent-suffix.md +3 -1
  63. package/templates/banner.txt +24 -6
  64. package/templates/orchestrator-plugin/.claude-plugin/plugin.json +5 -0
  65. package/templates/orchestrator-plugin/hooks/hooks.json +25 -0
  66. package/templates/orchestrator-plugin/scripts/block-task.sh +4 -0
  67. package/templates/orchestrator-plugin/scripts/stop-suggest.sh +4 -0
  68. package/templates/orchestrator-plugin/skills/git-management/SKILL.md +111 -0
  69. package/templates/orchestrator-plugin/skills/orchestration/SKILL.md +40 -0
  70. package/templates/orchestrator-plugin/skills/orchestration/task-patterns.md +248 -0
  71. package/templates/orchestrator-plugin/skills/orchestration/workflow-examples.md +237 -0
  72. package/templates/orchestrator-settings.json +2 -0
  73. package/templates/orchestrator.md +56 -49
  74. package/dist/chunk-FWHTKXN5.js.map +0 -1
package/README.md CHANGED
@@ -1,13 +1,31 @@
1
1
  ```
2
- _____ _____ _______ _______ _ _ _ _ _____
3
- / ___|_ _/ ___\ \ / / ___ \ | | | | | / ___|
4
- \ `--. | | \ `--. \ V /| |_/ / |_| | | | \ `--.
5
- `--. \ | | `--. \ \ / | __/| _ | | | |`--. \
6
- /\__/ /_| |_/\__/ / | | | | | | | | |_| /\__/ /
7
- \____/ \___/\____/ \_/ \_| \_| |_/\___/\____/
2
+ ╔═══════════════════════════════════════════════════════╗
3
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@%%%#*++**#%%@@@@@@@@@@@@@@
4
+ @@@@@@@@@@@@@@@@@@@@@@@@%*====-----::::-:=%@@@@@@@@@@
5
+ @@@@@@@@@@@@@@@@@@@@@%#=:.:-=------:... -%@@@@@@@@
6
+ @@@@@@@@@@@@@@@@@@%%#= .....:-:.......... *%@@@@@@
7
+ @@@@@@@@@@@@@@%+==-+%*: .:---::::....:.... #@@@@@@
8
+ ║ @@@@@@@@@@@@%#:. ..:. ..:-...:..... . :%@@@@@@ ║
9
+ ║ @@@@@@@@@@@@#:.:.. :*= ............ . :%@@@@@@ ║
10
+ ║ @@@@@@@@@@@@#--:.. -%+............... .. *%#=-:.: ║
11
+ ║ @@@@@@@@@@%#----.:#%+.::::... ..... .... .:# ║
12
+ ║ @@@@@@@@%+-:::.. :%@@@@@@@@%*=: ..*%@ ║
13
+ ║ @@@@@@%*-=:..::.:-..+@@@@@@%%#=:. .. . ... *@@@ ║
14
+ ║ @@@@#==::%@@@@@@%=:::=%*-:. .... . ... :%@@@@ ║
15
+ ║ @@#::=#@@@@%#-.:-... .::... :#%@@@@@ ║
16
+ ║ %=:%%%#####+:.: . ..... . . *%@@@@@@@ ║
17
+ ║ :::.:.:::..::. . .. :#@@@@@@@ ║
18
+ ║ %#*++===--============++===-::::::::---=====#%@@@@@@@ ║
19
+ ║ _____ _____ _______ _______ _ _ _ _ _____ ║
20
+ ║ / ___|_ _/ ___\ \ / / ___ \ | | | | | / ___| ║
21
+ ║ \ `--. | | \ `--. \ V /| |_/ / |_| | | | \ `--. ║
22
+ ║ `--. \ | | `--. \ \ / | __/| _ | | | |`--. \ ║
23
+ ║ /\__/ /_| |_/\__/ / | | | | | | | | |_| /\__/ / ║
24
+ ║ \____/ \___/\____/ \_/ \_| \_| |_/\___/\____/ ║
25
+ ╚═══════════════════════════════════════════════════════╝
8
26
  ```
9
27
 
10
- # sisyphi
28
+ # sisyphus
11
29
 
12
30
  A tmux-integrated orchestration daemon for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) multi-agent workflows.
13
31
 
@@ -38,7 +56,7 @@ You ──► sisyphus start "build auth system"
38
56
  ```
39
57
 
40
58
  1. **You** run `sisyphus start` with a high-level task
41
- 2. **Orchestrator** decomposes it, adds tasks, spawns agents, yields
59
+ 2. **Orchestrator** decomposes it, spawns agents, yields
42
60
  3. **Agents** work in parallel tmux panes, send progress reports, submit when done
43
61
  4. **Daemon** detects completion, respawns orchestrator with updated state
44
62
  5. **Orchestrator** reviews reports, spawns more agents or completes the session
@@ -63,7 +81,7 @@ This gives you two commands:
63
81
 
64
82
  ### Claude Code Plugin (optional)
65
83
 
66
- The companion plugin on the [crouton-kit](https://github.com/CaptainCrouton89/crouton-kit) marketplace adds 11 specialized agent types and an orchestration skill with task breakdown patterns for common workflows (bug fixes, feature builds, refactors, reviews, etc.).
84
+ The companion plugin on the [crouton-kit](https://github.com/CaptainCrouton89/crouton-kit) marketplace adds specialized agent types and an orchestration skill with task breakdown patterns for common workflows (bug fixes, feature builds, refactors, reviews, etc.).
67
85
 
68
86
  ```bash
69
87
  claude plugins install CaptainCrouton89/crouton-kit sisyphus
@@ -79,7 +97,9 @@ This makes `sisyphus:debug`, `sisyphus:implement`, `sisyphus:plan`, and other ag
79
97
  sisyphusd
80
98
  ```
81
99
 
82
- Or run it in the background. On macOS you can use launchd — create `~/Library/LaunchAgents/com.sisyphus.daemon.plist`:
100
+ The daemon also supports `sisyphusd stop` and `sisyphusd restart` subcommands.
101
+
102
+ To run it persistently on macOS, use launchd — create `~/Library/LaunchAgents/com.sisyphus.daemon.plist`:
83
103
 
84
104
  ```xml
85
105
  <?xml version="1.0" encoding="UTF-8"?>
@@ -110,6 +130,13 @@ Then load it:
110
130
  launchctl load ~/Library/LaunchAgents/com.sisyphus.daemon.plist
111
131
  ```
112
132
 
133
+ To unload and clean up:
134
+
135
+ ```bash
136
+ sisyphus uninstall # Unload from launchd
137
+ sisyphus uninstall --purge # Also remove ~/.sisyphus data
138
+ ```
139
+
113
140
  ### 2. Start a session (inside tmux)
114
141
 
115
142
  ```bash
@@ -121,23 +148,19 @@ The orchestrator spawns in a yellow tmux pane and begins planning.
121
148
  ### 3. Watch it work
122
149
 
123
150
  ```bash
124
- sisyphus status # Check session state, tasks, agents
125
- sisyphus tasks list # View task breakdown
151
+ sisyphus status # Check session state and agents
152
+ sisyphus list # List sessions in current project
153
+ sisyphus list --all # List sessions across all projects
126
154
  ```
127
155
 
128
- Agent panes appear as the orchestrator spawns them, color-coded by agent:
129
-
130
- | Role | Color |
131
- |------|-------|
132
- | Orchestrator | Yellow |
133
- | Agents | Blue, Green, Magenta, Cyan, Red, White (rotating) |
156
+ Agent panes appear as the orchestrator spawns them, color-coded by role. Agent types from the crouton-kit plugin define their own colors via frontmatter; otherwise agents rotate through blue, green, magenta, cyan, red, and white.
134
157
 
135
158
  ### 4. Resume or complete
136
159
 
137
160
  ```bash
138
161
  sisyphus resume <session-id> # Resume a paused session
139
162
  sisyphus resume <session-id> "focus on tests" # Resume with new instructions
140
- sisyphus list # List all sessions
163
+ sisyphus kill <session-id> # Kill a session and all agents
141
164
  ```
142
165
 
143
166
  ## CLI Reference
@@ -145,25 +168,56 @@ sisyphus list # List all sessions
145
168
  ```bash
146
169
  # Session lifecycle
147
170
  sisyphus start "task description" # Create session, launch orchestrator
148
- sisyphus status # Current session state
149
- sisyphus list # List all sessions
171
+ sisyphus status [session-id] # Session state (defaults to active session)
172
+ sisyphus list [-a, --all] # List sessions (--all for cross-project)
150
173
  sisyphus resume <id> [message] # Resume paused session
151
- sisyphus kill <id> # Kill a session
174
+ sisyphus kill <id> # Kill session and all agents
175
+ sisyphus uninstall [--purge] [-y] # Unload daemon from launchd
176
+
177
+ # Daemon management
178
+ sisyphusd # Start the daemon
179
+ sisyphusd stop # Stop the daemon
180
+ sisyphusd restart # Restart the daemon
152
181
 
153
- # These are used by the orchestrator/agents (not typically run manually):
182
+ # Used by the orchestrator/agents (not typically run manually):
154
183
  sisyphus spawn --agent-type <t> --name <n> --instruction "..."
155
- sisyphus yield # Orchestrator yields control
184
+ sisyphus spawn --agent-type <t> --name <n> --instruction "..." --worktree
185
+ sisyphus yield [--prompt "next cycle context"]
156
186
  sisyphus complete --report "summary" # Mark session done
157
187
  sisyphus submit --report "findings" # Agent submits final report
158
188
  sisyphus report --message "progress" # Agent sends progress update
189
+ ```
190
+
191
+ Both `yield`, `submit`, and `report` support stdin piping for long content:
159
192
 
160
- # Task management
161
- sisyphus tasks list
162
- sisyphus tasks add "description"
163
- sisyphus tasks add "idea" --status draft
164
- echo "long description" | sisyphus tasks add # stdin piping
165
- sisyphus tasks update <taskId> --status done
166
- sisyphus tasks update <taskId> --description "refined"
193
+ ```bash
194
+ echo "detailed report" | sisyphus submit
195
+ echo "progress update" | sisyphus report
196
+ ```
197
+
198
+ ## Git Worktree Isolation
199
+
200
+ Agents can work in isolated git worktrees to avoid conflicts when multiple agents edit files in parallel:
201
+
202
+ ```bash
203
+ sisyphus spawn --agent-type sisyphus:implement --name "auth" \
204
+ --instruction "implement auth module" --worktree
205
+ ```
206
+
207
+ With `--worktree`, the daemon:
208
+ 1. Creates a new branch (`sisyphus/{session}/{agent-id}`) and worktree
209
+ 2. Symlinks `.sisyphus` and `.claude` directories into the worktree
210
+ 3. Runs bootstrap commands from `.sisyphus/worktree.json` (copy files, install deps, etc.)
211
+ 4. Automatically merges the agent's branch back when the agent submits
212
+
213
+ Configure worktree bootstrap in `.sisyphus/worktree.json`:
214
+
215
+ ```json
216
+ {
217
+ "symlink": [".env", "node_modules"],
218
+ "copy": ["package.json"],
219
+ "init": "npm install"
220
+ }
167
221
  ```
168
222
 
169
223
  ## Architecture
@@ -174,7 +228,22 @@ Three layers communicating over a Unix socket (`~/.sisyphus/daemon.sock`):
174
228
  - **Daemon** (`sisyphusd`) — Manages sessions, spawns/monitors tmux panes, tracks state
175
229
  - **Shared** — Types, protocol definitions, config resolution
176
230
 
177
- State is persisted as JSON at `.sisyphus/sessions/{id}/state.json` (relative to your project directory), written atomically via temp file + rename.
231
+ ### State & Persistence
232
+
233
+ State is persisted as JSON at `.sisyphus/sessions/{id}/state.json` (project-relative), written atomically via temp file + rename.
234
+
235
+ Each session directory contains:
236
+ ```
237
+ .sisyphus/sessions/{id}/
238
+ ├── state.json # Session state (atomic writes)
239
+ ├── plan.md # Orchestrator memory — outstanding work
240
+ ├── logs.md # Orchestrator memory — session log
241
+ ├── prompts/ # Rendered system + user prompt files
242
+ ├── reports/ # Agent report files
243
+ └── context/ # Persistent artifacts (specs, plans, explorations)
244
+ ```
245
+
246
+ The orchestrator maintains `plan.md` and `logs.md` across cycles as persistent memory — these survive orchestrator respawns and give each new cycle continuity with previous work.
178
247
 
179
248
  ## Configuration
180
249
 
@@ -183,7 +252,8 @@ Config is layered: project (`.sisyphus/config.json`) overrides global (`~/.sisyp
183
252
  ```json
184
253
  {
185
254
  "model": "sonnet",
186
- "pollIntervalMs": 3000
255
+ "pollIntervalMs": 1000,
256
+ "tmuxSession": "my-session"
187
257
  }
188
258
  ```
189
259
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/shared/paths.ts
4
4
  import { homedir } from "os";
5
- import { join } from "path";
5
+ import { basename, join } from "path";
6
6
  function globalDir() {
7
7
  return join(homedir(), ".sisyphus");
8
8
  }
@@ -42,9 +42,24 @@ function reportsDir(cwd, sessionId) {
42
42
  function reportFilePath(cwd, sessionId, agentId, suffix) {
43
43
  return join(reportsDir(cwd, sessionId), `${agentId}-${suffix}.md`);
44
44
  }
45
+ function promptsDir(cwd, sessionId) {
46
+ return join(sessionDir(cwd, sessionId), "prompts");
47
+ }
45
48
  function contextDir(cwd, sessionId) {
46
49
  return join(sessionDir(cwd, sessionId), "context");
47
50
  }
51
+ function planPath(cwd, sessionId) {
52
+ return join(sessionDir(cwd, sessionId), "plan.md");
53
+ }
54
+ function logsPath(cwd, sessionId) {
55
+ return join(sessionDir(cwd, sessionId), "logs.md");
56
+ }
57
+ function worktreeConfigPath(cwd) {
58
+ return join(projectDir(cwd), "worktree.json");
59
+ }
60
+ function worktreeBaseDir(cwd) {
61
+ return join(cwd, "..", `${basename(cwd)}-sisyphus-wt`);
62
+ }
48
63
 
49
64
  export {
50
65
  globalDir,
@@ -59,6 +74,11 @@ export {
59
74
  statePath,
60
75
  reportsDir,
61
76
  reportFilePath,
62
- contextDir
77
+ promptsDir,
78
+ contextDir,
79
+ planPath,
80
+ logsPath,
81
+ worktreeConfigPath,
82
+ worktreeBaseDir
63
83
  };
64
- //# sourceMappingURL=chunk-FWHTKXN5.js.map
84
+ //# sourceMappingURL=chunk-N2BPQOO2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/paths.ts"],"sourcesContent":["import { homedir } from 'node:os';\nimport { basename, join } from 'node:path';\n\nexport function globalDir(): string {\n return join(homedir(), '.sisyphus');\n}\n\nexport function socketPath(): string {\n return join(globalDir(), 'daemon.sock');\n}\n\nexport function globalConfigPath(): string {\n return join(globalDir(), 'config.json');\n}\n\nexport function daemonLogPath(): string {\n return join(globalDir(), 'daemon.log');\n}\n\nexport function daemonPidPath(): string {\n return join(globalDir(), 'daemon.pid');\n}\n\nexport function projectDir(cwd: string): string {\n return join(cwd, '.sisyphus');\n}\n\nexport function projectConfigPath(cwd: string): string {\n return join(projectDir(cwd), 'config.json');\n}\n\nexport function projectOrchestratorPromptPath(cwd: string): string {\n return join(projectDir(cwd), 'orchestrator.md');\n}\n\nexport function sessionsDir(cwd: string): string {\n return join(projectDir(cwd), 'sessions');\n}\n\nexport function sessionDir(cwd: string, sessionId: string): string {\n return join(sessionsDir(cwd), sessionId);\n}\n\nexport function statePath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'state.json');\n}\n\nexport function reportsDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'reports');\n}\n\nexport function reportFilePath(cwd: string, sessionId: string, agentId: string, suffix: string): string {\n return join(reportsDir(cwd, sessionId), `${agentId}-${suffix}.md`);\n}\n\nexport function promptsDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'prompts');\n}\n\nexport function contextDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'context');\n}\n\nexport function planPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'plan.md');\n}\n\nexport function logsPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'logs.md');\n}\n\nexport function worktreeConfigPath(cwd: string): string {\n return join(projectDir(cwd), 'worktree.json');\n}\n\nexport function worktreeBaseDir(cwd: string): string {\n return join(cwd, '..', `${basename(cwd)}-sisyphus-wt`);\n}\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,SAAS,UAAU,YAAY;AAExB,SAAS,YAAoB;AAClC,SAAO,KAAK,QAAQ,GAAG,WAAW;AACpC;AAEO,SAAS,aAAqB;AACnC,SAAO,KAAK,UAAU,GAAG,aAAa;AACxC;AAEO,SAAS,mBAA2B;AACzC,SAAO,KAAK,UAAU,GAAG,aAAa;AACxC;AAEO,SAAS,gBAAwB;AACtC,SAAO,KAAK,UAAU,GAAG,YAAY;AACvC;AAEO,SAAS,gBAAwB;AACtC,SAAO,KAAK,UAAU,GAAG,YAAY;AACvC;AAEO,SAAS,WAAW,KAAqB;AAC9C,SAAO,KAAK,KAAK,WAAW;AAC9B;AAEO,SAAS,kBAAkB,KAAqB;AACrD,SAAO,KAAK,WAAW,GAAG,GAAG,aAAa;AAC5C;AAEO,SAAS,8BAA8B,KAAqB;AACjE,SAAO,KAAK,WAAW,GAAG,GAAG,iBAAiB;AAChD;AAEO,SAAS,YAAY,KAAqB;AAC/C,SAAO,KAAK,WAAW,GAAG,GAAG,UAAU;AACzC;AAEO,SAAS,WAAW,KAAa,WAA2B;AACjE,SAAO,KAAK,YAAY,GAAG,GAAG,SAAS;AACzC;AAEO,SAAS,UAAU,KAAa,WAA2B;AAChE,SAAO,KAAK,WAAW,KAAK,SAAS,GAAG,YAAY;AACtD;AAEO,SAAS,WAAW,KAAa,WAA2B;AACjE,SAAO,KAAK,WAAW,KAAK,SAAS,GAAG,SAAS;AACnD;AAEO,SAAS,eAAe,KAAa,WAAmB,SAAiB,QAAwB;AACtG,SAAO,KAAK,WAAW,KAAK,SAAS,GAAG,GAAG,OAAO,IAAI,MAAM,KAAK;AACnE;AAEO,SAAS,WAAW,KAAa,WAA2B;AACjE,SAAO,KAAK,WAAW,KAAK,SAAS,GAAG,SAAS;AACnD;AAEO,SAAS,WAAW,KAAa,WAA2B;AACjE,SAAO,KAAK,WAAW,KAAK,SAAS,GAAG,SAAS;AACnD;AAEO,SAAS,SAAS,KAAa,WAA2B;AAC/D,SAAO,KAAK,WAAW,KAAK,SAAS,GAAG,SAAS;AACnD;AAEO,SAAS,SAAS,KAAa,WAA2B;AAC/D,SAAO,KAAK,WAAW,KAAK,SAAS,GAAG,SAAS;AACnD;AAEO,SAAS,mBAAmB,KAAqB;AACtD,SAAO,KAAK,WAAW,GAAG,GAAG,eAAe;AAC9C;AAEO,SAAS,gBAAgB,KAAqB;AACnD,SAAO,KAAK,KAAK,MAAM,GAAG,SAAS,GAAG,CAAC,cAAc;AACvD;","names":[]}
package/dist/cli.js CHANGED
@@ -3,14 +3,11 @@ import {
3
3
  daemonLogPath,
4
4
  globalDir,
5
5
  socketPath
6
- } from "./chunk-FWHTKXN5.js";
6
+ } from "./chunk-N2BPQOO2.js";
7
7
 
8
8
  // src/cli/index.ts
9
9
  import { Command } from "commander";
10
10
 
11
- // src/cli/commands/start.ts
12
- import { execSync as execSync2 } from "child_process";
13
-
14
11
  // src/cli/client.ts
15
12
  import { connect as connect2 } from "net";
16
13
 
@@ -163,41 +160,59 @@ function rawSend(request) {
163
160
  });
164
161
  }
165
162
  async function sendRequest(request) {
166
- try {
167
- return await rawSend(request);
168
- } catch (err) {
169
- const code = err.code;
170
- if (code === "ENOENT" || code === "ECONNREFUSED") {
171
- if (process.platform !== "darwin") {
172
- throw new Error(
173
- `Sisyphus daemon is not running.
174
- Start it manually: sisyphusd &
175
- Or check logs at: ~/.sisyphus/daemon.log`
176
- );
163
+ const sleep2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
164
+ const MAX_ATTEMPTS = 5;
165
+ const RETRY_DELAY_MS = 2e3;
166
+ let installedDaemon = false;
167
+ let lastErr;
168
+ for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
169
+ try {
170
+ return await rawSend(request);
171
+ } catch (err) {
172
+ lastErr = err;
173
+ const code = err.code;
174
+ if (code !== "ENOENT" && code !== "ECONNREFUSED") {
175
+ throw err;
176
+ }
177
+ if (attempt === MAX_ATTEMPTS) break;
178
+ if (process.platform === "darwin" && !installedDaemon) {
179
+ installedDaemon = true;
180
+ await ensureDaemonInstalled();
181
+ await waitForDaemon(5e3);
182
+ } else {
183
+ process.stderr.write(`Daemon not ready, retrying (${attempt}/${MAX_ATTEMPTS - 1})...
184
+ `);
185
+ await sleep2(RETRY_DELAY_MS);
177
186
  }
178
- await ensureDaemonInstalled();
179
- await waitForDaemon(5e3);
180
- return rawSend(request);
181
187
  }
182
- throw err;
183
188
  }
189
+ if (process.platform !== "darwin") {
190
+ throw new Error(
191
+ `Sisyphus daemon is not running.
192
+ Start it manually: sisyphusd &
193
+ Or check logs at: ~/.sisyphus/daemon.log`
194
+ );
195
+ }
196
+ throw lastErr;
184
197
  }
185
198
 
186
- // src/cli/commands/start.ts
187
- function getTmuxSession() {
188
- try {
189
- return execSync2('tmux display-message -p "#{session_name}"', { encoding: "utf8" }).trim();
190
- } catch {
191
- throw new Error("Not running inside tmux");
199
+ // src/cli/tmux.ts
200
+ import { execSync as execSync2 } from "child_process";
201
+ function assertTmux() {
202
+ if (!process.env.TMUX) {
203
+ throw new Error("Not running inside a tmux pane. Sisyphus requires tmux.");
192
204
  }
193
205
  }
206
+ function getTmuxSession() {
207
+ assertTmux();
208
+ return execSync2('tmux display-message -p "#{session_name}"', { encoding: "utf8" }).trim();
209
+ }
194
210
  function getTmuxWindow() {
195
- try {
196
- return execSync2('tmux display-message -p "#{window_id}"', { encoding: "utf8" }).trim();
197
- } catch {
198
- throw new Error("Not running inside tmux");
199
- }
211
+ assertTmux();
212
+ return execSync2('tmux display-message -p "#{window_id}"', { encoding: "utf8" }).trim();
200
213
  }
214
+
215
+ // src/cli/commands/start.ts
201
216
  function registerStart(program2) {
202
217
  program2.command("start").description("Start a new sisyphus session").argument("<task>", "Task description for the orchestrator").action(async (task) => {
203
218
  const tmuxSession = getTmuxSession();
@@ -219,7 +234,8 @@ function registerStart(program2) {
219
234
 
220
235
  // src/cli/commands/spawn.ts
221
236
  function registerSpawn(program2) {
222
- program2.command("spawn").description("Spawn a new agent (orchestrator only)").option("--agent-type <type>", "Agent role label (default: worker)", "worker").requiredOption("--name <name>", "Agent name").requiredOption("--instruction <instruction>", "Task instruction for the agent").action(async (opts) => {
237
+ program2.command("spawn").description("Spawn a new agent (orchestrator only)").option("--agent-type <type>", "Agent role label (default: worker)", "worker").requiredOption("--name <name>", "Agent name").requiredOption("--instruction <instruction>", "Task instruction for the agent").option("--worktree", "Spawn agent in an isolated git worktree").action(async (opts) => {
238
+ assertTmux();
223
239
  const sessionId = process.env.SISYPHUS_SESSION_ID;
224
240
  if (!sessionId) {
225
241
  console.error("Error: SISYPHUS_SESSION_ID environment variable not set");
@@ -230,7 +246,8 @@ function registerSpawn(program2) {
230
246
  sessionId,
231
247
  agentType: opts.agentType,
232
248
  name: opts.name,
233
- instruction: opts.instruction
249
+ instruction: opts.instruction,
250
+ ...opts.worktree ? { worktree: true } : {}
234
251
  };
235
252
  const response = await sendRequest(request);
236
253
  if (response.ok) {
@@ -262,6 +279,7 @@ function readStdin() {
262
279
  // src/cli/commands/submit.ts
263
280
  function registerSubmit(program2) {
264
281
  program2.command("submit").description("Submit work report and exit (agent only)").option("--report <report>", "Work report (or pipe via stdin)").action(async (opts) => {
282
+ assertTmux();
265
283
  const sessionId = process.env.SISYPHUS_SESSION_ID;
266
284
  const agentId = process.env.SISYPHUS_AGENT_ID;
267
285
  if (!sessionId || !agentId) {
@@ -288,6 +306,7 @@ function registerSubmit(program2) {
288
306
  // src/cli/commands/yield.ts
289
307
  function registerYield(program2) {
290
308
  program2.command("yield").description("Yield control back to daemon (orchestrator only)").option("--prompt <text>", "Instructions for the next orchestrator cycle (or pipe via stdin)").action(async (opts) => {
309
+ assertTmux();
291
310
  const sessionId = process.env.SISYPHUS_SESSION_ID;
292
311
  if (!sessionId) {
293
312
  console.error("Error: SISYPHUS_SESSION_ID environment variable not set");
@@ -308,6 +327,7 @@ function registerYield(program2) {
308
327
  // src/cli/commands/complete.ts
309
328
  function registerComplete(program2) {
310
329
  program2.command("complete").description("Mark session as completed (orchestrator only)").requiredOption("--report <report>", "Final completion report").action(async (opts) => {
330
+ assertTmux();
311
331
  const sessionId = process.env.SISYPHUS_SESSION_ID;
312
332
  if (!sessionId) {
313
333
  console.error("Error: SISYPHUS_SESSION_ID environment variable not set");
@@ -317,7 +337,6 @@ function registerComplete(program2) {
317
337
  const response = await sendRequest(request);
318
338
  if (response.ok) {
319
339
  console.log("Session completed.");
320
- console.log("All panes will close.");
321
340
  } else {
322
341
  console.error(`Error: ${response.error}`);
323
342
  process.exit(1);
@@ -339,16 +358,8 @@ var STATUS_COLORS = {
339
358
  // red
340
359
  crashed: "\x1B[31m",
341
360
  // red
342
- lost: "\x1B[90m",
361
+ lost: "\x1B[90m"
343
362
  // gray
344
- draft: "\x1B[2m",
345
- // dim
346
- pending: "\x1B[90m",
347
- // gray
348
- in_progress: "\x1B[33m",
349
- // yellow
350
- done: "\x1B[32m"
351
- // green
352
363
  };
353
364
  var RESET = "\x1B[0m";
354
365
  var BOLD = "\x1B[1m";
@@ -390,10 +401,6 @@ function formatAgent(agent) {
390
401
  }
391
402
  return line;
392
403
  }
393
- function formatTask(task) {
394
- const status = colorize(task.status, task.status);
395
- return ` ${task.id}: ${task.description} [${status}]`;
396
- }
397
404
  function formatCycle(cycle) {
398
405
  const duration = cycle.completedAt ? ` ${DIM}(${formatDuration(cycle.timestamp, cycle.completedAt)})${RESET}` : ` ${DIM}(running)${RESET}`;
399
406
  const agents = cycle.agentsSpawned.length > 0 ? ` \u2014 agents: ${cycle.agentsSpawned.join(", ")}` : "";
@@ -417,13 +424,6 @@ ${BOLD}Session: ${session.id}${RESET}`);
417
424
  console.log(formatCycle(cycle));
418
425
  }
419
426
  }
420
- if (session.tasks.length > 0) {
421
- console.log(`
422
- ${BOLD}Tasks:${RESET}`);
423
- for (const task of session.tasks) {
424
- console.log(formatTask(task));
425
- }
426
- }
427
427
  if (session.agents.length > 0) {
428
428
  console.log(`
429
429
  ${BOLD}Agents:${RESET}`);
@@ -451,112 +451,50 @@ function registerStatus(program2) {
451
451
  });
452
452
  }
453
453
 
454
- // src/cli/commands/tasks.ts
455
- function getSessionId() {
456
- const sessionId = process.env.SISYPHUS_SESSION_ID;
457
- if (!sessionId) {
458
- console.error("Error: SISYPHUS_SESSION_ID environment variable not set");
459
- process.exit(1);
460
- }
461
- return sessionId;
462
- }
463
- var STATUS_COLORS2 = {
464
- draft: "\x1B[2m",
465
- // dim
466
- pending: "\x1B[90m",
467
- // gray
468
- in_progress: "\x1B[33m",
469
- // yellow
470
- done: "\x1B[32m"
471
- // green
472
- };
473
- var RESET2 = "\x1B[0m";
474
- function registerTasks(program2) {
475
- const tasks = program2.command("tasks").description("Manage session tasks");
476
- tasks.command("add").description("Add a new task").argument("[description]", "Task description (or pipe via stdin)").option("--status <status>", "Initial status (draft|pending)", "pending").action(async (descriptionArg, opts) => {
477
- const description = descriptionArg ?? await readStdin();
478
- if (!description) {
479
- console.error("Error: provide a description argument or pipe via stdin");
480
- process.exit(1);
481
- }
482
- const sessionId = getSessionId();
483
- const request = { type: "tasks_add", sessionId, description, status: opts.status !== "pending" ? opts.status : void 0 };
484
- const response = await sendRequest(request);
485
- if (response.ok) {
486
- const taskId = response.data?.taskId;
487
- console.log(`Task added: ${taskId} [${opts.status}]`);
488
- } else {
489
- console.error(`Error: ${response.error}`);
490
- if (response.error?.includes("Unknown session")) console.error("Hint: run `sisyphus list` to see active sessions.");
491
- process.exit(1);
492
- }
493
- });
494
- tasks.command("update").description("Update a task").argument("<task-id>", "Task ID (e.g. t1)").option("--status <status>", "New status (draft|pending|in_progress|done)").option("--description <description>", "New description").action(async (taskId, opts) => {
495
- if (!opts.status && !opts.description) {
496
- console.error("Error: provide --status and/or --description");
497
- process.exit(1);
498
- }
499
- const sessionId = getSessionId();
500
- const request = { type: "tasks_update", sessionId, taskId, status: opts.status, description: opts.description };
501
- const response = await sendRequest(request);
502
- if (response.ok) {
503
- const parts = [];
504
- if (opts.status) parts.push(`status \u2192 ${opts.status}`);
505
- if (opts.description) parts.push(`description updated`);
506
- console.log(`Task ${taskId}: ${parts.join(", ")}`);
507
- } else {
508
- console.error(`Error: ${response.error}`);
509
- if (response.error?.includes("not found")) console.error("Hint: run `sisyphus tasks list` to see current tasks.");
510
- if (response.error?.includes("Unknown session")) console.error("Hint: run `sisyphus list` to see active sessions.");
511
- process.exit(1);
512
- }
513
- });
514
- tasks.command("list").description("List all tasks").action(async () => {
515
- const sessionId = getSessionId();
516
- const request = { type: "tasks_list", sessionId };
517
- const response = await sendRequest(request);
518
- if (response.ok) {
519
- const taskList = response.data?.tasks ?? [];
520
- if (taskList.length === 0) {
521
- console.log("No tasks");
522
- return;
523
- }
524
- for (const task of taskList) {
525
- const color = STATUS_COLORS2[task.status] ?? "";
526
- console.log(` ${task.id}: ${task.description} [${color}${task.status}${RESET2}]`);
527
- }
528
- } else {
529
- console.error(`Error: ${response.error}`);
530
- if (response.error?.includes("Unknown session")) console.error("Hint: run `sisyphus list` to see active sessions.");
531
- process.exit(1);
532
- }
533
- });
534
- }
535
-
536
454
  // src/cli/commands/list.ts
537
- var STATUS_COLORS3 = {
455
+ import { basename } from "path";
456
+ var STATUS_COLORS2 = {
538
457
  active: "\x1B[32m",
539
458
  paused: "\x1B[33m",
540
459
  completed: "\x1B[36m"
541
460
  };
542
- var RESET3 = "\x1B[0m";
461
+ var RESET2 = "\x1B[0m";
543
462
  var BOLD2 = "\x1B[1m";
544
463
  var DIM2 = "\x1B[2m";
464
+ function truncateTask(task, max) {
465
+ if (task.length <= max) return task;
466
+ return task.slice(0, max - 1) + "\u2026";
467
+ }
545
468
  function registerList(program2) {
546
- program2.command("list").description("List all sessions").action(async () => {
547
- const request = { type: "list" };
469
+ program2.command("list").description("List sessions (defaults to current project)").option("-a, --all", "Show sessions from all projects").action(async (opts) => {
470
+ const cwd = process.cwd();
471
+ const request = { type: "list", cwd, all: opts.all };
548
472
  const response = await sendRequest(request);
549
473
  if (response.ok) {
550
474
  const sessions = response.data?.sessions ?? [];
475
+ const totalCount = response.data?.totalCount;
476
+ const filtered = response.data?.filtered;
551
477
  if (sessions.length === 0) {
552
- console.log("No sessions");
478
+ if (filtered && totalCount && totalCount > 0) {
479
+ console.log(`No sessions in this project. ${totalCount} session(s) in other projects.`);
480
+ console.log(`${DIM2}Run ${RESET2}sisyphus list --all${DIM2} to show all.${RESET2}`);
481
+ } else {
482
+ console.log("No sessions");
483
+ }
553
484
  return;
554
485
  }
555
486
  for (const s of sessions) {
556
- const color = STATUS_COLORS3[s.status] ?? "";
557
- const status = `${color}${s.status}${RESET3}`;
558
- const agents = `${DIM2}${s.agentCount} agent(s)${RESET3}`;
559
- console.log(` ${BOLD2}${s.id}${RESET3} ${status} ${agents} ${s.task}`);
487
+ const color = STATUS_COLORS2[s.status] ?? "";
488
+ const status = `${color}${s.status}${RESET2}`;
489
+ const agents = `${DIM2}${s.agentCount} agent(s)${RESET2}`;
490
+ const task = truncateTask(s.task, 60);
491
+ const cwdLabel = opts.all && s.cwd ? ` ${DIM2}${basename(s.cwd)}${RESET2}` : "";
492
+ console.log(` ${BOLD2}${s.id}${RESET2} ${status} ${agents} ${task}${cwdLabel}`);
493
+ }
494
+ if (filtered && totalCount && totalCount > sessions.length) {
495
+ const otherCount = totalCount - sessions.length;
496
+ console.log(`
497
+ ${DIM2}${otherCount} more session(s) in other projects. Run ${RESET2}sisyphus list --all${DIM2} to show all.${RESET2}`);
560
498
  }
561
499
  } else {
562
500
  console.error(`Error: ${response.error}`);
@@ -568,6 +506,7 @@ function registerList(program2) {
568
506
  // src/cli/commands/report.ts
569
507
  function registerReport(program2) {
570
508
  program2.command("report").description("Send a progress report without exiting (agent only)").option("--message <message>", "Progress report content").action(async (opts) => {
509
+ assertTmux();
571
510
  const sessionId = process.env.SISYPHUS_SESSION_ID;
572
511
  const agentId = process.env.SISYPHUS_AGENT_ID;
573
512
  if (!sessionId || !agentId) {
@@ -591,25 +530,10 @@ function registerReport(program2) {
591
530
  }
592
531
 
593
532
  // src/cli/commands/resume.ts
594
- import { execSync as execSync3 } from "child_process";
595
- function getTmuxSession2() {
596
- try {
597
- return execSync3('tmux display-message -p "#{session_name}"', { encoding: "utf8" }).trim();
598
- } catch {
599
- throw new Error("Not running inside tmux");
600
- }
601
- }
602
- function getTmuxWindow2() {
603
- try {
604
- return execSync3('tmux display-message -p "#{window_id}"', { encoding: "utf8" }).trim();
605
- } catch {
606
- throw new Error("Not running inside tmux");
607
- }
608
- }
609
533
  function registerResume(program2) {
610
534
  program2.command("resume").description("Resume a paused session").argument("<session-id>", "Session ID to resume").argument("[message]", "Additional instructions for the orchestrator").action(async (sessionId, message) => {
611
- const tmuxSession = getTmuxSession2();
612
- const tmuxWindow = getTmuxWindow2();
535
+ const tmuxSession = getTmuxSession();
536
+ const tmuxWindow = getTmuxWindow();
613
537
  const cwd = process.cwd();
614
538
  const request = { type: "resume", sessionId, cwd, tmuxSession, tmuxWindow, message };
615
539
  const response = await sendRequest(request);
@@ -678,7 +602,6 @@ registerReport(program);
678
602
  registerYield(program);
679
603
  registerComplete(program);
680
604
  registerStatus(program);
681
- registerTasks(program);
682
605
  registerList(program);
683
606
  registerResume(program);
684
607
  registerKill(program);