@itsaplan/runner 0.7.0 → 0.8.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 +19 -17
- package/dist/cli.js +74 -13
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -8,7 +8,8 @@ This package runs such agents on your own machine — one, or several at once.
|
|
|
8
8
|
- Polls your instance for the agent's queued runs. Runs each one with a coding agent CLI.
|
|
9
9
|
Reports the result.
|
|
10
10
|
- Has presets for Claude Code, Codex, opencode, Antigravity CLI, GitHub Copilot CLI,
|
|
11
|
-
Pi,
|
|
11
|
+
Pi, Oh My Pi (`omp`), and Mastra Code. Each preset sets the unattended flags and the
|
|
12
|
+
session resume.
|
|
12
13
|
- Runs your own `command` instead, if you prefer. The command takes the task on stdin.
|
|
13
14
|
- Answers the agent's chat. Sends the text and the tool calls while the CLI prints them.
|
|
14
15
|
- Sends the messages and the tool calls of a queued run to the issue while the run works.
|
|
@@ -23,9 +24,9 @@ of kind External. The key appears one time only, at creation.
|
|
|
23
24
|
**2. Enable MCP** for the project, in Settings, MCP Server. MCP is off by default. The
|
|
24
25
|
agent reads the issue and writes its result through it.
|
|
25
26
|
|
|
26
|
-
**3. Give the coding agent the address of that server.** Claude Code, Oh My Pi,
|
|
27
|
-
(through `pi-mcp-adapter`) read `.mcp.json` from the folder they run in. For
|
|
28
|
-
CLIs, see
|
|
27
|
+
**3. Give the coding agent the address of that server.** Claude Code, Oh My Pi, Mastra
|
|
28
|
+
Code, and Pi (through `pi-mcp-adapter`) read `.mcp.json` from the folder they run in. For
|
|
29
|
+
the other CLIs, see
|
|
29
30
|
[Coding agent setup](https://github.com/croffasia/itsaplan/blob/main/docs/runner.md).
|
|
30
31
|
|
|
31
32
|
```json
|
|
@@ -67,15 +68,16 @@ or mention it in a comment. The task then starts in your terminal.
|
|
|
67
68
|
`agent` names a CLI that the runner knows. The runner then builds the command itself: the
|
|
68
69
|
flags for an unattended run, and the session resume. Every preset keeps a chat session.
|
|
69
70
|
|
|
70
|
-
| Agent | Runs
|
|
71
|
-
| ------------- |
|
|
72
|
-
| `claude` | Claude Code
|
|
73
|
-
| `codex` | Codex CLI
|
|
74
|
-
| `opencode` | opencode
|
|
75
|
-
| `antigravity` | Antigravity CLI
|
|
76
|
-
| `copilot` | GitHub Copilot CLI
|
|
77
|
-
| `pi` | Pi
|
|
78
|
-
| `omp` | Oh My Pi
|
|
71
|
+
| Agent | Runs |
|
|
72
|
+
| ------------- | ---------------------------------------------------------------------------- |
|
|
73
|
+
| `claude` | [Claude Code](https://code.claude.com/docs/en/overview) |
|
|
74
|
+
| `codex` | [Codex CLI](https://github.com/openai/codex) |
|
|
75
|
+
| `opencode` | [opencode](https://opencode.ai) |
|
|
76
|
+
| `antigravity` | [Antigravity CLI](https://antigravity.google/docs/getting-started?tab=cli) |
|
|
77
|
+
| `copilot` | [GitHub Copilot CLI](https://github.com/github/copilot-cli) |
|
|
78
|
+
| `pi` | [Pi](https://pi.dev) |
|
|
79
|
+
| `omp` | [Oh My Pi](https://omp.sh) |
|
|
80
|
+
| `mastracode` | [Mastra Code](https://code.mastra.ai) |
|
|
79
81
|
|
|
80
82
|
Each preset needs the CLI's own MCP config.
|
|
81
83
|
[Coding agent setup](https://github.com/croffasia/itsaplan/blob/main/docs/runner.md) holds
|
|
@@ -273,8 +275,8 @@ npx -y @itsaplan/runner --agent claude
|
|
|
273
275
|
|
|
274
276
|
The server writes the task text. The text states what occurred, what to do, and to post
|
|
275
277
|
the result as a comment on the issue. Your own `command` receives the text on **stdin**. A
|
|
276
|
-
preset gives it to its CLI in the way that CLI accepts it: on stdin for `claude`, `codex
|
|
277
|
-
and `
|
|
278
|
+
preset gives it to its CLI in the way that CLI accepts it: on stdin for `claude`, `codex`,
|
|
279
|
+
`pi` and `mastracode`, as an argument for `antigravity`, `copilot`, `opencode` and `omp`.
|
|
278
280
|
|
|
279
281
|
The agent reads all other data through the MCP server at `$ITSAPLAN_URL/mcp`. The agent
|
|
280
282
|
sends `$ITSAPLAN_API_KEY` as a bearer token, and acts as its own user with its role.
|
|
@@ -323,8 +325,8 @@ error.
|
|
|
323
325
|
|
|
324
326
|
- `text` — all of stdout is the answer.
|
|
325
327
|
- `claude-stream-json`, `codex-jsonl`, `opencode-json`, `antigravity-stream-json`,
|
|
326
|
-
`copilot-json`, `pi-json` — the event stream of that CLI. `pi` and
|
|
327
|
-
`pi-json`. The runner reads the text and the tool calls from it.
|
|
328
|
+
`copilot-json`, `pi-json`, `mastracode-jsonl` — the event stream of that CLI. `pi` and
|
|
329
|
+
`omp` both use `pi-json`. The runner reads the text and the tool calls from it.
|
|
328
330
|
|
|
329
331
|
A preset sets `outputFormat` for you. Set it yourself only with your own `command`. If the
|
|
330
332
|
output does not agree with the format, the runner uses the output as plain text.
|
package/dist/cli.js
CHANGED
|
@@ -177,6 +177,19 @@ var PRESETS = {
|
|
|
177
177
|
...sessionId ? ["--resume", sessionId] : []
|
|
178
178
|
],
|
|
179
179
|
tail: ["--"]
|
|
180
|
+
},
|
|
181
|
+
mastracode: {
|
|
182
|
+
bin: "mastracode",
|
|
183
|
+
outputFormat: "mastracode-jsonl",
|
|
184
|
+
promptVia: "stdin",
|
|
185
|
+
head: (sessionId) => [
|
|
186
|
+
"--output",
|
|
187
|
+
"jsonl",
|
|
188
|
+
"--permission-mode",
|
|
189
|
+
"auto",
|
|
190
|
+
...sessionId ? ["--thread", sessionId] : []
|
|
191
|
+
],
|
|
192
|
+
tail: ["--prompt", "-"]
|
|
180
193
|
}
|
|
181
194
|
};
|
|
182
195
|
var PRESET_NAMES = Object.keys(PRESETS);
|
|
@@ -208,7 +221,8 @@ var OUTPUT_FORMATS = [
|
|
|
208
221
|
"opencode-json",
|
|
209
222
|
"antigravity-stream-json",
|
|
210
223
|
"copilot-json",
|
|
211
|
-
"pi-json"
|
|
224
|
+
"pi-json",
|
|
225
|
+
"mastracode-jsonl"
|
|
212
226
|
];
|
|
213
227
|
function presetOf(config) {
|
|
214
228
|
if (config.command || !config.agent)
|
|
@@ -529,6 +543,7 @@ function startListener(port, agents, log) {
|
|
|
529
543
|
var FLUSH_CHARS = 1500;
|
|
530
544
|
var DELTA_LIMIT = 12000;
|
|
531
545
|
var TOOL_TEXT_LIMIT = 32000;
|
|
546
|
+
var TERMINAL_CODES = /\x1b\[[0-?]*[ -/]*[@-~]/g;
|
|
532
547
|
|
|
533
548
|
class AnswerStream {
|
|
534
549
|
format;
|
|
@@ -537,6 +552,7 @@ class AnswerStream {
|
|
|
537
552
|
send;
|
|
538
553
|
messageId;
|
|
539
554
|
queued = [];
|
|
555
|
+
unsent = [];
|
|
540
556
|
text = "";
|
|
541
557
|
started = false;
|
|
542
558
|
line = "";
|
|
@@ -544,6 +560,7 @@ class AnswerStream {
|
|
|
544
560
|
openTextPart = "";
|
|
545
561
|
openToolCalls = new Set;
|
|
546
562
|
closedToolCalls = new Set;
|
|
563
|
+
mastraMessageId;
|
|
547
564
|
sawPartialText = false;
|
|
548
565
|
sawAnyText = false;
|
|
549
566
|
segment = "";
|
|
@@ -587,15 +604,13 @@ class AnswerStream {
|
|
|
587
604
|
}
|
|
588
605
|
async sendQueued() {
|
|
589
606
|
this.drainText();
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
await this.send(
|
|
596
|
-
|
|
597
|
-
this.queued.unshift(...batch);
|
|
598
|
-
throw err;
|
|
607
|
+
while (this.unsent.length > 0 || this.queued.length > 0) {
|
|
608
|
+
if (this.unsent.length === 0) {
|
|
609
|
+
this.unsent = this.queued;
|
|
610
|
+
this.queued = [];
|
|
611
|
+
}
|
|
612
|
+
await this.send(this.unsent);
|
|
613
|
+
this.unsent = [];
|
|
599
614
|
}
|
|
600
615
|
}
|
|
601
616
|
async finish(fallback) {
|
|
@@ -654,7 +669,9 @@ class AnswerStream {
|
|
|
654
669
|
try {
|
|
655
670
|
parsed = JSON.parse(trimmed);
|
|
656
671
|
} catch {
|
|
657
|
-
|
|
672
|
+
const plain = trimmed.replace(TERMINAL_CODES, "").trim();
|
|
673
|
+
if (plain)
|
|
674
|
+
this.appendText(`${plain}
|
|
658
675
|
`);
|
|
659
676
|
return;
|
|
660
677
|
}
|
|
@@ -680,6 +697,39 @@ class AnswerStream {
|
|
|
680
697
|
case "pi-json":
|
|
681
698
|
this.readPiLine(parsed);
|
|
682
699
|
break;
|
|
700
|
+
case "mastracode-jsonl":
|
|
701
|
+
this.readMastraLine(parsed);
|
|
702
|
+
break;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
readMastraLine(message) {
|
|
706
|
+
switch (message.type) {
|
|
707
|
+
case "thread_created":
|
|
708
|
+
if (message.thread?.id)
|
|
709
|
+
this.sessionId ??= message.thread.id;
|
|
710
|
+
return;
|
|
711
|
+
case "message_start":
|
|
712
|
+
if (message.message?.role === "assistant")
|
|
713
|
+
this.mastraMessageId = message.message.id;
|
|
714
|
+
return;
|
|
715
|
+
case "message_update":
|
|
716
|
+
if (message.id === this.mastraMessageId && message.event?.type === "text-delta") {
|
|
717
|
+
this.appendText(message.event.delta ?? "");
|
|
718
|
+
}
|
|
719
|
+
return;
|
|
720
|
+
case "tool_start":
|
|
721
|
+
if (message.toolCallId) {
|
|
722
|
+
this.pushToolCall(message.toolCallId, message.toolName ?? "tool", JSON.stringify(message.args ?? {}));
|
|
723
|
+
}
|
|
724
|
+
return;
|
|
725
|
+
case "tool_end":
|
|
726
|
+
if (message.toolCallId)
|
|
727
|
+
this.pushToolResult(message.toolCallId, toolResultText(message.result));
|
|
728
|
+
return;
|
|
729
|
+
case "result":
|
|
730
|
+
if (!this.sawAnyText)
|
|
731
|
+
this.appendText(message.text || message.error?.message || "");
|
|
732
|
+
return;
|
|
683
733
|
}
|
|
684
734
|
}
|
|
685
735
|
readPiLine(message) {
|
|
@@ -704,7 +754,7 @@ class AnswerStream {
|
|
|
704
754
|
if (!message.toolCallId || this.closedToolCalls.has(message.toolCallId))
|
|
705
755
|
return;
|
|
706
756
|
this.closedToolCalls.add(message.toolCallId);
|
|
707
|
-
this.pushToolResult(message.toolCallId,
|
|
757
|
+
this.pushToolResult(message.toolCallId, toolResultText(message.result));
|
|
708
758
|
return;
|
|
709
759
|
}
|
|
710
760
|
case "message_end":
|
|
@@ -970,8 +1020,19 @@ class UsageReader {
|
|
|
970
1020
|
case "pi-json":
|
|
971
1021
|
this.readPi(parsed);
|
|
972
1022
|
return;
|
|
1023
|
+
case "mastracode-jsonl":
|
|
1024
|
+
this.readMastra(parsed);
|
|
1025
|
+
return;
|
|
973
1026
|
}
|
|
974
1027
|
}
|
|
1028
|
+
readMastra(message) {
|
|
1029
|
+
if (message.type !== "usage_update" || !message.usage)
|
|
1030
|
+
return;
|
|
1031
|
+
this.last = {
|
|
1032
|
+
inputTokens: message.usage.promptTokens ?? 0,
|
|
1033
|
+
outputTokens: message.usage.completionTokens ?? 0
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
975
1036
|
readClaude(message) {
|
|
976
1037
|
const event = message.type === "stream_event" ? message.event : undefined;
|
|
977
1038
|
if (!event)
|
|
@@ -1042,7 +1103,7 @@ function textOfResult(content) {
|
|
|
1042
1103
|
}
|
|
1043
1104
|
return "";
|
|
1044
1105
|
}
|
|
1045
|
-
function
|
|
1106
|
+
function toolResultText(result) {
|
|
1046
1107
|
if (result && typeof result === "object" && !Array.isArray(result) && "content" in result) {
|
|
1047
1108
|
return textOfResult(result.content);
|
|
1048
1109
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itsaplan/runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Runs an Itsaplan external agent's queued tasks and answers its chat on your own machine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"itsaplan",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"antigravity",
|
|
21
21
|
"opencode",
|
|
22
22
|
"pi",
|
|
23
|
-
"omp"
|
|
23
|
+
"omp",
|
|
24
|
+
"mastracode"
|
|
24
25
|
],
|
|
25
26
|
"homepage": "https://github.com/croffasia/itsaplan/tree/main/packages/runner#readme",
|
|
26
27
|
"repository": {
|