feat(workspace): store runtime state under omo

This commit is contained in:
YeonGyu-Kim
2026-05-16 17:40:11 +09:00
parent 5dca1a5742
commit a86221b1a9
13 changed files with 137 additions and 137 deletions
+2 -2
View File
@@ -10,7 +10,7 @@ function createTempDirectory(): string {
} }
function seedPlanAndState(directory: string): void { function seedPlanAndState(directory: string): void {
const planDirectory = join(directory, ".sisyphus", "plans") const planDirectory = join(directory, ".omo", "plans")
mkdirSync(planDirectory, { recursive: true }) mkdirSync(planDirectory, { recursive: true })
const planAPath = join(planDirectory, "alpha.md") const planAPath = join(planDirectory, "alpha.md")
@@ -35,7 +35,7 @@ function seedPlanAndState(directory: string): void {
"utf-8", "utf-8",
) )
const boulderDirectory = join(directory, ".sisyphus") const boulderDirectory = join(directory, ".omo")
mkdirSync(boulderDirectory, { recursive: true }) mkdirSync(boulderDirectory, { recursive: true })
writeFileSync( writeFileSync(
+38 -38
View File
@@ -53,10 +53,10 @@ function writeBoulderStateFile(
sessionIDs: string[], sessionIDs: string[],
sessionOrigins?: Record<string, "direct" | "appended">, sessionOrigins?: Record<string, "direct" | "appended">,
): void { ): void {
const sisyphusDir = join(directory, ".sisyphus") const omoDir = join(directory, ".omo")
mkdirSync(sisyphusDir, { recursive: true }) mkdirSync(omoDir, { recursive: true })
writeFileSync( writeFileSync(
join(sisyphusDir, "boulder.json"), join(omoDir, "boulder.json"),
JSON.stringify({ JSON.stringify({
active_plan: activePlanPath, active_plan: activePlanPath,
started_at: new Date().toISOString(), started_at: new Date().toISOString(),
@@ -74,8 +74,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "active-plan.md") const planPath = join(directory, ".omo", "plans", "active-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] incomplete task\n", "utf-8") writeFileSync(planPath, "- [ ] incomplete task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["test-session"]) writeBoulderStateFile(directory, planPath, ["test-session"])
const ctx = createMockContext(directory) const ctx = createMockContext(directory)
@@ -92,8 +92,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "done-plan.md") const planPath = join(directory, ".omo", "plans", "done-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [x] completed task\n", "utf-8") writeFileSync(planPath, "- [x] completed task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["test-session"]) writeBoulderStateFile(directory, planPath, ["test-session"])
const ctx = createMockContext(directory) const ctx = createMockContext(directory)
@@ -110,17 +110,17 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const mainPlanPath = join(directory, ".sisyphus", "plans", "done-in-worktree-plan.md") const mainPlanPath = join(directory, ".omo", "plans", "done-in-worktree-plan.md")
const worktreeDirectory = createTempDir() const worktreeDirectory = createTempDir()
const worktreePlanPath = join(worktreeDirectory, ".sisyphus", "plans", "done-in-worktree-plan.md") const worktreePlanPath = join(worktreeDirectory, ".omo", "plans", "done-in-worktree-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
mkdirSync(join(worktreeDirectory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(worktreeDirectory, ".omo", "plans"), { recursive: true })
writeFileSync(mainPlanPath, "- [ ] stale main repo task\n", "utf-8") writeFileSync(mainPlanPath, "- [ ] stale main repo task\n", "utf-8")
writeFileSync(worktreePlanPath, "- [x] completed worktree task\n", "utf-8") writeFileSync(worktreePlanPath, "- [x] completed worktree task\n", "utf-8")
const sisyphusDir = join(directory, ".sisyphus") const omoDir = join(directory, ".omo")
mkdirSync(sisyphusDir, { recursive: true }) mkdirSync(omoDir, { recursive: true })
writeFileSync( writeFileSync(
join(sisyphusDir, "boulder.json"), join(omoDir, "boulder.json"),
JSON.stringify({ JSON.stringify({
active_plan: mainPlanPath, active_plan: mainPlanPath,
started_at: new Date().toISOString(), started_at: new Date().toISOString(),
@@ -145,8 +145,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "active-descendant-plan.md") const planPath = join(directory, ".omo", "plans", "active-descendant-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["root-session", "child-session"], { writeBoulderStateFile(directory, planPath, ["root-session", "child-session"], {
"root-session": "direct", "root-session": "direct",
@@ -181,8 +181,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "lineage-non-subagent-plan.md") const planPath = join(directory, ".omo", "plans", "lineage-non-subagent-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["root-session"]) writeBoulderStateFile(directory, planPath, ["root-session"])
@@ -209,8 +209,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "lineage-agent-mismatch-plan.md") const planPath = join(directory, ".omo", "plans", "lineage-agent-mismatch-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["root-session", "mismatch-subagent-session"], { writeBoulderStateFile(directory, planPath, ["root-session", "mismatch-subagent-session"], {
"root-session": "direct", "root-session": "direct",
@@ -244,8 +244,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "appended-mismatch-plan.md") const planPath = join(directory, ".omo", "plans", "appended-mismatch-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["root-session", "appended-mismatch-session"], { writeBoulderStateFile(directory, planPath, ["root-session", "appended-mismatch-session"], {
"root-session": "direct", "root-session": "direct",
@@ -279,8 +279,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "appended-unresolved-lineage-plan.md") const planPath = join(directory, ".omo", "plans", "appended-unresolved-lineage-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["root-session", "ses_appended_descendant"], { writeBoulderStateFile(directory, planPath, ["root-session", "ses_appended_descendant"], {
"root-session": "direct", "root-session": "direct",
@@ -311,8 +311,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "direct-tracked-child-plan.md") const planPath = join(directory, ".omo", "plans", "direct-tracked-child-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["ses_direct_child"]) writeBoulderStateFile(directory, planPath, ["ses_direct_child"])
@@ -338,8 +338,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "multi-tracked-direct-plan.md") const planPath = join(directory, ".omo", "plans", "multi-tracked-direct-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["ses_other_tracked", "ses_direct_tracked"], { writeBoulderStateFile(directory, planPath, ["ses_other_tracked", "ses_direct_tracked"], {
"ses_other_tracked": "direct", "ses_other_tracked": "direct",
@@ -368,8 +368,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "unknown-origin-multi-session-plan.md") const planPath = join(directory, ".omo", "plans", "unknown-origin-multi-session-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["ses_root_tracked", "ses_unknown_child"]) writeBoulderStateFile(directory, planPath, ["ses_root_tracked", "ses_unknown_child"])
@@ -392,8 +392,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "multi-tracked-direct-child-plan.md") const planPath = join(directory, ".omo", "plans", "multi-tracked-direct-child-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["ses_root_tracked", "ses_direct_child"], { writeBoulderStateFile(directory, planPath, ["ses_root_tracked", "ses_direct_child"], {
"ses_root_tracked": "direct", "ses_root_tracked": "direct",
@@ -427,8 +427,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "compaction-descendant-plan.md") const planPath = join(directory, ".omo", "plans", "compaction-descendant-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["root-session", "ses_child_after_compaction"], { writeBoulderStateFile(directory, planPath, ["root-session", "ses_child_after_compaction"], {
"root-session": "direct", "root-session": "direct",
@@ -466,8 +466,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "sqlite-ordered-descendant-plan.md") const planPath = join(directory, ".omo", "plans", "sqlite-ordered-descendant-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["root-session"]) writeBoulderStateFile(directory, planPath, ["root-session"])
@@ -502,8 +502,8 @@ describe("checkCompletionConditions continuation coverage", () => {
// given // given
spyOn(console, "log").mockImplementation(() => {}) spyOn(console, "log").mockImplementation(() => {})
const directory = createTempDir() const directory = createTempDir()
const planPath = join(directory, ".sisyphus", "plans", "session-agent-fallback-plan.md") const planPath = join(directory, ".omo", "plans", "session-agent-fallback-plan.md")
mkdirSync(join(directory, ".sisyphus", "plans"), { recursive: true }) mkdirSync(join(directory, ".omo", "plans"), { recursive: true })
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
writeBoulderStateFile(directory, planPath, ["ses_root_tracked", "ses_appended_child"], { writeBoulderStateFile(directory, planPath, ["ses_root_tracked", "ses_appended_child"], {
"ses_root_tracked": "direct", "ses_root_tracked": "direct",
@@ -68,12 +68,12 @@ describe("getContinuationState JSON backend descendant coverage", () => {
test("returns active boulder for explicitly tracked appended descendant on JSON message storage backend", async () => { test("returns active boulder for explicitly tracked appended descendant on JSON message storage backend", async () => {
// given // given
const directory = createTempDir() const directory = createTempDir()
const plansDir = join(directory, ".sisyphus", "plans") const plansDir = join(directory, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const planPath = join(plansDir, "json-descendant-plan.md") const planPath = join(plansDir, "json-descendant-plan.md")
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
mkdirSync(join(directory, ".sisyphus"), { recursive: true }) mkdirSync(join(directory, ".omo"), { recursive: true })
writeFileSync(join(directory, ".sisyphus", "boulder.json"), JSON.stringify({ writeFileSync(join(directory, ".omo", "boulder.json"), JSON.stringify({
active_plan: planPath, active_plan: planPath,
started_at: new Date().toISOString(), started_at: new Date().toISOString(),
session_ids: ["ses_root_session", "ses_child_session"], session_ids: ["ses_root_session", "ses_child_session"],
@@ -134,12 +134,12 @@ describe("getContinuationState JSON backend descendant coverage", () => {
test("prefers newest JSON agent by time.created even when filenames look reversed and timestamps tie-break by filename only", async () => { test("prefers newest JSON agent by time.created even when filenames look reversed and timestamps tie-break by filename only", async () => {
// given // given
const directory = createTempDir() const directory = createTempDir()
const plansDir = join(directory, ".sisyphus", "plans") const plansDir = join(directory, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const planPath = join(plansDir, "json-random-id-plan.md") const planPath = join(plansDir, "json-random-id-plan.md")
writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8") writeFileSync(planPath, "- [ ] unfinished task\n", "utf-8")
mkdirSync(join(directory, ".sisyphus"), { recursive: true }) mkdirSync(join(directory, ".omo"), { recursive: true })
writeFileSync(join(directory, ".sisyphus", "boulder.json"), JSON.stringify({ writeFileSync(join(directory, ".omo", "boulder.json"), JSON.stringify({
active_plan: planPath, active_plan: planPath,
started_at: new Date().toISOString(), started_at: new Date().toISOString(),
session_ids: ["ses_root_random"], session_ids: ["ses_root_random"],
+2 -2
View File
@@ -34,7 +34,7 @@ interface BoulderState {
| File | Purpose | | File | Purpose |
|------|---------| |------|---------|
| `types.ts` | `BoulderState`, `BoulderWorkState`, `TaskSessionState`, status enums | | `types.ts` | `BoulderState`, `BoulderWorkState`, `TaskSessionState`, status enums |
| `storage.ts` | Atomic CRUD on `.sisyphus/boulder-state.json`. Writes via temp file + rename; file lock per work_id | | `storage.ts` | Atomic CRUD on `.omo/boulder-state.json`. Writes via temp file + rename; file lock per work_id |
| `constants.ts` | Path resolution + schema version constant | | `constants.ts` | Path resolution + schema version constant |
| `top-level-task.ts` | Helpers to identify the current top-level plan task and resolve its reusable subagent session | | `top-level-task.ts` | Helpers to identify the current top-level plan task and resolve its reusable subagent session |
| `format-duration.ts` | `formatDurationHuman(ms)` — "1h 23m 5s" formatting for boulder duration | | `format-duration.ts` | `formatDurationHuman(ms)` — "1h 23m 5s" formatting for boulder duration |
@@ -67,7 +67,7 @@ session.completed
## STORAGE ## STORAGE
``` ```
<worktree-root>/.sisyphus/boulder-state.json # gitignored; one file per worktree <worktree-root>/.omo/boulder-state.json # gitignored; one file per worktree
``` ```
Atomic writes: temp file → fsync (where supported) → rename. File lock prevents concurrent corruption. Schema migrations between versions handled inline in `storage.ts`. Atomic writes: temp file → fsync (where supported) → rename. File lock prevents concurrent corruption. Schema migrations between versions handled inline in `storage.ts`.
+2 -2
View File
@@ -2,7 +2,7 @@
* Boulder State Constants * Boulder State Constants
*/ */
export const BOULDER_DIR = ".sisyphus" export const BOULDER_DIR = ".omo"
export const BOULDER_FILE = "boulder.json" export const BOULDER_FILE = "boulder.json"
export const BOULDER_STATE_PATH = `${BOULDER_DIR}/${BOULDER_FILE}` export const BOULDER_STATE_PATH = `${BOULDER_DIR}/${BOULDER_FILE}`
@@ -10,4 +10,4 @@ export const NOTEPAD_DIR = "notepads"
export const NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}` export const NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`
/** Prometheus plan directory pattern */ /** Prometheus plan directory pattern */
export const PROMETHEUS_PLANS_DIR = ".sisyphus/plans" export const PROMETHEUS_PLANS_DIR = ".omo/plans"
+31 -31
View File
@@ -34,14 +34,14 @@ import { readCurrentTopLevelTask } from "./top-level-task"
describe("boulder-state", () => { describe("boulder-state", () => {
const TEST_DIR = join(tmpdir(), "boulder-state-test-" + Date.now()) const TEST_DIR = join(tmpdir(), "boulder-state-test-" + Date.now())
const SISYPHUS_DIR = join(TEST_DIR, ".sisyphus") const OMO_DIR = join(TEST_DIR, ".omo")
beforeEach(() => { beforeEach(() => {
if (!existsSync(TEST_DIR)) { if (!existsSync(TEST_DIR)) {
mkdirSync(TEST_DIR, { recursive: true }) mkdirSync(TEST_DIR, { recursive: true })
} }
if (!existsSync(SISYPHUS_DIR)) { if (!existsSync(OMO_DIR)) {
mkdirSync(SISYPHUS_DIR, { recursive: true }) mkdirSync(OMO_DIR, { recursive: true })
} }
clearBoulderState(TEST_DIR) clearBoulderState(TEST_DIR)
}) })
@@ -55,7 +55,7 @@ describe("boulder-state", () => {
describe("readBoulderState", () => { describe("readBoulderState", () => {
test("should preserve legacy boulder.json fields during round-trip", () => { test("should preserve legacy boulder.json fields during round-trip", () => {
// given // given
const boulderFile = join(SISYPHUS_DIR, "boulder.json") const boulderFile = join(OMO_DIR, "boulder.json")
const legacyRawState = { const legacyRawState = {
active_plan: "/path/to/legacy-plan.md", active_plan: "/path/to/legacy-plan.md",
started_at: "2026-01-01T00:00:00.000Z", started_at: "2026-01-01T00:00:00.000Z",
@@ -88,7 +88,7 @@ describe("boulder-state", () => {
test("should return null for JSON null value", () => { test("should return null for JSON null value", () => {
//#given - boulder.json containing null //#given - boulder.json containing null
const boulderFile = join(SISYPHUS_DIR, "boulder.json") const boulderFile = join(OMO_DIR, "boulder.json")
writeFileSync(boulderFile, "null") writeFileSync(boulderFile, "null")
//#when //#when
@@ -100,7 +100,7 @@ describe("boulder-state", () => {
test("should return null for JSON primitive value", () => { test("should return null for JSON primitive value", () => {
//#given - boulder.json containing a string //#given - boulder.json containing a string
const boulderFile = join(SISYPHUS_DIR, "boulder.json") const boulderFile = join(OMO_DIR, "boulder.json")
writeFileSync(boulderFile, '"just a string"') writeFileSync(boulderFile, '"just a string"')
//#when //#when
@@ -112,7 +112,7 @@ describe("boulder-state", () => {
test("should default session_ids to [] when missing from JSON", () => { test("should default session_ids to [] when missing from JSON", () => {
//#given - boulder.json without session_ids field //#given - boulder.json without session_ids field
const boulderFile = join(SISYPHUS_DIR, "boulder.json") const boulderFile = join(OMO_DIR, "boulder.json")
writeFileSync(boulderFile, JSON.stringify({ writeFileSync(boulderFile, JSON.stringify({
active_plan: "/path/to/plan.md", active_plan: "/path/to/plan.md",
started_at: "2026-01-01T00:00:00Z", started_at: "2026-01-01T00:00:00Z",
@@ -129,7 +129,7 @@ describe("boulder-state", () => {
test("should default session_ids to [] when not an array", () => { test("should default session_ids to [] when not an array", () => {
//#given - boulder.json with session_ids as a string //#given - boulder.json with session_ids as a string
const boulderFile = join(SISYPHUS_DIR, "boulder.json") const boulderFile = join(OMO_DIR, "boulder.json")
writeFileSync(boulderFile, JSON.stringify({ writeFileSync(boulderFile, JSON.stringify({
active_plan: "/path/to/plan.md", active_plan: "/path/to/plan.md",
started_at: "2026-01-01T00:00:00Z", started_at: "2026-01-01T00:00:00Z",
@@ -147,7 +147,7 @@ describe("boulder-state", () => {
test("should default session_ids to [] for empty object", () => { test("should default session_ids to [] for empty object", () => {
//#given - boulder.json with empty object //#given - boulder.json with empty object
const boulderFile = join(SISYPHUS_DIR, "boulder.json") const boulderFile = join(OMO_DIR, "boulder.json")
writeFileSync(boulderFile, JSON.stringify({})) writeFileSync(boulderFile, JSON.stringify({}))
//#when //#when
@@ -160,7 +160,7 @@ describe("boulder-state", () => {
test("should backfill missing origin as direct only for a single tracked session", () => { test("should backfill missing origin as direct only for a single tracked session", () => {
// given // given
const boulderFile = join(SISYPHUS_DIR, "boulder.json") const boulderFile = join(OMO_DIR, "boulder.json")
writeFileSync(boulderFile, JSON.stringify({ writeFileSync(boulderFile, JSON.stringify({
active_plan: "/path/to/plan.md", active_plan: "/path/to/plan.md",
started_at: "2026-01-01T00:00:00Z", started_at: "2026-01-01T00:00:00Z",
@@ -177,7 +177,7 @@ describe("boulder-state", () => {
test("should keep missing origins empty when multiple sessions are tracked", () => { test("should keep missing origins empty when multiple sessions are tracked", () => {
// given // given
const boulderFile = join(SISYPHUS_DIR, "boulder.json") const boulderFile = join(OMO_DIR, "boulder.json")
writeFileSync(boulderFile, JSON.stringify({ writeFileSync(boulderFile, JSON.stringify({
active_plan: "/path/to/plan.md", active_plan: "/path/to/plan.md",
started_at: "2026-01-01T00:00:00Z", started_at: "2026-01-01T00:00:00Z",
@@ -213,7 +213,7 @@ describe("boulder-state", () => {
test("should default task_sessions to empty object when missing from JSON", () => { test("should default task_sessions to empty object when missing from JSON", () => {
// given - boulder.json without task_sessions field // given - boulder.json without task_sessions field
const boulderFile = join(SISYPHUS_DIR, "boulder.json") const boulderFile = join(OMO_DIR, "boulder.json")
writeFileSync(boulderFile, JSON.stringify({ writeFileSync(boulderFile, JSON.stringify({
active_plan: "/path/to/plan.md", active_plan: "/path/to/plan.md",
started_at: "2026-01-01T00:00:00Z", started_at: "2026-01-01T00:00:00Z",
@@ -231,7 +231,7 @@ describe("boulder-state", () => {
}) })
describe("writeBoulderState", () => { describe("writeBoulderState", () => {
test("should write state and create .sisyphus directory if needed", () => { test("should write state and create .omo directory if needed", () => {
// given - state to write // given - state to write
const state: BoulderState = { const state: BoulderState = {
active_plan: "/test/plan.md", active_plan: "/test/plan.md",
@@ -298,7 +298,7 @@ describe("boulder-state", () => {
test("should not crash when boulder.json has no session_ids field", () => { test("should not crash when boulder.json has no session_ids field", () => {
//#given - boulder.json without session_ids //#given - boulder.json without session_ids
const boulderFile = join(SISYPHUS_DIR, "boulder.json") const boulderFile = join(OMO_DIR, "boulder.json")
writeFileSync(boulderFile, JSON.stringify({ writeFileSync(boulderFile, JSON.stringify({
active_plan: "/plan.md", active_plan: "/plan.md",
started_at: "2026-01-01T00:00:00Z", started_at: "2026-01-01T00:00:00Z",
@@ -430,7 +430,7 @@ describe("boulder-state", () => {
test("should add second work and keep both active works", () => { test("should add second work and keep both active works", () => {
// given // given
const firstState = createBoulderState( const firstState = createBoulderState(
join(TEST_DIR, ".sisyphus/plans/plan-a.md"), join(TEST_DIR, ".omo/plans/plan-a.md"),
"session-a", "session-a",
"atlas", "atlas",
"/worktree-a", "/worktree-a",
@@ -440,7 +440,7 @@ describe("boulder-state", () => {
// when // when
const updatedState = addBoulderWork(TEST_DIR, { const updatedState = addBoulderWork(TEST_DIR, {
planPath: join(TEST_DIR, ".sisyphus/plans/plan-b.md"), planPath: join(TEST_DIR, ".omo/plans/plan-b.md"),
sessionId: "session-b", sessionId: "session-b",
agent: "atlas", agent: "atlas",
worktreePath: "/worktree-b", worktreePath: "/worktree-b",
@@ -459,12 +459,12 @@ describe("boulder-state", () => {
test("should resolve work for session using updated_at tie-break", () => { test("should resolve work for session using updated_at tie-break", () => {
// given // given
const baseState = createBoulderState( const baseState = createBoulderState(
join(TEST_DIR, ".sisyphus/plans/plan-a.md"), join(TEST_DIR, ".omo/plans/plan-a.md"),
"session-a", "session-a",
) )
writeBoulderState(TEST_DIR, baseState) writeBoulderState(TEST_DIR, baseState)
const stateWithSecond = addBoulderWork(TEST_DIR, { const stateWithSecond = addBoulderWork(TEST_DIR, {
planPath: join(TEST_DIR, ".sisyphus/plans/plan-b.md"), planPath: join(TEST_DIR, ".omo/plans/plan-b.md"),
sessionId: "session-b", sessionId: "session-b",
}) })
expect(stateWithSecond).not.toBeNull() expect(stateWithSecond).not.toBeNull()
@@ -486,10 +486,10 @@ describe("boulder-state", () => {
test("should support selecting active work and read helpers", () => { test("should support selecting active work and read helpers", () => {
// given // given
const initialState = createBoulderState(join(TEST_DIR, ".sisyphus/plans/plan-a.md"), "session-a") const initialState = createBoulderState(join(TEST_DIR, ".omo/plans/plan-a.md"), "session-a")
writeBoulderState(TEST_DIR, initialState) writeBoulderState(TEST_DIR, initialState)
const added = addBoulderWork(TEST_DIR, { const added = addBoulderWork(TEST_DIR, {
planPath: join(TEST_DIR, ".sisyphus/plans/plan-b.md"), planPath: join(TEST_DIR, ".omo/plans/plan-b.md"),
sessionId: "session-b", sessionId: "session-b",
worktreePath: "/tmp/worktree-b", worktreePath: "/tmp/worktree-b",
}) })
@@ -516,7 +516,7 @@ describe("boulder-state", () => {
test("should upsert task session for specific work and keep first started_at", () => { test("should upsert task session for specific work and keep first started_at", () => {
// given // given
const initialState = createBoulderState(join(TEST_DIR, ".sisyphus/plans/plan-a.md"), "session-a") const initialState = createBoulderState(join(TEST_DIR, ".omo/plans/plan-a.md"), "session-a")
writeBoulderState(TEST_DIR, initialState) writeBoulderState(TEST_DIR, initialState)
const workId = initialState.active_work_id! const workId = initialState.active_work_id!
@@ -550,7 +550,7 @@ describe("boulder-state", () => {
describe("task timer and completion helpers", () => { describe("task timer and completion helpers", () => {
test("should keep started_at stable when starting timer repeatedly", () => { test("should keep started_at stable when starting timer repeatedly", () => {
// given // given
const initialState = createBoulderState(join(TEST_DIR, ".sisyphus/plans/plan-a.md"), "session-a") const initialState = createBoulderState(join(TEST_DIR, ".omo/plans/plan-a.md"), "session-a")
writeBoulderState(TEST_DIR, initialState) writeBoulderState(TEST_DIR, initialState)
const workId = initialState.active_work_id! const workId = initialState.active_work_id!
@@ -578,7 +578,7 @@ describe("boulder-state", () => {
test("should compute elapsed_ms when ending task timer", () => { test("should compute elapsed_ms when ending task timer", () => {
// given // given
const initialState = createBoulderState(join(TEST_DIR, ".sisyphus/plans/plan-a.md"), "session-a") const initialState = createBoulderState(join(TEST_DIR, ".omo/plans/plan-a.md"), "session-a")
writeBoulderState(TEST_DIR, initialState) writeBoulderState(TEST_DIR, initialState)
const workId = initialState.active_work_id! const workId = initialState.active_work_id!
startTaskTimer(TEST_DIR, workId, { startTaskTimer(TEST_DIR, workId, {
@@ -601,11 +601,11 @@ describe("boulder-state", () => {
test("should complete one work and keep other work untouched", () => { test("should complete one work and keep other work untouched", () => {
// given // given
const initialState = createBoulderState(join(TEST_DIR, ".sisyphus/plans/plan-a.md"), "session-a") const initialState = createBoulderState(join(TEST_DIR, ".omo/plans/plan-a.md"), "session-a")
writeBoulderState(TEST_DIR, initialState) writeBoulderState(TEST_DIR, initialState)
const firstWorkId = initialState.active_work_id! const firstWorkId = initialState.active_work_id!
const withSecond = addBoulderWork(TEST_DIR, { const withSecond = addBoulderWork(TEST_DIR, {
planPath: join(TEST_DIR, ".sisyphus/plans/plan-b.md"), planPath: join(TEST_DIR, ".omo/plans/plan-b.md"),
sessionId: "session-b", sessionId: "session-b",
}) })
const secondWorkId = Object.keys(withSecond!.works!).find((workId) => workId !== firstWorkId)! const secondWorkId = Object.keys(withSecond!.works!).find((workId) => workId !== firstWorkId)!
@@ -620,13 +620,13 @@ describe("boulder-state", () => {
Date.parse("2026-01-01T01:00:00.000Z") - Date.parse(completedState!.works![firstWorkId]!.started_at), Date.parse("2026-01-01T01:00:00.000Z") - Date.parse(completedState!.works![firstWorkId]!.started_at),
) )
expect(completedState?.works?.[secondWorkId]?.status).not.toBe("completed") expect(completedState?.works?.[secondWorkId]?.status).not.toBe("completed")
expect(existsSync(join(SISYPHUS_DIR, "boulder.json"))).toBe(true) expect(existsSync(join(OMO_DIR, "boulder.json"))).toBe(true)
}) })
test("should keep first completion timing when completeBoulder is called repeatedly", () => { test("should keep first completion timing when completeBoulder is called repeatedly", () => {
// given // given
const initialState = createBoulderState( const initialState = createBoulderState(
join(TEST_DIR, ".sisyphus/plans/plan-idempotent.md"), join(TEST_DIR, ".omo/plans/plan-idempotent.md"),
"session-a", "session-a",
) )
writeBoulderState(TEST_DIR, initialState) writeBoulderState(TEST_DIR, initialState)
@@ -974,7 +974,7 @@ describe("boulder-state", () => {
describe("getPlanName", () => { describe("getPlanName", () => {
test("should extract plan name from path", () => { test("should extract plan name from path", () => {
// given // given
const path = "/home/user/.sisyphus/plans/project/my-feature.md" const path = "/home/user/.omo/plans/project/my-feature.md"
// when // when
const name = getPlanName(path) const name = getPlanName(path)
// then // then
@@ -1042,9 +1042,9 @@ describe("boulder-state", () => {
describe("resolveBoulderPlanPath", () => { describe("resolveBoulderPlanPath", () => {
test("should prefer the mirrored worktree plan when it exists", () => { test("should prefer the mirrored worktree plan when it exists", () => {
// given // given
const planPath = join(TEST_DIR, ".sisyphus", "plans", "worktree-plan.md") const planPath = join(TEST_DIR, ".omo", "plans", "worktree-plan.md")
const worktreeDir = join(tmpdir(), `boulder-state-worktree-${Date.now()}`) const worktreeDir = join(tmpdir(), `boulder-state-worktree-${Date.now()}`)
const worktreePlanPath = join(worktreeDir, ".sisyphus", "plans", "worktree-plan.md") const worktreePlanPath = join(worktreeDir, ".omo", "plans", "worktree-plan.md")
mkdirSync(dirname(planPath), { recursive: true }) mkdirSync(dirname(planPath), { recursive: true })
mkdirSync(dirname(worktreePlanPath), { recursive: true }) mkdirSync(dirname(worktreePlanPath), { recursive: true })
writeFileSync(planPath, "# Plan\n- [ ] Main repo task\n") writeFileSync(planPath, "# Plan\n- [ ] Main repo task\n")
@@ -1066,7 +1066,7 @@ describe("boulder-state", () => {
test("should fall back to the tracked plan when the mirrored worktree plan is missing", () => { test("should fall back to the tracked plan when the mirrored worktree plan is missing", () => {
// given // given
const planPath = join(TEST_DIR, ".sisyphus", "plans", "fallback-plan.md") const planPath = join(TEST_DIR, ".omo", "plans", "fallback-plan.md")
mkdirSync(dirname(planPath), { recursive: true }) mkdirSync(dirname(planPath), { recursive: true })
writeFileSync(planPath, "# Plan\n- [ ] Main repo task\n") writeFileSync(planPath, "# Plan\n- [ ] Main repo task\n")
+1 -1
View File
@@ -348,7 +348,7 @@ export function upsertTaskSessionState(
/** /**
* Find Prometheus plan files for this project. * Find Prometheus plan files for this project.
* Prometheus stores plans at: {project}/.sisyphus/plans/{name}.md * Prometheus stores plans at: {project}/.omo/plans/{name}.md
*/ */
export function findPrometheusPlans(directory: string): string[] { export function findPrometheusPlans(directory: string): string[] {
const plansDir = join(directory, PROMETHEUS_PLANS_DIR) const plansDir = join(directory, PROMETHEUS_PLANS_DIR)
@@ -11,9 +11,9 @@ export const START_WORK_TEMPLATE = `You are starting a Sisyphus work session.
## WHAT TO DO ## WHAT TO DO
1. **Find available plans**: Search for Prometheus-generated plan files at \`.sisyphus/plans/\` 1. **Find available plans**: Search for Prometheus-generated plan files at \`.omo/plans/\`
2. **Check for active boulder state**: Read \`.sisyphus/boulder.json\` if it exists 2. **Check for active boulder state**: Read \`.omo/boulder.json\` if it exists
3. **Decision logic**: 3. **Decision logic**:
- If multiple active works are listed in your context: - If multiple active works are listed in your context:
@@ -119,10 +119,10 @@ Register these as task/todo items so progress is tracked and visible throughout
When working in a worktree (\`worktree_path\` is set in boulder.json) and ALL plan tasks are complete: When working in a worktree (\`worktree_path\` is set in boulder.json) and ALL plan tasks are complete:
1. Commit all remaining changes in the worktree 1. Commit all remaining changes in the worktree
2. **Sync .sisyphus state back**: Copy \`.sisyphus/\` from the worktree to the main repo before removal. 2. **Sync .omo state back**: Copy \`.omo/\` from the worktree to the main repo before removal.
This is CRITICAL when \`.sisyphus/\` is gitignored - state written during worktree execution would otherwise be lost. This is CRITICAL when \`.omo/\` is gitignored - state written during worktree execution would otherwise be lost.
\`\`\`bash \`\`\`bash
cp -r <worktree-path>/.sisyphus/* <main-repo>/.sisyphus/ 2>/dev/null || true cp -r <worktree-path>/.omo/* <main-repo>/.omo/ 2>/dev/null || true
\`\`\` \`\`\`
3. Switch to the main working directory (the original repo, NOT the worktree) 3. Switch to the main working directory (the original repo, NOT the worktree)
4. Merge the worktree branch into the current branch: \`git merge <worktree-branch>\` 4. Merge the worktree branch into the current branch: \`git merge <worktree-branch>\`
@@ -1 +1 @@
export const CONTINUATION_MARKER_DIR = ".sisyphus/run-continuation" export const CONTINUATION_MARKER_DIR = ".omo/run-continuation"
@@ -26,7 +26,7 @@ describe("buildStartWorkContextInfo", () => {
} }
function writePlan(planName: string, content: string): string { function writePlan(planName: string, content: string): string {
const plansDirectory = join(testDirectory, ".sisyphus", "plans") const plansDirectory = join(testDirectory, ".omo", "plans")
mkdirSync(plansDirectory, { recursive: true }) mkdirSync(plansDirectory, { recursive: true })
const planPath = join(plansDirectory, `${planName}.md`) const planPath = join(plansDirectory, `${planName}.md`)
writeFileSync(planPath, content) writeFileSync(planPath, content)
@@ -176,7 +176,7 @@ describe("buildStartWorkContextInfo", () => {
writePlan("new-plan-c", "## TODOs\n- [ ] 1. Work C") writePlan("new-plan-c", "## TODOs\n- [ ] 1. Work C")
const initialState = createBoulderState( const initialState = createBoulderState(
join(testDirectory, ".sisyphus", "plans", "work-a.md"), join(testDirectory, ".omo", "plans", "work-a.md"),
"session-a", "session-a",
"atlas", "atlas",
"/tmp/worktree-a", "/tmp/worktree-a",
+1 -1
View File
@@ -328,7 +328,7 @@ function buildPlanDiscoveryContext(params: {
return contextInfo + ` return contextInfo + `
## No Plans Found ## No Plans Found
No Prometheus plan files found in the .sisyphus plans directory. No Prometheus plan files found in the .omo plans directory.
Use the Prometheus agent to create a work plan first.` Use the Prometheus agent to create a work plan first.`
} }
+25 -25
View File
@@ -20,7 +20,7 @@ import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
describe("start-work hook", () => { describe("start-work hook", () => {
let testDir: string let testDir: string
let sisyphusDir: string let omoDir: string
function createMockPluginInput() { function createMockPluginInput() {
return { return {
@@ -50,12 +50,12 @@ You are starting a Sisyphus work session.
sessionState.registerAgentName("atlas") sessionState.registerAgentName("atlas")
sessionState.registerAgentName("sisyphus") sessionState.registerAgentName("sisyphus")
testDir = join(tmpdir(), `start-work-test-${randomUUID()}`) testDir = join(tmpdir(), `start-work-test-${randomUUID()}`)
sisyphusDir = join(testDir, ".sisyphus") omoDir = join(testDir, ".omo")
if (!existsSync(testDir)) { if (!existsSync(testDir)) {
mkdirSync(testDir, { recursive: true }) mkdirSync(testDir, { recursive: true })
} }
if (!existsSync(sisyphusDir)) { if (!existsSync(omoDir)) {
mkdirSync(sisyphusDir, { recursive: true }) mkdirSync(omoDir, { recursive: true })
} }
clearBoulderState(testDir) clearBoulderState(testDir)
}) })
@@ -224,7 +224,7 @@ You are starting a Sisyphus work session.
test("should auto-select when only one incomplete plan among multiple plans", async () => { test("should auto-select when only one incomplete plan among multiple plans", async () => {
// given - multiple plans but only one incomplete // given - multiple plans but only one incomplete
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
// Plan 1: complete (all checked) // Plan 1: complete (all checked)
@@ -254,7 +254,7 @@ You are starting a Sisyphus work session.
test("should wrap multiple plans message in system-reminder tag", async () => { test("should wrap multiple plans message in system-reminder tag", async () => {
// given - multiple incomplete plans // given - multiple incomplete plans
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const plan1Path = join(plansDir, "plan-a.md") const plan1Path = join(plansDir, "plan-a.md")
@@ -282,7 +282,7 @@ You are starting a Sisyphus work session.
test("should use 'ask user' prompt style for multiple plans", async () => { test("should use 'ask user' prompt style for multiple plans", async () => {
// given - multiple incomplete plans // given - multiple incomplete plans
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const plan1Path = join(plansDir, "plan-x.md") const plan1Path = join(plansDir, "plan-x.md")
@@ -309,7 +309,7 @@ You are starting a Sisyphus work session.
test("should select explicitly specified plan name from user-request, ignoring existing boulder state", async () => { test("should select explicitly specified plan name from user-request, ignoring existing boulder state", async () => {
// given - existing boulder state pointing to old plan // given - existing boulder state pointing to old plan
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
// Old plan (in boulder state) // Old plan (in boulder state)
@@ -353,7 +353,7 @@ You are starting a Sisyphus work session.
test("should strip ultrawork/ulw keywords from plan name argument", async () => { test("should strip ultrawork/ulw keywords from plan name argument", async () => {
// given - plan with ultrawork keyword in user-request // given - plan with ultrawork keyword in user-request
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const planPath = join(plansDir, "my-feature-plan.md") const planPath = join(plansDir, "my-feature-plan.md")
@@ -382,7 +382,7 @@ You are starting a Sisyphus work session.
test("should strip ulw keyword from plan name argument", async () => { test("should strip ulw keyword from plan name argument", async () => {
// given - plan with ulw keyword in user-request // given - plan with ulw keyword in user-request
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const planPath = join(plansDir, "api-refactor.md") const planPath = join(plansDir, "api-refactor.md")
@@ -411,7 +411,7 @@ You are starting a Sisyphus work session.
test("should match plan by partial name", async () => { test("should match plan by partial name", async () => {
// given - user specifies partial plan name // given - user specifies partial plan name
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const planPath = join(plansDir, "2026-01-15-feature-implementation.md") const planPath = join(plansDir, "2026-01-15-feature-implementation.md")
@@ -440,7 +440,7 @@ You are starting a Sisyphus work session.
test("should match quoted human-readable plan names to slugged filenames", async () => { test("should match quoted human-readable plan names to slugged filenames", async () => {
// given - saved plan uses a slugged filename // given - saved plan uses a slugged filename
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const planPath = join(plansDir, "my-feature-plan.md") const planPath = join(plansDir, "my-feature-plan.md")
@@ -469,7 +469,7 @@ You are starting a Sisyphus work session.
test("should match Korean plan names after Unicode-aware normalization", async () => { test("should match Korean plan names after Unicode-aware normalization", async () => {
// given // given
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const planPath = join(plansDir, "결제-플로우.md") const planPath = join(plansDir, "결제-플로우.md")
@@ -498,7 +498,7 @@ You are starting a Sisyphus work session.
test("should match Japanese plan names after Unicode-aware normalization", async () => { test("should match Japanese plan names after Unicode-aware normalization", async () => {
// given // given
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const planPath = join(plansDir, "支払い-フロー.md") const planPath = join(plansDir, "支払い-フロー.md")
@@ -527,7 +527,7 @@ You are starting a Sisyphus work session.
test("should keep ASCII plan name matching behavior unchanged", async () => { test("should keep ASCII plan name matching behavior unchanged", async () => {
// given // given
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const planPath = join(plansDir, "checkout-flow.md") const planPath = join(plansDir, "checkout-flow.md")
@@ -556,7 +556,7 @@ You are starting a Sisyphus work session.
test("should match mixed ASCII and non-ASCII plan names", async () => { test("should match mixed ASCII and non-ASCII plan names", async () => {
// given // given
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
const planPath = join(plansDir, "v2-결제-flow.md") const planPath = join(plansDir, "v2-결제-flow.md")
@@ -674,7 +674,7 @@ You are starting a Sisyphus work session.
sessionState.registerAgentName("sisyphus") sessionState.registerAgentName("sisyphus")
sessionState.updateSessionAgent("ses-prometheus-to-worker", "prometheus") sessionState.updateSessionAgent("ses-prometheus-to-worker", "prometheus")
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
writeFileSync(join(plansDir, "worker-plan.md"), "# Plan\n- [ ] Task 1") writeFileSync(join(plansDir, "worker-plan.md"), "# Plan\n- [ ] Task 1")
@@ -732,7 +732,7 @@ You are starting a Sisyphus work session.
test("#given start-work hands the session to Atlas #when Atlas later receives session.idle #then the same session continues the selected plan", async () => { test("#given start-work hands the session to Atlas #when Atlas later receives session.idle #then the same session continues the selected plan", async () => {
// given // given
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
writeFileSync(join(plansDir, "atlas-plan.md"), "# Plan\n- [ ] Task 1\n- [ ] Task 2") writeFileSync(join(plansDir, "atlas-plan.md"), "# Plan\n- [ ] Task 1\n- [ ] Task 2")
@@ -770,7 +770,7 @@ You are starting a Sisyphus work session.
test("#given start-work hands the session to Atlas but background work is still running #when that work finishes #then Atlas resumes via retry for the same session", async () => { test("#given start-work hands the session to Atlas but background work is still running #when that work finishes #then Atlas resumes via retry for the same session", async () => {
// given // given
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
writeFileSync(join(plansDir, "atlas-plan.md"), "# Plan\n- [ ] Task 1\n- [ ] Task 2") writeFileSync(join(plansDir, "atlas-plan.md"), "# Plan\n- [ ] Task 1\n- [ ] Task 2")
@@ -877,7 +877,7 @@ You are starting a Sisyphus work session.
test("should NOT inject worktree instructions when no --worktree flag", async () => { test("should NOT inject worktree instructions when no --worktree flag", async () => {
// given - single plan, no worktree flag // given - single plan, no worktree flag
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
writeFileSync(join(plansDir, "my-plan.md"), "# Plan\n- [ ] Task 1") writeFileSync(join(plansDir, "my-plan.md"), "# Plan\n- [ ] Task 1")
@@ -897,7 +897,7 @@ You are starting a Sisyphus work session.
test("should inject worktree path when --worktree flag is valid", async () => { test("should inject worktree path when --worktree flag is valid", async () => {
// given - single plan + valid worktree path // given - single plan + valid worktree path
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
writeFileSync(join(plansDir, "my-plan.md"), "# Plan\n- [ ] Task 1") writeFileSync(join(plansDir, "my-plan.md"), "# Plan\n- [ ] Task 1")
detectSpy.mockReturnValue("/validated/worktree") detectSpy.mockReturnValue("/validated/worktree")
@@ -919,7 +919,7 @@ You are starting a Sisyphus work session.
test("should store worktree_path in boulder when --worktree is valid", async () => { test("should store worktree_path in boulder when --worktree is valid", async () => {
// given - plan + valid worktree // given - plan + valid worktree
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
writeFileSync(join(plansDir, "my-plan.md"), "# Plan\n- [ ] Task 1") writeFileSync(join(plansDir, "my-plan.md"), "# Plan\n- [ ] Task 1")
detectSpy.mockReturnValue("/valid/wt") detectSpy.mockReturnValue("/valid/wt")
@@ -939,7 +939,7 @@ You are starting a Sisyphus work session.
test("should NOT store worktree_path when --worktree path is invalid", async () => { test("should NOT store worktree_path when --worktree path is invalid", async () => {
// given - plan + invalid worktree path (detectWorktreePath returns null) // given - plan + invalid worktree path (detectWorktreePath returns null)
const plansDir = join(testDir, ".sisyphus", "plans") const plansDir = join(testDir, ".omo", "plans")
mkdirSync(plansDir, { recursive: true }) mkdirSync(plansDir, { recursive: true })
writeFileSync(join(plansDir, "my-plan.md"), "# Plan\n- [ ] Task 1") writeFileSync(join(plansDir, "my-plan.md"), "# Plan\n- [ ] Task 1")
// detectSpy already returns null by default // detectSpy already returns null by default
@@ -1017,9 +1017,9 @@ You are starting a Sisyphus work session.
test("should show worktree plan progress and path when the mirrored plan exists", async () => { test("should show worktree plan progress and path when the mirrored plan exists", async () => {
// given // given
const mainPlanPath = join(testDir, ".sisyphus", "plans", "resume-worktree-plan.md") const mainPlanPath = join(testDir, ".omo", "plans", "resume-worktree-plan.md")
const worktreeDir = join(testDir, "..", `resume-worktree-${randomUUID()}`) const worktreeDir = join(testDir, "..", `resume-worktree-${randomUUID()}`)
const worktreePlanPath = join(worktreeDir, ".sisyphus", "plans", "resume-worktree-plan.md") const worktreePlanPath = join(worktreeDir, ".omo", "plans", "resume-worktree-plan.md")
mkdirSync(dirname(mainPlanPath), { recursive: true }) mkdirSync(dirname(mainPlanPath), { recursive: true })
mkdirSync(dirname(worktreePlanPath), { recursive: true }) mkdirSync(dirname(worktreePlanPath), { recursive: true })
writeFileSync(mainPlanPath, "# Plan\n- [ ] Main repo task\n") writeFileSync(mainPlanPath, "# Plan\n- [ ] Main repo task\n")
+21 -21
View File
@@ -11,7 +11,7 @@ describe("createTaskList", () => {
let taskDir: string let taskDir: string
beforeEach(() => { beforeEach(() => {
taskDir = join(testProjectDir, ".sisyphus/tasks") taskDir = join(testProjectDir, ".omo/tasks")
if (existsSync(taskDir)) { if (existsSync(taskDir)) {
rmSync(taskDir, { recursive: true }) rmSync(taskDir, { recursive: true })
} }
@@ -28,7 +28,7 @@ describe("createTaskList", () => {
const config = { const config = {
sisyphus: { sisyphus: {
tasks: { tasks: {
storage_path: join(testProjectDir, ".sisyphus/tasks"), storage_path: join(testProjectDir, ".omo/tasks"),
claude_code_compat: false, claude_code_compat: false,
}, },
}, },
@@ -64,13 +64,13 @@ describe("createTaskList", () => {
threadID: "test-session", threadID: "test-session",
} }
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-1.json"), task1) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-1.json"), task1)
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-2.json"), task2) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-2.json"), task2)
const config = { const config = {
sisyphus: { sisyphus: {
tasks: { tasks: {
storage_path: join(testProjectDir, ".sisyphus/tasks"), storage_path: join(testProjectDir, ".omo/tasks"),
claude_code_compat: false, claude_code_compat: false,
}, },
}, },
@@ -107,13 +107,13 @@ describe("createTaskList", () => {
threadID: "test-session", threadID: "test-session",
} }
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-1.json"), task1) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-1.json"), task1)
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-2.json"), task2) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-2.json"), task2)
const config = { const config = {
sisyphus: { sisyphus: {
tasks: { tasks: {
storage_path: join(testProjectDir, ".sisyphus/tasks"), storage_path: join(testProjectDir, ".omo/tasks"),
claude_code_compat: false, claude_code_compat: false,
}, },
}, },
@@ -142,12 +142,12 @@ describe("createTaskList", () => {
threadID: "test-session", threadID: "test-session",
} }
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-1.json"), task) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-1.json"), task)
const config = { const config = {
sisyphus: { sisyphus: {
tasks: { tasks: {
storage_path: join(testProjectDir, ".sisyphus/tasks"), storage_path: join(testProjectDir, ".omo/tasks"),
claude_code_compat: false, claude_code_compat: false,
}, },
}, },
@@ -204,14 +204,14 @@ describe("createTaskList", () => {
threadID: "test-session", threadID: "test-session",
} }
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-blocker-completed.json"), blockerCompleted) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-blocker-completed.json"), blockerCompleted)
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-blocker-pending.json"), blockerPending) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-blocker-pending.json"), blockerPending)
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-main.json"), mainTask) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-main.json"), mainTask)
const config = { const config = {
sisyphus: { sisyphus: {
tasks: { tasks: {
storage_path: join(testProjectDir, ".sisyphus/tasks"), storage_path: join(testProjectDir, ".omo/tasks"),
claude_code_compat: false, claude_code_compat: false,
}, },
}, },
@@ -248,13 +248,13 @@ describe("createTaskList", () => {
threadID: "test-session", threadID: "test-session",
} }
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-1.json"), task1) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-1.json"), task1)
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-2.json"), task2) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-2.json"), task2)
const config = { const config = {
sisyphus: { sisyphus: {
tasks: { tasks: {
storage_path: join(testProjectDir, ".sisyphus/tasks"), storage_path: join(testProjectDir, ".omo/tasks"),
claude_code_compat: false, claude_code_compat: false,
}, },
}, },
@@ -281,12 +281,12 @@ describe("createTaskList", () => {
threadID: "test-session", threadID: "test-session",
} }
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-1.json"), task) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-1.json"), task)
const config = { const config = {
sisyphus: { sisyphus: {
tasks: { tasks: {
storage_path: join(testProjectDir, ".sisyphus/tasks"), storage_path: join(testProjectDir, ".omo/tasks"),
claude_code_compat: false, claude_code_compat: false,
}, },
}, },
@@ -313,12 +313,12 @@ describe("createTaskList", () => {
threadID: "test-session", threadID: "test-session",
} }
writeJsonAtomic(join(testProjectDir, ".sisyphus/tasks", "T-1.json"), task) writeJsonAtomic(join(testProjectDir, ".omo/tasks", "T-1.json"), task)
const config = { const config = {
sisyphus: { sisyphus: {
tasks: { tasks: {
storage_path: join(testProjectDir, ".sisyphus/tasks"), storage_path: join(testProjectDir, ".omo/tasks"),
claude_code_compat: false, claude_code_compat: false,
}, },
}, },