sisyphi 0.1.18 → 0.1.21
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/dist/cli.js +32 -21
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +153 -93
- package/dist/daemon.js.map +1 -1
- package/dist/templates/agent-plugin/agents/review-plan.md +94 -68
- package/dist/templates/agent-plugin/agents/spec-draft.md +27 -51
- package/dist/templates/agent-plugin/hooks/hooks.json +1 -13
- package/dist/templates/agent-plugin/hooks/intercept-send-message.sh +4 -55
- package/dist/templates/agent-suffix.md +10 -6
- package/dist/templates/orchestrator-plugin/scripts/block-task.sh +8 -1
- package/dist/templates/orchestrator.md +22 -18
- package/package.json +1 -1
- package/templates/agent-plugin/agents/review-plan.md +94 -68
- package/templates/agent-plugin/agents/spec-draft.md +27 -51
- package/templates/agent-plugin/hooks/hooks.json +1 -13
- package/templates/agent-plugin/hooks/intercept-send-message.sh +4 -55
- package/templates/agent-suffix.md +10 -6
- package/templates/orchestrator-plugin/scripts/block-task.sh +8 -1
- package/templates/orchestrator.md +22 -18
package/dist/daemon.js
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
} from "./chunk-LTAW6OWS.js";
|
|
22
22
|
|
|
23
23
|
// src/daemon/index.ts
|
|
24
|
-
import { mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync6, unlinkSync as unlinkSync3, existsSync as
|
|
24
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync6, unlinkSync as unlinkSync3, existsSync as existsSync7 } from "fs";
|
|
25
25
|
import { execSync as execSync4 } from "child_process";
|
|
26
26
|
import { setTimeout as sleep } from "timers/promises";
|
|
27
27
|
|
|
@@ -46,12 +46,12 @@ function loadConfig(cwd) {
|
|
|
46
46
|
|
|
47
47
|
// src/daemon/server.ts
|
|
48
48
|
import { createServer } from "net";
|
|
49
|
-
import { unlinkSync, existsSync as
|
|
49
|
+
import { unlinkSync, existsSync as existsSync6, writeFileSync as writeFileSync4, readFileSync as readFileSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
50
50
|
import { join as join4 } from "path";
|
|
51
51
|
|
|
52
52
|
// src/daemon/session-manager.ts
|
|
53
53
|
import { v4 as uuidv4 } from "uuid";
|
|
54
|
-
import { existsSync as
|
|
54
|
+
import { existsSync as existsSync5, readdirSync as readdirSync4, rmSync as rmSync2 } from "fs";
|
|
55
55
|
|
|
56
56
|
// src/daemon/state.ts
|
|
57
57
|
import { randomUUID } from "crypto";
|
|
@@ -95,7 +95,7 @@ function atomicWrite(filePath, data) {
|
|
|
95
95
|
writeFileSync(tmpPath, data, "utf-8");
|
|
96
96
|
renameSync(tmpPath, filePath);
|
|
97
97
|
}
|
|
98
|
-
function createSession(id, task, cwd) {
|
|
98
|
+
function createSession(id, task, cwd, context) {
|
|
99
99
|
const dir = sessionDir(cwd, id);
|
|
100
100
|
mkdirSync(dir, { recursive: true });
|
|
101
101
|
mkdirSync(contextDir(cwd, id), { recursive: true });
|
|
@@ -106,6 +106,7 @@ function createSession(id, task, cwd) {
|
|
|
106
106
|
const session = {
|
|
107
107
|
id,
|
|
108
108
|
task,
|
|
109
|
+
...context ? { context } : {},
|
|
109
110
|
cwd,
|
|
110
111
|
status: "active",
|
|
111
112
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -203,13 +204,10 @@ async function completeOrchestratorCycle(cwd, sessionId, nextPrompt) {
|
|
|
203
204
|
}
|
|
204
205
|
|
|
205
206
|
// src/daemon/orchestrator.ts
|
|
206
|
-
import { existsSync, readdirSync, readFileSync as
|
|
207
|
+
import { existsSync, readdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
207
208
|
import { resolve } from "path";
|
|
208
209
|
|
|
209
210
|
// src/daemon/colors.ts
|
|
210
|
-
import { readFileSync as readFileSync3 } from "fs";
|
|
211
|
-
import { homedir } from "os";
|
|
212
|
-
import { join as join2 } from "path";
|
|
213
211
|
var ORCHESTRATOR_COLOR = "yellow";
|
|
214
212
|
var AGENT_PALETTE = ["blue", "green", "magenta", "cyan", "red", "white"];
|
|
215
213
|
var TMUX_COLOR_MAP = {
|
|
@@ -229,56 +227,6 @@ function getNextColor(sessionId) {
|
|
|
229
227
|
function resetColors(sessionId) {
|
|
230
228
|
sessionColorIndex.delete(sessionId);
|
|
231
229
|
}
|
|
232
|
-
function extractFrontmatterColor(content) {
|
|
233
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
234
|
-
if (!match) return null;
|
|
235
|
-
const colorMatch = match[1].match(/^color:\s*(.+)$/m);
|
|
236
|
-
return colorMatch ? colorMatch[1].trim() : null;
|
|
237
|
-
}
|
|
238
|
-
function findPluginInstallPath(namespace) {
|
|
239
|
-
try {
|
|
240
|
-
const registryPath2 = join2(homedir(), ".claude", "plugins", "installed_plugins.json");
|
|
241
|
-
const registry = JSON.parse(readFileSync3(registryPath2, "utf-8"));
|
|
242
|
-
for (const key of Object.keys(registry)) {
|
|
243
|
-
if (key.startsWith(`${namespace}@`)) {
|
|
244
|
-
return registry[key].installPath ?? null;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
} catch {
|
|
248
|
-
}
|
|
249
|
-
return null;
|
|
250
|
-
}
|
|
251
|
-
function resolveAgentTypeColor(agentType, pluginDir, cwd) {
|
|
252
|
-
if (!agentType) return null;
|
|
253
|
-
let namespace;
|
|
254
|
-
let name;
|
|
255
|
-
if (agentType.includes(":")) {
|
|
256
|
-
[namespace, name] = agentType.split(":", 2);
|
|
257
|
-
} else {
|
|
258
|
-
name = agentType;
|
|
259
|
-
}
|
|
260
|
-
const searchPaths = [];
|
|
261
|
-
if (namespace) {
|
|
262
|
-
searchPaths.push(join2(pluginDir, "agents", `${name}.md`));
|
|
263
|
-
const installPath = findPluginInstallPath(namespace);
|
|
264
|
-
if (installPath) {
|
|
265
|
-
searchPaths.push(join2(installPath, "agents", `${name}.md`));
|
|
266
|
-
}
|
|
267
|
-
} else {
|
|
268
|
-
searchPaths.push(join2(cwd, ".claude", "agents", `${name}.md`));
|
|
269
|
-
searchPaths.push(join2(homedir(), ".claude", "agents", `${name}.md`));
|
|
270
|
-
searchPaths.push(join2(pluginDir, "agents", `${name}.md`));
|
|
271
|
-
}
|
|
272
|
-
for (const path of searchPaths) {
|
|
273
|
-
try {
|
|
274
|
-
const content = readFileSync3(path, "utf-8");
|
|
275
|
-
const color = extractFrontmatterColor(content);
|
|
276
|
-
if (color) return normalizeTmuxColor(color);
|
|
277
|
-
} catch {
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
return null;
|
|
281
|
-
}
|
|
282
230
|
|
|
283
231
|
// src/daemon/tmux.ts
|
|
284
232
|
import { execSync } from "child_process";
|
|
@@ -296,9 +244,13 @@ function execSafe(cmd) {
|
|
|
296
244
|
return null;
|
|
297
245
|
}
|
|
298
246
|
}
|
|
299
|
-
function createPane(windowTarget, cwd) {
|
|
247
|
+
function createPane(windowTarget, cwd, position = "right") {
|
|
300
248
|
const cwdFlag = cwd ? ` -c ${shellQuote(cwd)}` : "";
|
|
301
|
-
const
|
|
249
|
+
const panes = listPanes(windowTarget);
|
|
250
|
+
const target = position === "left" ? panes[0]?.paneId : panes[panes.length - 1]?.paneId;
|
|
251
|
+
const targetFlag = target ? ` -t "${target}"` : ` -t "${windowTarget}"`;
|
|
252
|
+
const beforeFlag = position === "left" ? "b" : "";
|
|
253
|
+
const paneId = exec(`tmux split-window -h${beforeFlag}${targetFlag}${cwdFlag} -P -F "#{pane_id}"`);
|
|
302
254
|
execSafe(`tmux select-layout -t "${windowTarget}" even-horizontal`);
|
|
303
255
|
return paneId;
|
|
304
256
|
}
|
|
@@ -381,10 +333,10 @@ function setOrchestratorPaneId(sessionId, paneId) {
|
|
|
381
333
|
function loadOrchestratorPrompt(cwd) {
|
|
382
334
|
const projectPath = projectOrchestratorPromptPath(cwd);
|
|
383
335
|
if (existsSync(projectPath)) {
|
|
384
|
-
return
|
|
336
|
+
return readFileSync3(projectPath, "utf-8");
|
|
385
337
|
}
|
|
386
338
|
const bundledPath = resolve(import.meta.dirname, "../templates/orchestrator.md");
|
|
387
|
-
return
|
|
339
|
+
return readFileSync3(bundledPath, "utf-8");
|
|
388
340
|
}
|
|
389
341
|
function formatStateForOrchestrator(session) {
|
|
390
342
|
const shortId = session.id.slice(0, 8);
|
|
@@ -436,11 +388,15 @@ function formatStateForOrchestrator(session) {
|
|
|
436
388
|
${wtLines}`;
|
|
437
389
|
}
|
|
438
390
|
const worktreeHint = existsSync(worktreeConfigPath(session.cwd)) ? "Worktree config active (`.sisyphus/worktree.json`). Use `--worktree` flag with `sisyphus spawn` to isolate agents in their own worktrees. Recommended for feature work, especially with potential file overlap." : "No worktree configuration found. If this session involves parallel work where agents may edit overlapping files, use the `git-management` skill to set up `.sisyphus/worktree.json` and enable worktree isolation.";
|
|
391
|
+
const contextSection = session.context ? `
|
|
392
|
+
## Background Context
|
|
393
|
+
${session.context}
|
|
394
|
+
` : "";
|
|
439
395
|
return `<state>
|
|
440
396
|
session: ${shortId} (cycle ${cycleNum})
|
|
441
397
|
task: ${session.task}
|
|
442
398
|
status: ${session.status}
|
|
443
|
-
|
|
399
|
+
${contextSection}
|
|
444
400
|
## Plan
|
|
445
401
|
${planRef}
|
|
446
402
|
|
|
@@ -494,8 +450,8 @@ Review the current session and delegate the next cycle of work.`;
|
|
|
494
450
|
writeFileSync2(userPromptFilePath, userPrompt, "utf-8");
|
|
495
451
|
const pluginPath = resolve(import.meta.dirname, "../templates/orchestrator-plugin");
|
|
496
452
|
const settingsPath = resolve(import.meta.dirname, "../templates/orchestrator-settings.json");
|
|
497
|
-
const claudeCmd = `claude --dangerously-skip-permissions --
|
|
498
|
-
const paneId = createPane(windowId, cwd);
|
|
453
|
+
const claudeCmd = `claude --dangerously-skip-permissions --settings "${settingsPath}" --plugin-dir "${pluginPath}" --append-system-prompt "$(cat '${promptFilePath}')" "$(cat '${userPromptFilePath}')"`;
|
|
454
|
+
const paneId = createPane(windowId, cwd, "left");
|
|
499
455
|
sessionOrchestratorPane.set(sessionId, paneId);
|
|
500
456
|
registerPane(paneId, sessionId, "orchestrator");
|
|
501
457
|
setPaneTitle(paneId, `Sisyphus`);
|
|
@@ -546,13 +502,13 @@ function cleanupSessionMaps(sessionId) {
|
|
|
546
502
|
}
|
|
547
503
|
|
|
548
504
|
// src/daemon/agent.ts
|
|
549
|
-
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync3, existsSync as
|
|
505
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync3, existsSync as existsSync4 } from "fs";
|
|
550
506
|
import { resolve as resolve2 } from "path";
|
|
551
507
|
|
|
552
508
|
// src/daemon/worktree.ts
|
|
553
509
|
import { execSync as execSync2 } from "child_process";
|
|
554
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as
|
|
555
|
-
import { dirname as dirname2, join as
|
|
510
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync4, readdirSync as readdirSync2, rmSync } from "fs";
|
|
511
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
556
512
|
var EXEC_ENV2 = {
|
|
557
513
|
...process.env,
|
|
558
514
|
PATH: `/opt/homebrew/bin:/usr/local/bin:${process.env["PATH"] ?? "/usr/bin:/bin"}`
|
|
@@ -572,7 +528,7 @@ function shellQuote2(s) {
|
|
|
572
528
|
}
|
|
573
529
|
function loadWorktreeConfig(cwd) {
|
|
574
530
|
try {
|
|
575
|
-
const content =
|
|
531
|
+
const content = readFileSync4(worktreeConfigPath(cwd), "utf-8");
|
|
576
532
|
return JSON.parse(content);
|
|
577
533
|
} catch {
|
|
578
534
|
return null;
|
|
@@ -580,7 +536,7 @@ function loadWorktreeConfig(cwd) {
|
|
|
580
536
|
}
|
|
581
537
|
function createWorktreeShell(cwd, sessionId, agentId) {
|
|
582
538
|
const branchName = `sisyphus/${sessionId.slice(0, 8)}/${agentId}`;
|
|
583
|
-
const worktreePath =
|
|
539
|
+
const worktreePath = join2(worktreeBaseDir(cwd), sessionId.slice(0, 8), agentId);
|
|
584
540
|
mkdirSync2(dirname2(worktreePath), { recursive: true });
|
|
585
541
|
execSafe2(`git -C ${shellQuote2(cwd)} worktree prune`);
|
|
586
542
|
if (existsSync2(worktreePath)) {
|
|
@@ -594,16 +550,16 @@ function createWorktreeShell(cwd, sessionId, agentId) {
|
|
|
594
550
|
function bootstrapWorktree(cwd, worktreePath, config) {
|
|
595
551
|
if (config.copy) {
|
|
596
552
|
for (const entry of config.copy) {
|
|
597
|
-
const dest =
|
|
553
|
+
const dest = join2(worktreePath, entry);
|
|
598
554
|
mkdirSync2(dirname2(dest), { recursive: true });
|
|
599
|
-
execSafe2(`cp -r ${shellQuote2(
|
|
555
|
+
execSafe2(`cp -r ${shellQuote2(join2(cwd, entry))} ${shellQuote2(dest)}`);
|
|
600
556
|
}
|
|
601
557
|
}
|
|
602
558
|
if (config.clone) {
|
|
603
559
|
for (const entry of config.clone) {
|
|
604
|
-
const dest =
|
|
560
|
+
const dest = join2(worktreePath, entry);
|
|
605
561
|
mkdirSync2(dirname2(dest), { recursive: true });
|
|
606
|
-
const src = shellQuote2(
|
|
562
|
+
const src = shellQuote2(join2(cwd, entry));
|
|
607
563
|
const dstQ = shellQuote2(dest);
|
|
608
564
|
if (execSafe2(`cp -Rc ${src} ${dstQ}`) === null) {
|
|
609
565
|
execSafe2(`cp -r ${src} ${dstQ}`);
|
|
@@ -612,9 +568,9 @@ function bootstrapWorktree(cwd, worktreePath, config) {
|
|
|
612
568
|
}
|
|
613
569
|
if (config.symlink) {
|
|
614
570
|
for (const entry of config.symlink) {
|
|
615
|
-
const dest =
|
|
571
|
+
const dest = join2(worktreePath, entry);
|
|
616
572
|
mkdirSync2(dirname2(dest), { recursive: true });
|
|
617
|
-
execSafe2(`ln -s ${shellQuote2(
|
|
573
|
+
execSafe2(`ln -s ${shellQuote2(join2(cwd, entry))} ${shellQuote2(dest)}`);
|
|
618
574
|
}
|
|
619
575
|
}
|
|
620
576
|
if (config.init) {
|
|
@@ -697,6 +653,93 @@ function countWorktreeAgents(agents) {
|
|
|
697
653
|
return agents.filter((a) => a.worktreePath && a.status === "running").length;
|
|
698
654
|
}
|
|
699
655
|
|
|
656
|
+
// src/daemon/frontmatter.ts
|
|
657
|
+
import { readFileSync as readFileSync5, existsSync as existsSync3 } from "fs";
|
|
658
|
+
import { homedir } from "os";
|
|
659
|
+
import { join as join3 } from "path";
|
|
660
|
+
function detectProvider(model) {
|
|
661
|
+
if (!model) return "anthropic";
|
|
662
|
+
if (/^(gpt-|codex-)/.test(model)) return "openai";
|
|
663
|
+
return "anthropic";
|
|
664
|
+
}
|
|
665
|
+
function parseAgentFrontmatter(content) {
|
|
666
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
667
|
+
if (!match) return {};
|
|
668
|
+
const block = match[1];
|
|
669
|
+
const fm = {};
|
|
670
|
+
const str = (key) => {
|
|
671
|
+
const m = block.match(new RegExp(`^${key}:\\s*(.+)$`, "m"));
|
|
672
|
+
return m ? m[1].trim() : void 0;
|
|
673
|
+
};
|
|
674
|
+
fm.name = str("name");
|
|
675
|
+
fm.model = str("model");
|
|
676
|
+
fm.color = str("color");
|
|
677
|
+
fm.description = str("description");
|
|
678
|
+
fm.permissionMode = str("permissionMode");
|
|
679
|
+
const skillsMatch = block.match(/^skills:\s*\n((?:\s+-\s+.+\n?)*)/m);
|
|
680
|
+
if (skillsMatch) {
|
|
681
|
+
fm.skills = skillsMatch[1].split("\n").map((line) => line.replace(/^\s+-\s+/, "").trim()).filter(Boolean);
|
|
682
|
+
}
|
|
683
|
+
return fm;
|
|
684
|
+
}
|
|
685
|
+
function extractAgentBody(content) {
|
|
686
|
+
const match = content.match(/^---\n[\s\S]*?\n---\n?([\s\S]*)$/);
|
|
687
|
+
return match ? match[1].trim() : content.trim();
|
|
688
|
+
}
|
|
689
|
+
function findPluginInstallPath(namespace) {
|
|
690
|
+
try {
|
|
691
|
+
const registryPath2 = join3(homedir(), ".claude", "plugins", "installed_plugins.json");
|
|
692
|
+
const registry = JSON.parse(readFileSync5(registryPath2, "utf-8"));
|
|
693
|
+
for (const key of Object.keys(registry)) {
|
|
694
|
+
if (key.startsWith(`${namespace}@`)) {
|
|
695
|
+
return registry[key].installPath ?? null;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
} catch {
|
|
699
|
+
}
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
702
|
+
function resolveAgentTypePath(agentType, pluginDir, cwd) {
|
|
703
|
+
if (!agentType) return null;
|
|
704
|
+
let namespace;
|
|
705
|
+
let name;
|
|
706
|
+
if (agentType.includes(":")) {
|
|
707
|
+
[namespace, name] = agentType.split(":", 2);
|
|
708
|
+
} else {
|
|
709
|
+
name = agentType;
|
|
710
|
+
}
|
|
711
|
+
const searchPaths = [];
|
|
712
|
+
if (namespace) {
|
|
713
|
+
searchPaths.push(join3(pluginDir, "agents", `${name}.md`));
|
|
714
|
+
const installPath = findPluginInstallPath(namespace);
|
|
715
|
+
if (installPath) {
|
|
716
|
+
searchPaths.push(join3(installPath, "agents", `${name}.md`));
|
|
717
|
+
}
|
|
718
|
+
} else {
|
|
719
|
+
searchPaths.push(join3(cwd, ".claude", "agents", `${name}.md`));
|
|
720
|
+
searchPaths.push(join3(homedir(), ".claude", "agents", `${name}.md`));
|
|
721
|
+
searchPaths.push(join3(pluginDir, "agents", `${name}.md`));
|
|
722
|
+
}
|
|
723
|
+
for (const path of searchPaths) {
|
|
724
|
+
if (existsSync3(path)) return path;
|
|
725
|
+
}
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
728
|
+
function resolveAgentConfig(agentType, pluginDir, cwd) {
|
|
729
|
+
const filePath = resolveAgentTypePath(agentType, pluginDir, cwd);
|
|
730
|
+
if (!filePath) return null;
|
|
731
|
+
try {
|
|
732
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
733
|
+
return {
|
|
734
|
+
frontmatter: parseAgentFrontmatter(content),
|
|
735
|
+
body: extractAgentBody(content),
|
|
736
|
+
filePath
|
|
737
|
+
};
|
|
738
|
+
} catch {
|
|
739
|
+
return null;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
700
743
|
// src/daemon/agent.ts
|
|
701
744
|
var agentCounters = /* @__PURE__ */ new Map();
|
|
702
745
|
function resetAgentCounterFromState(sessionId, agents) {
|
|
@@ -736,7 +779,9 @@ async function spawnAgent(opts) {
|
|
|
736
779
|
agentCounters.set(sessionId, count);
|
|
737
780
|
const agentId = `agent-${String(count).padStart(3, "0")}`;
|
|
738
781
|
const pluginPath = resolve2(import.meta.dirname, "../templates/agent-plugin");
|
|
739
|
-
const
|
|
782
|
+
const agentConfig = resolveAgentConfig(agentType, pluginPath, cwd);
|
|
783
|
+
const provider = detectProvider(agentConfig?.frontmatter.model);
|
|
784
|
+
const color = (agentConfig?.frontmatter.color ? normalizeTmuxColor(agentConfig.frontmatter.color) : null) ?? getNextColor(sessionId);
|
|
740
785
|
let paneCwd = cwd;
|
|
741
786
|
let worktreePath;
|
|
742
787
|
let branchName;
|
|
@@ -760,22 +805,37 @@ async function spawnAgent(opts) {
|
|
|
760
805
|
const suffixFilePath = `${promptsDir(cwd, sessionId)}/${agentId}-system.md`;
|
|
761
806
|
writeFileSync3(suffixFilePath, suffix, "utf-8");
|
|
762
807
|
const bannerPath = resolve2(import.meta.dirname, "../templates/banner.txt");
|
|
763
|
-
const bannerCmd =
|
|
808
|
+
const bannerCmd = existsSync4(bannerPath) ? `cat '${bannerPath}' &&` : "";
|
|
764
809
|
const envExports = [
|
|
765
810
|
`export SISYPHUS_SESSION_ID='${sessionId}'`,
|
|
766
811
|
`export SISYPHUS_AGENT_ID='${agentId}'`,
|
|
767
812
|
...worktreeContext ? [`export SISYPHUS_PORT_OFFSET='${worktreeContext.offset}'`] : []
|
|
768
813
|
].join(" && ");
|
|
769
|
-
const agentFlag = agentType && agentType !== "worker" ? ` --agent ${shellQuote3(agentType)}` : "";
|
|
770
|
-
const agentNameFlag = ` --agent-name ${shellQuote3(paneLabel)}`;
|
|
771
|
-
const teamFlag = ` --agent-id ${shellQuote3(agentId)} --team-name sisyphus-${sessionId.slice(0, 8)}`;
|
|
772
|
-
const claudeCmd = `claude --dangerously-skip-permissions --plugin-dir "${pluginPath}"${agentFlag}${agentNameFlag}${teamFlag} --append-system-prompt "$(cat '${suffixFilePath}')" ${shellQuote3(instruction)}`;
|
|
773
814
|
const notifyCmd = `sisyphus notify pane-exited --pane-id ${paneId}`;
|
|
774
|
-
|
|
815
|
+
let mainCmd;
|
|
816
|
+
if (provider === "openai") {
|
|
817
|
+
const codexPromptPath = `${promptsDir(cwd, sessionId)}/${agentId}-codex-prompt.md`;
|
|
818
|
+
const parts = [];
|
|
819
|
+
if (agentConfig?.body) {
|
|
820
|
+
parts.push(agentConfig.body);
|
|
821
|
+
}
|
|
822
|
+
parts.push(suffix);
|
|
823
|
+
parts.push(`## Task
|
|
824
|
+
|
|
825
|
+
${instruction}`);
|
|
826
|
+
writeFileSync3(codexPromptPath, parts.join("\n\n"), "utf-8");
|
|
827
|
+
const model = agentConfig?.frontmatter.model ?? "codex-mini";
|
|
828
|
+
mainCmd = `codex -m ${shellQuote3(model)} --dangerously-bypass-approvals-and-sandbox "$(cat '${codexPromptPath}')"`;
|
|
829
|
+
} else {
|
|
830
|
+
const agentFlag = agentType && agentType !== "worker" ? ` --agent ${shellQuote3(agentType)}` : "";
|
|
831
|
+
mainCmd = `claude --dangerously-skip-permissions --plugin-dir "${pluginPath}"${agentFlag} --append-system-prompt "$(cat '${suffixFilePath}')" ${shellQuote3(instruction)}`;
|
|
832
|
+
}
|
|
833
|
+
const fullCmd = `${bannerCmd} ${envExports} && ${mainCmd}; ${notifyCmd}`;
|
|
775
834
|
const agent = {
|
|
776
835
|
id: agentId,
|
|
777
836
|
name,
|
|
778
837
|
agentType,
|
|
838
|
+
provider,
|
|
779
839
|
color,
|
|
780
840
|
instruction,
|
|
781
841
|
status: "running",
|
|
@@ -970,9 +1030,9 @@ async function pollSession(sessionId, cwd, windowId) {
|
|
|
970
1030
|
}
|
|
971
1031
|
|
|
972
1032
|
// src/daemon/session-manager.ts
|
|
973
|
-
async function startSession(task, cwd, tmuxSession, windowId) {
|
|
1033
|
+
async function startSession(task, cwd, tmuxSession, windowId, context) {
|
|
974
1034
|
const sessionId = uuidv4();
|
|
975
|
-
const session = createSession(sessionId, task, cwd);
|
|
1035
|
+
const session = createSession(sessionId, task, cwd, context);
|
|
976
1036
|
await updateSessionTmux(cwd, sessionId, tmuxSession, windowId);
|
|
977
1037
|
trackSession(sessionId, cwd, tmuxSession);
|
|
978
1038
|
await spawnOrchestrator(sessionId, cwd, windowId);
|
|
@@ -985,7 +1045,7 @@ var PRUNE_KEEP_DAYS = 7;
|
|
|
985
1045
|
function pruneOldSessions(cwd) {
|
|
986
1046
|
try {
|
|
987
1047
|
const dir = sessionsDir(cwd);
|
|
988
|
-
if (!
|
|
1048
|
+
if (!existsSync5(dir)) return;
|
|
989
1049
|
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
990
1050
|
const candidates = [];
|
|
991
1051
|
for (const entry of entries) {
|
|
@@ -1052,7 +1112,7 @@ function getSessionStatus(cwd, sessionId) {
|
|
|
1052
1112
|
}
|
|
1053
1113
|
function listSessions(cwd) {
|
|
1054
1114
|
const dir = sessionsDir(cwd);
|
|
1055
|
-
if (!
|
|
1115
|
+
if (!existsSync5(dir)) return [];
|
|
1056
1116
|
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
1057
1117
|
const sessions = [];
|
|
1058
1118
|
for (const entry of entries) {
|
|
@@ -1223,7 +1283,7 @@ function persistSessionRegistry() {
|
|
|
1223
1283
|
}
|
|
1224
1284
|
function loadSessionRegistry() {
|
|
1225
1285
|
const p = registryPath();
|
|
1226
|
-
if (!
|
|
1286
|
+
if (!existsSync6(p)) return {};
|
|
1227
1287
|
try {
|
|
1228
1288
|
return JSON.parse(readFileSync7(p, "utf-8"));
|
|
1229
1289
|
} catch {
|
|
@@ -1242,7 +1302,7 @@ async function handleRequest(req) {
|
|
|
1242
1302
|
try {
|
|
1243
1303
|
switch (req.type) {
|
|
1244
1304
|
case "start": {
|
|
1245
|
-
const session = await startSession(req.task, req.cwd, req.tmuxSession, req.tmuxWindow);
|
|
1305
|
+
const session = await startSession(req.task, req.cwd, req.tmuxSession, req.tmuxWindow, req.context);
|
|
1246
1306
|
registerSessionCwd(session.id, req.cwd);
|
|
1247
1307
|
sessionTmuxMap.set(session.id, req.tmuxSession);
|
|
1248
1308
|
sessionWindowMap2.set(session.id, req.tmuxWindow);
|
|
@@ -1319,7 +1379,7 @@ async function handleRequest(req) {
|
|
|
1319
1379
|
let cwd = sessionCwdMap.get(req.sessionId);
|
|
1320
1380
|
if (!cwd) {
|
|
1321
1381
|
const stateFile = `${req.cwd}/.sisyphus/sessions/${req.sessionId}/state.json`;
|
|
1322
|
-
if (
|
|
1382
|
+
if (existsSync6(stateFile)) {
|
|
1323
1383
|
cwd = req.cwd;
|
|
1324
1384
|
registerSessionCwd(req.sessionId, cwd);
|
|
1325
1385
|
} else {
|
|
@@ -1370,7 +1430,7 @@ async function handleRequest(req) {
|
|
|
1370
1430
|
function startServer() {
|
|
1371
1431
|
return new Promise((resolve4, reject) => {
|
|
1372
1432
|
const sock = socketPath();
|
|
1373
|
-
if (
|
|
1433
|
+
if (existsSync6(sock)) {
|
|
1374
1434
|
unlinkSync(sock);
|
|
1375
1435
|
}
|
|
1376
1436
|
server = createServer((conn) => {
|
|
@@ -1412,7 +1472,7 @@ function stopServer() {
|
|
|
1412
1472
|
}
|
|
1413
1473
|
server.close(() => {
|
|
1414
1474
|
const sock = socketPath();
|
|
1415
|
-
if (
|
|
1475
|
+
if (existsSync6(sock)) {
|
|
1416
1476
|
unlinkSync(sock);
|
|
1417
1477
|
}
|
|
1418
1478
|
server = null;
|
|
@@ -1618,7 +1678,7 @@ async function recoverSessions() {
|
|
|
1618
1678
|
let recovered = 0;
|
|
1619
1679
|
for (const [sessionId, cwd] of entries) {
|
|
1620
1680
|
const stateFile = statePath(cwd, sessionId);
|
|
1621
|
-
if (!
|
|
1681
|
+
if (!existsSync7(stateFile)) {
|
|
1622
1682
|
continue;
|
|
1623
1683
|
}
|
|
1624
1684
|
try {
|