@os-eco/overstory-cli 0.7.4 → 0.7.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.
- package/package.json +1 -1
- package/src/commands/coordinator.test.ts +3 -1
- package/src/commands/coordinator.ts +6 -3
- package/src/commands/monitor.ts +4 -3
- package/src/commands/supervisor.ts +4 -3
- package/src/index.ts +1 -1
- package/src/runtimes/claude.test.ts +40 -0
- package/src/runtimes/claude.ts +8 -1
- package/src/runtimes/pi.test.ts +28 -0
- package/src/runtimes/pi.ts +5 -1
- package/src/runtimes/types.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@os-eco/overstory-cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"description": "Multi-agent orchestration for AI coding agents — spawn workers in git worktrees via tmux, coordinate through SQLite mail, merge with tiered conflict resolution. Pluggable runtime adapters for Claude Code, Pi, and more.",
|
|
5
5
|
"author": "Jaymin West",
|
|
6
6
|
"license": "MIT",
|
|
@@ -540,7 +540,9 @@ describe("startCoordinator", () => {
|
|
|
540
540
|
expect(calls.createSession).toHaveLength(1);
|
|
541
541
|
const cmd = calls.createSession[0]?.command ?? "";
|
|
542
542
|
expect(cmd).toContain("--append-system-prompt");
|
|
543
|
-
|
|
543
|
+
// File path is passed via $(cat ...) instead of inlining content (overstory#45)
|
|
544
|
+
expect(cmd).toContain("$(cat '");
|
|
545
|
+
expect(cmd).toContain("agent-defs/coordinator.md");
|
|
544
546
|
});
|
|
545
547
|
|
|
546
548
|
test("reads model from manifest instead of hardcoding", async () => {
|
|
@@ -363,17 +363,20 @@ async function startCoordinator(
|
|
|
363
363
|
// Inject the coordinator base definition via --append-system-prompt so the
|
|
364
364
|
// coordinator knows its role, hierarchy rules, and delegation patterns
|
|
365
365
|
// (overstory-gaio, overstory-0kwf).
|
|
366
|
+
// Pass the file path (not content) so the shell inside the tmux pane reads
|
|
367
|
+
// it via $(cat ...) — avoids tmux IPC "command too long" errors with large
|
|
368
|
+
// agent definitions (overstory#45).
|
|
366
369
|
const agentDefPath = join(projectRoot, ".overstory", "agent-defs", "coordinator.md");
|
|
367
370
|
const agentDefFile = Bun.file(agentDefPath);
|
|
368
|
-
let
|
|
371
|
+
let appendSystemPromptFile: string | undefined;
|
|
369
372
|
if (await agentDefFile.exists()) {
|
|
370
|
-
|
|
373
|
+
appendSystemPromptFile = agentDefPath;
|
|
371
374
|
}
|
|
372
375
|
const spawnCmd = runtime.buildSpawnCommand({
|
|
373
376
|
model: resolvedModel.model,
|
|
374
377
|
permissionMode: "bypass",
|
|
375
378
|
cwd: projectRoot,
|
|
376
|
-
|
|
379
|
+
appendSystemPromptFile,
|
|
377
380
|
env: {
|
|
378
381
|
...runtime.buildEnv(resolvedModel),
|
|
379
382
|
OVERSTORY_AGENT_NAME: COORDINATOR_NAME,
|
package/src/commands/monitor.ts
CHANGED
|
@@ -142,17 +142,18 @@ async function startMonitor(opts: { json: boolean; attach: boolean }): Promise<v
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
// Spawn tmux session at project root with Claude Code (interactive mode).
|
|
145
|
+
// Pass file path (not content) to avoid tmux "command too long" (overstory#45).
|
|
145
146
|
const agentDefPath = join(projectRoot, ".overstory", "agent-defs", "monitor.md");
|
|
146
147
|
const agentDefFile = Bun.file(agentDefPath);
|
|
147
|
-
let
|
|
148
|
+
let appendSystemPromptFile: string | undefined;
|
|
148
149
|
if (await agentDefFile.exists()) {
|
|
149
|
-
|
|
150
|
+
appendSystemPromptFile = agentDefPath;
|
|
150
151
|
}
|
|
151
152
|
const spawnCmd = runtime.buildSpawnCommand({
|
|
152
153
|
model: resolvedModel.model,
|
|
153
154
|
permissionMode: "bypass",
|
|
154
155
|
cwd: projectRoot,
|
|
155
|
-
|
|
156
|
+
appendSystemPromptFile,
|
|
156
157
|
env: {
|
|
157
158
|
...runtime.buildEnv(resolvedModel),
|
|
158
159
|
OVERSTORY_AGENT_NAME: MONITOR_NAME,
|
|
@@ -169,18 +169,19 @@ async function startSupervisor(opts: {
|
|
|
169
169
|
|
|
170
170
|
// Spawn tmux session at project root with Claude Code (interactive mode).
|
|
171
171
|
// Inject the supervisor base definition via --append-system-prompt.
|
|
172
|
+
// Pass file path (not content) to avoid tmux "command too long" (overstory#45).
|
|
172
173
|
const tmuxSession = `overstory-${config.project.name}-supervisor-${opts.name}`;
|
|
173
174
|
const agentDefPath = join(projectRoot, ".overstory", "agent-defs", "supervisor.md");
|
|
174
175
|
const agentDefFile = Bun.file(agentDefPath);
|
|
175
|
-
let
|
|
176
|
+
let appendSystemPromptFile: string | undefined;
|
|
176
177
|
if (await agentDefFile.exists()) {
|
|
177
|
-
|
|
178
|
+
appendSystemPromptFile = agentDefPath;
|
|
178
179
|
}
|
|
179
180
|
const spawnCmd = runtime.buildSpawnCommand({
|
|
180
181
|
model: resolvedModel.model,
|
|
181
182
|
permissionMode: "bypass",
|
|
182
183
|
cwd: projectRoot,
|
|
183
|
-
|
|
184
|
+
appendSystemPromptFile,
|
|
184
185
|
env: {
|
|
185
186
|
...runtime.buildEnv(resolvedModel),
|
|
186
187
|
OVERSTORY_AGENT_NAME: opts.name,
|
package/src/index.ts
CHANGED
|
@@ -45,7 +45,7 @@ import { OverstoryError, WorktreeError } from "./errors.ts";
|
|
|
45
45
|
import { jsonError } from "./json.ts";
|
|
46
46
|
import { brand, chalk, muted, setQuiet } from "./logging/color.ts";
|
|
47
47
|
|
|
48
|
-
export const VERSION = "0.7.
|
|
48
|
+
export const VERSION = "0.7.5";
|
|
49
49
|
|
|
50
50
|
const rawArgs = process.argv.slice(2);
|
|
51
51
|
|
|
@@ -73,6 +73,46 @@ describe("ClaudeRuntime", () => {
|
|
|
73
73
|
);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
test("with appendSystemPromptFile uses $(cat ...) expansion", () => {
|
|
77
|
+
const opts: SpawnOpts = {
|
|
78
|
+
model: "opus",
|
|
79
|
+
permissionMode: "bypass",
|
|
80
|
+
cwd: "/project",
|
|
81
|
+
env: {},
|
|
82
|
+
appendSystemPromptFile: "/project/.overstory/agent-defs/coordinator.md",
|
|
83
|
+
};
|
|
84
|
+
const cmd = runtime.buildSpawnCommand(opts);
|
|
85
|
+
expect(cmd).toBe(
|
|
86
|
+
`claude --model opus --permission-mode bypassPermissions --append-system-prompt "$(cat '/project/.overstory/agent-defs/coordinator.md')"`,
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("appendSystemPromptFile with single quotes in path", () => {
|
|
91
|
+
const opts: SpawnOpts = {
|
|
92
|
+
model: "opus",
|
|
93
|
+
permissionMode: "bypass",
|
|
94
|
+
cwd: "/project",
|
|
95
|
+
env: {},
|
|
96
|
+
appendSystemPromptFile: "/project/it's a path/agent.md",
|
|
97
|
+
};
|
|
98
|
+
const cmd = runtime.buildSpawnCommand(opts);
|
|
99
|
+
expect(cmd).toContain("$(cat '/project/it'\\''s a path/agent.md')");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("appendSystemPromptFile takes precedence over appendSystemPrompt", () => {
|
|
103
|
+
const opts: SpawnOpts = {
|
|
104
|
+
model: "opus",
|
|
105
|
+
permissionMode: "bypass",
|
|
106
|
+
cwd: "/project",
|
|
107
|
+
env: {},
|
|
108
|
+
appendSystemPromptFile: "/project/.overstory/agent-defs/coordinator.md",
|
|
109
|
+
appendSystemPrompt: "This inline content should be ignored",
|
|
110
|
+
};
|
|
111
|
+
const cmd = runtime.buildSpawnCommand(opts);
|
|
112
|
+
expect(cmd).toContain("$(cat ");
|
|
113
|
+
expect(cmd).not.toContain("This inline content should be ignored");
|
|
114
|
+
});
|
|
115
|
+
|
|
76
116
|
test("without appendSystemPrompt omits the flag", () => {
|
|
77
117
|
const opts: SpawnOpts = {
|
|
78
118
|
model: "haiku",
|
package/src/runtimes/claude.ts
CHANGED
|
@@ -54,7 +54,14 @@ export class ClaudeRuntime implements AgentRuntime {
|
|
|
54
54
|
const permMode = opts.permissionMode === "bypass" ? "bypassPermissions" : "default";
|
|
55
55
|
let cmd = `claude --model ${opts.model} --permission-mode ${permMode}`;
|
|
56
56
|
|
|
57
|
-
if (opts.
|
|
57
|
+
if (opts.appendSystemPromptFile) {
|
|
58
|
+
// Read from file at shell expansion time — avoids tmux IPC message size
|
|
59
|
+
// limits (~8-16KB) that cause "command too long" errors when large agent
|
|
60
|
+
// definitions are inlined. The $(cat ...) expands inside the tmux pane's
|
|
61
|
+
// shell, so the tmux IPC message only carries the short command string.
|
|
62
|
+
const escaped = opts.appendSystemPromptFile.replace(/'/g, "'\\''");
|
|
63
|
+
cmd += ` --append-system-prompt "$(cat '${escaped}')"`;
|
|
64
|
+
} else if (opts.appendSystemPrompt) {
|
|
58
65
|
// Single-quote the content for safe shell expansion.
|
|
59
66
|
// POSIX single-quoted strings cannot contain single quotes, so escape
|
|
60
67
|
// them using the standard technique: end quote, escaped quote, start quote.
|
package/src/runtimes/pi.test.ts
CHANGED
|
@@ -126,6 +126,34 @@ describe("PiRuntime", () => {
|
|
|
126
126
|
);
|
|
127
127
|
});
|
|
128
128
|
|
|
129
|
+
test("with appendSystemPromptFile uses $(cat ...) expansion", () => {
|
|
130
|
+
const opts: SpawnOpts = {
|
|
131
|
+
model: "opus",
|
|
132
|
+
permissionMode: "bypass",
|
|
133
|
+
cwd: "/project",
|
|
134
|
+
env: {},
|
|
135
|
+
appendSystemPromptFile: "/project/.overstory/agent-defs/coordinator.md",
|
|
136
|
+
};
|
|
137
|
+
const cmd = runtime.buildSpawnCommand(opts);
|
|
138
|
+
expect(cmd).toBe(
|
|
139
|
+
`pi --model anthropic/claude-opus-4-6 --append-system-prompt "$(cat '/project/.overstory/agent-defs/coordinator.md')"`,
|
|
140
|
+
);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("appendSystemPromptFile takes precedence over appendSystemPrompt", () => {
|
|
144
|
+
const opts: SpawnOpts = {
|
|
145
|
+
model: "opus",
|
|
146
|
+
permissionMode: "bypass",
|
|
147
|
+
cwd: "/project",
|
|
148
|
+
env: {},
|
|
149
|
+
appendSystemPromptFile: "/project/.overstory/agent-defs/coordinator.md",
|
|
150
|
+
appendSystemPrompt: "This inline content should be ignored",
|
|
151
|
+
};
|
|
152
|
+
const cmd = runtime.buildSpawnCommand(opts);
|
|
153
|
+
expect(cmd).toContain("$(cat ");
|
|
154
|
+
expect(cmd).not.toContain("This inline content should be ignored");
|
|
155
|
+
});
|
|
156
|
+
|
|
129
157
|
test("without appendSystemPrompt omits the flag", () => {
|
|
130
158
|
const opts: SpawnOpts = {
|
|
131
159
|
model: "haiku",
|
package/src/runtimes/pi.ts
CHANGED
|
@@ -75,7 +75,11 @@ export class PiRuntime implements AgentRuntime {
|
|
|
75
75
|
buildSpawnCommand(opts: SpawnOpts): string {
|
|
76
76
|
let cmd = `pi --model ${this.expandModel(opts.model)}`;
|
|
77
77
|
|
|
78
|
-
if (opts.
|
|
78
|
+
if (opts.appendSystemPromptFile) {
|
|
79
|
+
// Read from file at shell expansion time — avoids tmux command length limits.
|
|
80
|
+
const escaped = opts.appendSystemPromptFile.replace(/'/g, "'\\''");
|
|
81
|
+
cmd += ` --append-system-prompt "$(cat '${escaped}')"`;
|
|
82
|
+
} else if (opts.appendSystemPrompt) {
|
|
79
83
|
// POSIX single-quote escape: end quote, backslash-quote, start quote.
|
|
80
84
|
const escaped = opts.appendSystemPrompt.replace(/'/g, "'\\''");
|
|
81
85
|
cmd += ` --append-system-prompt '${escaped}'`;
|
package/src/runtimes/types.ts
CHANGED
|
@@ -15,6 +15,8 @@ export interface SpawnOpts {
|
|
|
15
15
|
systemPrompt?: string;
|
|
16
16
|
/** Optional system prompt suffix appended after the base instructions. */
|
|
17
17
|
appendSystemPrompt?: string;
|
|
18
|
+
/** Path to a file whose contents are appended as system prompt (avoids tmux command length limits). */
|
|
19
|
+
appendSystemPromptFile?: string;
|
|
18
20
|
/** Working directory for the spawned process. */
|
|
19
21
|
cwd: string;
|
|
20
22
|
/** Additional environment variables to pass to the spawned process. */
|