@saga-ai/cli 0.7.0 → 0.7.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.
- package/README.md +24 -0
- package/dist/cli.cjs +21 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ npx @saga-ai/cli init
|
|
|
16
16
|
npx @saga-ai/cli find <query>
|
|
17
17
|
npx @saga-ai/cli worktree <epic-slug> <story-slug>
|
|
18
18
|
npx @saga-ai/cli implement <story-slug>
|
|
19
|
+
npx @saga-ai/cli sessions list
|
|
19
20
|
npx @saga-ai/cli dashboard
|
|
20
21
|
```
|
|
21
22
|
|
|
@@ -49,6 +50,7 @@ saga find auth --type epic
|
|
|
49
50
|
|
|
50
51
|
Options:
|
|
51
52
|
- `--type <type>` - Type to search for: `epic` or `story` (default: story)
|
|
53
|
+
- `--status <status>` - Filter stories by status: `ready`, `completed`, `blocked`, etc.
|
|
52
54
|
|
|
53
55
|
Returns JSON with:
|
|
54
56
|
- `found: true` + `data` - Single match found
|
|
@@ -83,15 +85,37 @@ saga implement my-story
|
|
|
83
85
|
saga implement my-story --max-cycles 5
|
|
84
86
|
saga implement my-story --max-time 30
|
|
85
87
|
saga implement my-story --model sonnet
|
|
88
|
+
saga implement my-story --attached --stream
|
|
86
89
|
```
|
|
87
90
|
|
|
88
91
|
Options:
|
|
89
92
|
- `--max-cycles <n>` - Maximum number of worker cycles (default: 10)
|
|
90
93
|
- `--max-time <n>` - Maximum time in minutes (default: 60)
|
|
91
94
|
- `--model <name>` - Model to use (default: opus)
|
|
95
|
+
- `--attached` - Run in attached mode (synchronous). Default is detached (runs in tmux session)
|
|
96
|
+
- `--stream` - Stream worker output to stdout (only works with `--attached`)
|
|
97
|
+
|
|
98
|
+
By default, `implement` runs in **detached mode** using a tmux session. This allows the worker to continue running even if your terminal disconnects. Use `saga sessions` to monitor detached sessions.
|
|
92
99
|
|
|
93
100
|
**Note:** Requires `SAGA_PLUGIN_ROOT` environment variable to be set. This is automatically configured when running via the SAGA plugin.
|
|
94
101
|
|
|
102
|
+
### `saga sessions`
|
|
103
|
+
|
|
104
|
+
Manage tmux sessions created by detached `implement` runs.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
saga sessions list # List all SAGA sessions
|
|
108
|
+
saga sessions status <name> # Check if session is running
|
|
109
|
+
saga sessions logs <name> # Stream session output
|
|
110
|
+
saga sessions kill <name> # Terminate a session
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Subcommands:
|
|
114
|
+
- `list` - Returns JSON array of all SAGA sessions with name, status, and output file
|
|
115
|
+
- `status <name>` - Returns JSON `{running: boolean}` for the session
|
|
116
|
+
- `logs <name>` - Streams the session output file via `tail -f`
|
|
117
|
+
- `kill <name>` - Terminates the session, returns JSON `{killed: boolean}`
|
|
118
|
+
|
|
95
119
|
### `saga dashboard`
|
|
96
120
|
|
|
97
121
|
Start the SAGA dashboard server for viewing epics, stories, and progress.
|
package/dist/cli.cjs
CHANGED
|
@@ -1042,6 +1042,22 @@ function formatStreamLine(line) {
|
|
|
1042
1042
|
return null;
|
|
1043
1043
|
}
|
|
1044
1044
|
}
|
|
1045
|
+
function extractStructuredOutputFromToolCall(lines) {
|
|
1046
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
1047
|
+
try {
|
|
1048
|
+
const data = JSON.parse(lines[i]);
|
|
1049
|
+
if (data.type === "assistant" && data.message?.content) {
|
|
1050
|
+
for (const block of data.message.content) {
|
|
1051
|
+
if (block.type === "tool_use" && block.name === "StructuredOutput") {
|
|
1052
|
+
return block.input;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
} catch {
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
return null;
|
|
1060
|
+
}
|
|
1045
1061
|
function parseStreamingResult(buffer) {
|
|
1046
1062
|
const lines = buffer.split("\n").filter((line) => line.trim());
|
|
1047
1063
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
@@ -1051,10 +1067,13 @@ function parseStreamingResult(buffer) {
|
|
|
1051
1067
|
if (data.is_error) {
|
|
1052
1068
|
throw new Error(`Worker failed: ${data.result || "Unknown error"}`);
|
|
1053
1069
|
}
|
|
1054
|
-
|
|
1070
|
+
let output = data.structured_output;
|
|
1071
|
+
if (!output) {
|
|
1072
|
+
output = extractStructuredOutputFromToolCall(lines);
|
|
1073
|
+
}
|
|
1074
|
+
if (!output) {
|
|
1055
1075
|
throw new Error("Worker result missing structured_output");
|
|
1056
1076
|
}
|
|
1057
|
-
const output = data.structured_output;
|
|
1058
1077
|
if (!VALID_STATUSES.has(output.status)) {
|
|
1059
1078
|
throw new Error(`Invalid status: ${output.status}`);
|
|
1060
1079
|
}
|