8d29a1c5c7
* chore: pin bun-types to 1.3.6 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * chore: exclude test files and script from tsconfig 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor: remove sisyphus-swarm feature Remove mailbox types and swarm config schema. Update docs. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor: remove legacy sisyphus-tasks feature Remove old storage and types implementation, replaced by claude-tasks. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(claude-tasks): add task schema and storage utilities - Task schema with Zod validation (pending, in_progress, completed, deleted) - Storage utilities: getTaskDir, readJsonSafe, writeJsonAtomic, acquireLock - Atomic writes with temp file + rename - File-based locking with 30s stale threshold 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(tools/task): add task object schemas Add Zod schemas for task CRUD operations input validation. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(tools): add TaskCreate tool Create new tasks with sequential ID generation and lock-based concurrency. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(tools): add TaskGet tool Retrieve task by ID with null-safe handling. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(tools): add TaskUpdate tool with claim validation Update tasks with status transitions and owner claim validation. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(tools): add TaskList tool and exports - TaskList for summary view of all tasks - Export all claude-tasks tool factories from index 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(hooks): add task-reminder hook Remind agents to use task tools after 10 turns without task operations. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(config): add disabled_tools setting and tasks-todowrite-disabler hook - Add disabled_tools config option to disable specific tools by name - Register tasks-todowrite-disabler hook name in schema 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(config-handler): add task_* and teammate tool permissions Grant task_* and teammate permissions to atlas, sisyphus, prometheus, and sisyphus-junior agents. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(delegate-task): add execute option for task execution Add optional execute field with task_id and task_dir for task-based delegation. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * fix(truncator): add type guard for non-string outputs Prevent crashes when output is not a string by adding typeof checks. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * chore: export config types and update task-resume-info - Export SisyphusConfig and SisyphusTasksConfig types - Add task_tool to TARGET_TOOLS list 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(storage): remove team namespace, use flat task directory * feat(task): implement unified task tool with all 5 actions * fix(hooks): update task-reminder to track unified task tool * refactor(tools): register unified task tool, remove 4 separate tools * chore(cleanup): remove old 4-tool task implementation * refactor(config): use new_task_system_enabled as top-level flag - Add new_task_system_enabled to OhMyOpenCodeConfigSchema - Remove enabled from SisyphusTasksConfigSchema (keep storage_path, claude_code_compat) - Update index.ts to gate on new_task_system_enabled - Update plugin-config.ts default for config initialization - Update test configs in task.test.ts and storage.test.ts Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * fix: resolve typecheck and test failures - Add explicit ToolDefinition return type to createTask function - Fix planDemoteConfig to use 'subagent' mode instead of 'all' --------- Co-authored-by: justsisyphus <justsisyphus@users.noreply.github.com> Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
113 lines
2.8 KiB
TypeScript
113 lines
2.8 KiB
TypeScript
import { join, dirname } from "path"
|
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync, readdirSync } from "fs"
|
|
import { randomUUID } from "crypto"
|
|
import type { z } from "zod"
|
|
import type { OhMyOpenCodeConfig } from "../../config/schema"
|
|
|
|
export function getTaskDir(config: Partial<OhMyOpenCodeConfig> = {}): string {
|
|
const tasksConfig = config.sisyphus?.tasks
|
|
const storagePath = tasksConfig?.storage_path ?? ".sisyphus/tasks"
|
|
return join(process.cwd(), storagePath)
|
|
}
|
|
|
|
export function ensureDir(dirPath: string): void {
|
|
if (!existsSync(dirPath)) {
|
|
mkdirSync(dirPath, { recursive: true })
|
|
}
|
|
}
|
|
|
|
export function readJsonSafe<T>(filePath: string, schema: z.ZodType<T>): T | null {
|
|
try {
|
|
if (!existsSync(filePath)) {
|
|
return null
|
|
}
|
|
|
|
const content = readFileSync(filePath, "utf-8")
|
|
const parsed = JSON.parse(content)
|
|
const result = schema.safeParse(parsed)
|
|
|
|
if (!result.success) {
|
|
return null
|
|
}
|
|
|
|
return result.data
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function writeJsonAtomic(filePath: string, data: unknown): void {
|
|
const dir = dirname(filePath)
|
|
ensureDir(dir)
|
|
|
|
const tempPath = `${filePath}.tmp.${Date.now()}`
|
|
|
|
try {
|
|
writeFileSync(tempPath, JSON.stringify(data, null, 2), "utf-8")
|
|
renameSync(tempPath, filePath)
|
|
} catch (error) {
|
|
try {
|
|
if (existsSync(tempPath)) {
|
|
unlinkSync(tempPath)
|
|
}
|
|
} catch {
|
|
// Ignore cleanup errors
|
|
}
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const STALE_LOCK_THRESHOLD_MS = 30000
|
|
|
|
export function generateTaskId(): string {
|
|
return `T-${randomUUID()}`
|
|
}
|
|
|
|
export function listTaskFiles(config: Partial<OhMyOpenCodeConfig> = {}): string[] {
|
|
const dir = getTaskDir(config)
|
|
if (!existsSync(dir)) return []
|
|
return readdirSync(dir)
|
|
.filter((f) => f.endsWith('.json') && f.startsWith('T-'))
|
|
.map((f) => f.replace('.json', ''))
|
|
}
|
|
|
|
export function acquireLock(dirPath: string): { acquired: boolean; release: () => void } {
|
|
const lockPath = join(dirPath, ".lock")
|
|
const now = Date.now()
|
|
|
|
if (existsSync(lockPath)) {
|
|
try {
|
|
const lockContent = readFileSync(lockPath, "utf-8")
|
|
const lockData = JSON.parse(lockContent)
|
|
const lockAge = now - lockData.timestamp
|
|
|
|
if (lockAge <= STALE_LOCK_THRESHOLD_MS) {
|
|
return {
|
|
acquired: false,
|
|
release: () => {
|
|
// No-op release for failed acquisition
|
|
},
|
|
}
|
|
}
|
|
} catch {
|
|
// If lock file is corrupted, treat as stale and override
|
|
}
|
|
}
|
|
|
|
ensureDir(dirPath)
|
|
writeFileSync(lockPath, JSON.stringify({ timestamp: now }), "utf-8")
|
|
|
|
return {
|
|
acquired: true,
|
|
release: () => {
|
|
try {
|
|
if (existsSync(lockPath)) {
|
|
unlinkSync(lockPath)
|
|
}
|
|
} catch {
|
|
// Ignore cleanup errors
|
|
}
|
|
},
|
|
}
|
|
}
|