@revealui/harnesses 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "name": "@revealui/harnesses",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "[Pro] AI harness integration system - adapters, daemon, workboard coordination, and JSON-RPC server",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/RevealUIStudio/revealui.git",
8
8
  "directory": "packages/harnesses"
9
9
  },
10
- "license": "SEE LICENSE IN ../../LICENSE.commercial",
10
+ "license": "FSL-1.1-MIT",
11
11
  "bin": {
12
12
  "revealui-harnesses": "./dist/cli.js"
13
13
  },
14
14
  "dependencies": {
15
+ "@electric-sql/pglite": "^0.2.17",
15
16
  "zod": "^4.3.6",
16
- "@revealui/core": "0.5.3"
17
+ "@revealui/core": "0.5.5"
17
18
  },
18
19
  "devDependencies": {
19
20
  "@types/node": "^25.3.0",
@@ -41,10 +42,15 @@
41
42
  "./content": {
42
43
  "types": "./dist/content/index.d.ts",
43
44
  "import": "./dist/content/index.js"
45
+ },
46
+ "./storage": {
47
+ "types": "./dist/storage/index.d.ts",
48
+ "import": "./dist/storage/index.js"
44
49
  }
45
50
  },
46
51
  "files": [
47
- "dist"
52
+ "dist",
53
+ "LICENSE"
48
54
  ],
49
55
  "funding": {
50
56
  "type": "commercial",
@@ -1,111 +0,0 @@
1
- RevealUI Commercial License
2
- Version 1.0, February 2026
3
-
4
- Copyright (c) 2025-2026 RevealUI Studio (founder@revealui.com)
5
-
6
- TERMS AND CONDITIONS
7
-
8
- 1. DEFINITIONS
9
-
10
- "Software" means the RevealUI source code, documentation, and associated
11
- files contained in directories and packages designated as commercial,
12
- including but not limited to: packages/ai, packages/harnesses, and any
13
- directory named "ee" within the repository.
14
-
15
- "License Key" means a valid RevealUI license key obtained through an active
16
- paid subscription at https://revealui.com.
17
-
18
- "Licensee" means the individual or organization that holds a valid License
19
- Key through an active subscription.
20
-
21
- "Production Use" means any use of the Software beyond local development and
22
- evaluation, including but not limited to: deploying the Software to serve
23
- end users, integrating the Software into a product or service, or using the
24
- Software in a revenue-generating capacity.
25
-
26
- 2. GRANT OF RIGHTS
27
-
28
- Subject to the terms of this License and a valid License Key, the Licensee
29
- is granted a non-exclusive, non-transferable, revocable license to:
30
-
31
- (a) Use the Software for internal development and Production Use.
32
- (b) Modify the Software for internal use.
33
- (c) Deploy the Software on infrastructure controlled by the Licensee.
34
-
35
- Enterprise License holders are additionally granted the right to:
36
-
37
- (d) Deploy the Software in a self-hosted environment.
38
- (e) Remove or replace RevealUI branding (white-label).
39
- (f) Use the Software for multiple tenants within the Licensee's
40
- organization or customer base.
41
-
42
- 3. RESTRICTIONS
43
-
44
- The Licensee SHALL NOT:
45
-
46
- (a) Provide the Software, or any portion of it, to third parties as a
47
- hosted or managed service that competes with RevealUI.
48
- (b) Redistribute, sublicense, sell, or otherwise transfer the Software
49
- or any portion of it to third parties.
50
- (c) Remove, alter, or circumvent the license key verification
51
- functionality of the Software.
52
- (d) Use the Software in Production without a valid License Key.
53
- (e) Share, publish, or make the License Key available to unauthorized
54
- parties.
55
-
56
- 4. EVALUATION
57
-
58
- The Software may be used for evaluation and local development purposes
59
- without a License Key. Evaluation use does not grant any rights to
60
- Production Use.
61
-
62
- 5. SUBSCRIPTION AND PAYMENT
63
-
64
- This License is valid only during the term of an active paid subscription.
65
- Upon cancellation or expiration of the subscription:
66
-
67
- (a) The License terminates automatically.
68
- (b) A grace period of fourteen (14) days is provided for the Licensee
69
- to transition away from Production Use.
70
- (c) After the grace period, the Licensee must cease all Production Use
71
- of the Software.
72
-
73
- 6. INTELLECTUAL PROPERTY
74
-
75
- The Software is and remains the intellectual property of RevealUI Studio.
76
- This License does not grant any ownership rights. Contributions to
77
- commercial portions of the Software require a Contributor License Agreement.
78
-
79
- 7. OPEN SOURCE COMPONENTS
80
-
81
- This License applies only to files and directories designated as commercial.
82
- Files under the MIT License (as indicated in the root LICENSE file) are not
83
- subject to this commercial license and may be used freely under MIT terms.
84
-
85
- 8. DISCLAIMER OF WARRANTY
86
-
87
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
88
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
89
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
90
-
91
- 9. LIMITATION OF LIABILITY
92
-
93
- IN NO EVENT SHALL REVEALUI STUDIO BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
94
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
95
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
96
- DEALINGS IN THE SOFTWARE, EXCEEDING THE AMOUNT PAID BY THE LICENSEE IN
97
- THE TWELVE (12) MONTHS PRECEDING THE CLAIM.
98
-
99
- 10. GOVERNING LAW
100
-
101
- This License shall be governed by the laws of the State of California,
102
- United States of America, without regard to its conflict of law provisions.
103
-
104
- 11. ENTIRE AGREEMENT
105
-
106
- This License constitutes the entire agreement between the parties with
107
- respect to the commercial portions of the Software and supersedes all
108
- prior agreements, understandings, and communications.
109
-
110
- For licensing inquiries: founder@revealui.com
111
- For pricing and subscriptions: https://revealui.com/pricing
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/workboard/file-lock.ts","../src/workboard/session-identity.ts","../src/workboard/workboard-manager.ts"],"sourcesContent":["import {\n closeSync,\n openSync,\n readFileSync,\n renameSync,\n unlinkSync,\n writeFileSync,\n writeSync,\n} from 'node:fs';\n\nconst DEFAULT_TIMEOUT_MS = 2000;\nconst RETRY_MS = 50;\n\n/**\n * Check whether a process is still running.\n * Uses signal 0 which doesn't actually send a signal — just checks existence.\n */\nfunction isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Acquire an exclusive file lock using O_EXCL (kernel-level atomic create).\n * Writes the current PID to the lock file for dead-holder detection.\n *\n * Spins with a 50ms interval until timeout. If the current lock holder\n * is dead (process no longer running), the lock is stolen.\n *\n * @returns true if the lock was acquired, false on timeout\n */\nexport function acquireLock(lockPath: string, timeoutMs = DEFAULT_TIMEOUT_MS): boolean {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n try {\n const fd = openSync(lockPath, 'wx');\n writeSync(fd, String(process.pid));\n closeSync(fd);\n return true;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== 'EEXIST') return false;\n // Lock exists — check if holder is alive\n try {\n const holderPid = Number.parseInt(readFileSync(lockPath, 'utf8').trim(), 10);\n if (!(Number.isNaN(holderPid) || isPidAlive(holderPid))) {\n // Holder crashed — steal the lock\n unlinkSync(lockPath);\n continue;\n }\n } catch {\n // Lock file disappeared between checks — retry immediately\n continue;\n }\n // Busy-wait\n const spinUntil = Date.now() + RETRY_MS;\n while (Date.now() < spinUntil) {\n /* spin */\n }\n }\n }\n return false;\n}\n\n/**\n * Release a file lock. Swallows ENOENT (already released).\n */\nexport function releaseLock(lockPath: string): void {\n try {\n unlinkSync(lockPath);\n } catch {\n // Already released or never acquired — non-fatal\n }\n}\n\n/**\n * Execute a synchronous function while holding the file lock.\n * The lock is always released, even if fn throws.\n */\nexport function withLock<T>(lockPath: string, fn: () => T, timeoutMs?: number): T {\n const acquired = acquireLock(lockPath, timeoutMs);\n if (!acquired) {\n throw new Error(\n `Failed to acquire lock: ${lockPath} (timeout ${timeoutMs ?? DEFAULT_TIMEOUT_MS}ms)`,\n );\n }\n try {\n return fn();\n } finally {\n releaseLock(lockPath);\n }\n}\n\n/**\n * Execute an async function while holding the file lock.\n * The lock is always released, even if fn throws.\n */\nexport async function withLockAsync<T>(\n lockPath: string,\n fn: () => Promise<T>,\n timeoutMs?: number,\n): Promise<T> {\n const acquired = acquireLock(lockPath, timeoutMs);\n if (!acquired) {\n throw new Error(\n `Failed to acquire lock: ${lockPath} (timeout ${timeoutMs ?? DEFAULT_TIMEOUT_MS}ms)`,\n );\n }\n try {\n return await fn();\n } finally {\n releaseLock(lockPath);\n }\n}\n\n/**\n * Write a file atomically: write to a temporary file, then rename.\n * rename() on the same filesystem is atomic at the kernel level.\n */\nexport function atomicWriteSync(filePath: string, content: string): void {\n const tmpPath = `${filePath}.tmp.${process.pid}`;\n writeFileSync(tmpPath, content, 'utf8');\n renameSync(tmpPath, filePath);\n}\n\n/**\n * Derive a lock path from a workboard path (.md → .lock).\n */\nexport function lockPathFor(workboardPath: string): string {\n return workboardPath.replace(/\\.md$/, '.lock');\n}\n","import { readFileSync } from 'node:fs';\n\n/** Type of session detected from the runtime environment. */\nexport type SessionType = 'zed' | 'cursor' | 'terminal';\n\n/**\n * Detects whether the current process is running inside an AI tool (Zed, Cursor)\n * or a plain terminal session by walking the parent process chain.\n *\n * Uses /proc/<pid>/cmdline on Linux/WSL. Falls back to TERM_PROGRAM env var.\n */\nexport function detectSessionType(): SessionType {\n // Walk parent process chain looking for known AI tool process names.\n try {\n let pid = process.ppid;\n for (let depth = 0; depth < 8; depth++) {\n if (!pid || pid <= 1) break;\n const cmdline = readFileSync(`/proc/${pid}/cmdline`, 'utf8')\n .replace(/\\0/g, ' ')\n .toLowerCase();\n if (cmdline.includes('zed')) return 'zed';\n if (cmdline.includes('cursor')) return 'cursor';\n const status = readFileSync(`/proc/${pid}/status`, 'utf8');\n const m = status.match(/PPid:\\s+(\\d+)/);\n if (!m) break;\n pid = parseInt(m[1] ?? '0', 10);\n }\n } catch {\n // /proc not available (macOS, Windows non-WSL).\n }\n\n // Fallback: TERM_PROGRAM env var (set by some terminal emulators and IDEs).\n const termProgram = (process.env.TERM_PROGRAM ?? '').toLowerCase();\n if (termProgram.includes('zed')) return 'zed';\n if (termProgram.includes('cursor')) return 'cursor';\n\n return 'terminal';\n}\n\n/**\n * Derives a session ID (e.g. \"zed-1\", \"terminal-2\") given a type and a list\n * of existing session IDs already in the workboard.\n *\n * Picks the next available numeric suffix to avoid collisions.\n */\nexport function deriveSessionId(type: SessionType, existingIds: string[]): string {\n const matching = existingIds\n .filter((id) => id.startsWith(`${type}-`))\n .map((id) => parseInt(id.split('-')[1] ?? '0', 10))\n .filter((n) => !Number.isNaN(n));\n\n const maxN = matching.length > 0 ? Math.max(...matching) : 0;\n return `${type}-${maxN + 1}`;\n}\n","import { readFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport { atomicWriteSync, lockPathFor, withLock, withLockAsync } from './file-lock.js';\nimport type {\n ConflictResult,\n WorkboardAgent,\n WorkboardState,\n WorkboardTask,\n} from './workboard-protocol.js';\n\nconst STALE_THRESHOLD_MS = 4 * 60 * 60 * 1000; // 4 hours\nconst STARTING_STALE_MS = 60 * 60 * 1000; // 1 hour\n\n// ---------------------------------------------------------------------------\n// Section name normalization (backward compat with v1 workboard)\n// ---------------------------------------------------------------------------\n\nconst SECTION_MAP: Record<\n string,\n keyof Pick<WorkboardState, 'agents' | 'tasks' | 'blocked' | 'done' | 'log'> | null\n> = {\n agents: 'agents',\n active_sessions: 'agents',\n sessions: 'agents',\n tasks: 'tasks',\n blocked: 'blocked',\n done: 'done',\n log: 'log',\n recent: 'log',\n};\n\nfunction normalizeSectionName(title: string): string | null {\n const key = title.toLowerCase().replace(/\\s+/g, '_');\n return SECTION_MAP[key] || null;\n}\n\n// ---------------------------------------------------------------------------\n// Table parsing\n// ---------------------------------------------------------------------------\n\nfunction splitRow(line: string): string[] | null {\n if (!line.startsWith('|')) return null;\n return line\n .split('|')\n .slice(1, -1)\n .map((c) => c.trim());\n}\n\nfunction isSeparatorRow(cells: string[]): boolean {\n return cells.length > 0 && cells.every((c) => /^[-:]+$/.test(c));\n}\n\nfunction parseTable(lines: string[]): { columns: string[]; rows: Record<string, string>[] } {\n if (lines.length < 2) return { columns: [], rows: [] };\n\n const headerCells = splitRow(lines[0]!);\n if (!headerCells) return { columns: [], rows: [] };\n\n const sepCells = splitRow(lines[1]!);\n if (!(sepCells && isSeparatorRow(sepCells))) return { columns: [], rows: [] };\n\n const columns = headerCells.map((h) =>\n h\n .toLowerCase()\n .replace(/[^a-z0-9_]/g, '_')\n .replace(/_+/g, '_')\n .replace(/^_|_$/g, ''),\n );\n\n const rows: Record<string, string>[] = [];\n for (let i = 2; i < lines.length; i++) {\n const cells = splitRow(lines[i]!);\n if (!cells || isSeparatorRow(cells)) continue;\n const row: Record<string, string> = {};\n for (let j = 0; j < columns.length; j++) {\n const col = columns[j]!;\n const raw = (cells[j] || '').trim();\n row[col] = raw === '—' ? '' : raw;\n }\n rows.push(row);\n }\n\n return { columns, rows };\n}\n\n// ---------------------------------------------------------------------------\n// Parse\n// ---------------------------------------------------------------------------\n\nfunction parseWorkboard(content: string): WorkboardState {\n const lines = content.split('\\n');\n const rawSections: Array<{ title: string; line: number }> = [];\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const m = line.match(/^##\\s+(.+)/);\n if (m?.[1]) rawSections.push({ title: m[1].trim(), line: i });\n }\n\n const state: WorkboardState = {\n preamble: [],\n agents: [],\n tasks: [],\n blocked: [],\n done: [],\n log: [],\n _extra: {},\n };\n\n const firstLine = rawSections.length > 0 ? rawSections[0]?.line : lines.length;\n state.preamble = lines.slice(0, firstLine);\n\n for (let i = 0; i < rawSections.length; i++) {\n const sec = rawSections[i]!;\n const nextLine = i + 1 < rawSections.length ? rawSections[i + 1]?.line : lines.length;\n const body = lines.slice(sec.line + 1, nextLine);\n const normalized = normalizeSectionName(sec.title);\n\n if (\n normalized === 'agents' ||\n normalized === 'tasks' ||\n normalized === 'blocked' ||\n normalized === 'done'\n ) {\n const tableLines = body.filter((l) => l.startsWith('|'));\n if (tableLines.length >= 2) {\n const { rows } = parseTable(tableLines);\n (state[normalized] as unknown as Record<string, string>[]).length = 0;\n (state[normalized] as unknown as Record<string, string>[]).push(...rows);\n }\n } else if (normalized === 'log') {\n state.log = body.filter((l) => l.startsWith('- '));\n } else {\n state._extra[sec.title] = lines.slice(sec.line, nextLine).join('\\n');\n }\n }\n\n return state;\n}\n\n// ---------------------------------------------------------------------------\n// Serialize\n// ---------------------------------------------------------------------------\n\nfunction padCell(value: string | undefined, width: number): string {\n const str = String(value || '—');\n return str.length >= width ? str : str + ' '.repeat(width - str.length);\n}\n\nfunction serializeTable(headers: string[], rows: Record<string, string>[]): string {\n if (headers.length === 0) return '(none)';\n\n const widths = headers.map((h) => {\n const dataMax = rows.reduce((max, row) => Math.max(max, String(row[h] || '—').length), 0);\n return Math.max(h.length, dataMax, 3);\n });\n\n const headerLine = `| ${headers.map((h, i) => padCell(h, widths[i]!)).join(' | ')} |`;\n const sepLine = `| ${widths.map((w) => '-'.repeat(w)).join(' | ')} |`;\n const dataLines = rows.map(\n (row) => `| ${headers.map((h, i) => padCell(row[h] || '', widths[i]!)).join(' | ')} |`,\n );\n\n return [headerLine, sepLine, ...dataLines].join('\\n');\n}\n\nfunction serializeWorkboard(state: WorkboardState): string {\n const out: string[] = [];\n\n if (state.preamble.length > 0) {\n out.push(...state.preamble);\n if (state.preamble[state.preamble.length - 1] !== '') out.push('');\n }\n\n out.push('## Agents', '');\n out.push(\n serializeTable(\n ['id', 'env', 'started', 'task', 'files', 'updated'],\n state.agents as unknown as Record<string, string>[],\n ),\n '',\n );\n\n out.push('## Tasks', '');\n if (state.tasks.length > 0) {\n out.push(\n serializeTable(\n ['id', 'task', 'pri', 'status', 'owner', 'gh', 'updated', 'notes'],\n state.tasks as unknown as Record<string, string>[],\n ),\n '',\n );\n } else {\n out.push('(none)', '');\n }\n\n out.push('## Blocked', '');\n if (state.blocked.length > 0) {\n out.push(\n serializeTable(\n ['id', 'task', 'blocker', 'gh', 'notes'],\n state.blocked as unknown as Record<string, string>[],\n ),\n '',\n );\n } else {\n out.push('(none)', '');\n }\n\n out.push('## Done', '');\n if (state.done.length > 0) {\n out.push(\n serializeTable(\n ['id', 'task', 'owner', 'completed', 'gh', 'notes'],\n state.done as unknown as Record<string, string>[],\n ),\n '',\n );\n } else {\n out.push('(none)', '');\n }\n\n out.push('## Log', '');\n if (state.log.length > 0) out.push(...state.log);\n out.push('');\n\n for (const content of Object.values(state._extra)) {\n out.push(content, '');\n }\n\n return out.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// WorkboardManager\n// ---------------------------------------------------------------------------\n\n/**\n * WorkboardManager — reads, parses, and writes .claude/workboard.md (v2).\n *\n * Supports both v1 (Sessions/Recent) and v2 (Agents/Tasks/Blocked/Done/Log)\n * formats for backward compatibility. Always serializes to v2.\n *\n * All mutating methods use file locking (O_EXCL) to prevent race conditions.\n * Writes are atomic (tmp file + rename).\n */\nexport class WorkboardManager {\n private readonly lockPath: string;\n\n constructor(private readonly workboardPath: string) {\n const resolved = resolve(workboardPath);\n if (!resolved.endsWith('.md')) {\n throw new Error('Invalid workboard path: must be a .md file');\n }\n this.lockPath = lockPathFor(resolved);\n }\n\n // ---- Read/Write ----\n\n read(): WorkboardState {\n try {\n return parseWorkboard(readFileSync(this.workboardPath, 'utf8'));\n } catch {\n return emptyState();\n }\n }\n\n write(state: WorkboardState): void {\n withLock(this.lockPath, () => {\n atomicWriteSync(this.workboardPath, serializeWorkboard(state));\n });\n }\n\n async readAsync(): Promise<WorkboardState> {\n try {\n return parseWorkboard(await readFile(this.workboardPath, 'utf8'));\n } catch {\n return emptyState();\n }\n }\n\n async writeAsync(state: WorkboardState): Promise<void> {\n await withLockAsync(this.lockPath, async () => {\n atomicWriteSync(this.workboardPath, serializeWorkboard(state));\n });\n }\n\n // ---- Agent methods ----\n\n registerAgent(agent: WorkboardAgent): void {\n withLock(this.lockPath, () => {\n const state = this.readUnlocked();\n const idx = state.agents.findIndex((a) => a.id === agent.id);\n if (idx >= 0) {\n state.agents[idx] = agent;\n } else {\n state.agents.push(agent);\n }\n this.writeUnlocked(state);\n });\n }\n\n unregisterAgent(id: string): void {\n withLock(this.lockPath, () => {\n const state = this.readUnlocked();\n state.agents = state.agents.filter((a) => a.id !== id);\n this.writeUnlocked(state);\n });\n }\n\n updateAgent(id: string, updates: Partial<WorkboardAgent>): void {\n withLock(this.lockPath, () => {\n const state = this.readUnlocked();\n const idx = state.agents.findIndex((a) => a.id === id);\n if (idx < 0) return;\n state.agents[idx] = { ...state.agents[idx]!, ...updates };\n this.writeUnlocked(state);\n });\n }\n\n // ---- Task claiming ----\n\n /** Claim an available or partial task. Returns true on success. */\n claimTask(taskId: string, agentId: string): boolean {\n let success = false;\n withLock(this.lockPath, () => {\n const state = this.readUnlocked();\n const task = state.tasks.find((t) => t.id === taskId);\n if (!task) return;\n if (task.status !== 'available' && task.status !== 'partial') return;\n task.status = 'claimed';\n task.owner = agentId;\n task.updated = new Date().toISOString().slice(0, 10);\n this.writeUnlocked(state);\n success = true;\n });\n return success;\n }\n\n /** Move a task from Tasks to Done. Returns true on success. */\n completeTask(taskId: string, agentId: string): boolean {\n let success = false;\n withLock(this.lockPath, () => {\n const state = this.readUnlocked();\n const idx = state.tasks.findIndex((t) => t.id === taskId);\n if (idx === -1) return;\n const task = state.tasks.splice(idx, 1)[0]!;\n state.done.unshift({\n id: task.id,\n task: task.task,\n owner: agentId || task.owner,\n completed: new Date().toISOString().slice(0, 10),\n gh: task.gh || '',\n notes: task.notes || '',\n });\n this.writeUnlocked(state);\n success = true;\n });\n return success;\n }\n\n /** Mark a claimed task as partial (agent stopped mid-work). */\n markPartial(taskId: string, notes: string): boolean {\n let success = false;\n withLock(this.lockPath, () => {\n const state = this.readUnlocked();\n const task = state.tasks.find((t) => t.id === taskId);\n if (!task) return;\n task.status = 'partial';\n task.updated = new Date().toISOString().slice(0, 10);\n if (notes) task.notes = notes;\n this.writeUnlocked(state);\n success = true;\n });\n return success;\n }\n\n /** Release a claimed/partial task back to available. */\n releaseTask(taskId: string): boolean {\n let success = false;\n withLock(this.lockPath, () => {\n const state = this.readUnlocked();\n const task = state.tasks.find((t) => t.id === taskId);\n if (!task) return;\n task.status = 'available';\n task.owner = '';\n task.updated = new Date().toISOString().slice(0, 10);\n this.writeUnlocked(state);\n success = true;\n });\n return success;\n }\n\n /** Move a blocked task to Tasks as available. */\n unblockTask(taskId: string, pri: string = 'P2'): boolean {\n let success = false;\n withLock(this.lockPath, () => {\n const state = this.readUnlocked();\n const idx = state.blocked.findIndex((t) => t.id === taskId);\n if (idx === -1) return;\n const blocked = state.blocked.splice(idx, 1)[0]!;\n state.tasks.push({\n id: blocked.id,\n task: blocked.task,\n pri: pri as WorkboardTask['pri'],\n status: 'available',\n owner: '',\n gh: blocked.gh || '',\n updated: new Date().toISOString().slice(0, 10),\n notes: blocked.notes || '',\n });\n this.writeUnlocked(state);\n success = true;\n });\n return success;\n }\n\n // ---- File claims ----\n\n claimFiles(id: string, files: string[]): void {\n withLock(this.lockPath, () => {\n const state = this.readUnlocked();\n const agent = state.agents.find((a) => a.id === id);\n if (!agent) return;\n agent.files = files.join(', ');\n agent.updated = `${new Date().toISOString().slice(0, 16)}Z`;\n this.writeUnlocked(state);\n });\n }\n\n releaseFiles(id: string): void {\n withLock(this.lockPath, () => {\n const state = this.readUnlocked();\n const agent = state.agents.find((a) => a.id === id);\n if (!agent) return;\n agent.files = '';\n agent.updated = `${new Date().toISOString().slice(0, 16)}Z`;\n this.writeUnlocked(state);\n });\n }\n\n // ---- Log ----\n\n addLogEntry(agentId: string, description: string): void {\n withLock(this.lockPath, () => {\n const state = this.readUnlocked();\n const now = new Date();\n const dateStr = now.toISOString().slice(0, 10);\n const timeStr = now.toISOString().slice(11, 16);\n state.log.unshift(`- [${dateStr} ${timeStr}] ${agentId}: ${description}`);\n if (state.log.length > 20) state.log.splice(20);\n this.writeUnlocked(state);\n });\n }\n\n // ---- Queries ----\n\n detectStale(): WorkboardAgent[] {\n const state = this.read();\n const now = Date.now();\n return state.agents.filter((a) => {\n try {\n const age = now - new Date(a.updated).getTime();\n const threshold = a.task === '(starting)' ? STARTING_STALE_MS : STALE_THRESHOLD_MS;\n return age > threshold;\n } catch {\n return false;\n }\n });\n }\n\n checkConflicts(mySessionId: string, files: string[]): ConflictResult {\n const state = this.read();\n const conflicts: ConflictResult['conflicts'] = [];\n\n for (const agent of state.agents) {\n if (agent.id === mySessionId) continue;\n const theirFiles = agent.files\n .split(',')\n .map((f) => f.trim())\n .filter(Boolean);\n const overlapping = files.filter((myFile) =>\n theirFiles.some(\n (theirFile) =>\n myFile === theirFile ||\n myFile.startsWith(theirFile.replace('**', '')) ||\n theirFile.startsWith(myFile.replace('**', '')),\n ),\n );\n if (overlapping.length > 0) {\n conflicts.push({\n thisSession: mySessionId,\n otherSession: agent.id,\n overlappingFiles: overlapping,\n });\n }\n }\n\n return { clean: conflicts.length === 0, conflicts };\n }\n\n getClaimedTasks(agentId: string): WorkboardTask[] {\n const state = this.read();\n return state.tasks.filter(\n (t) => t.status === 'claimed' && t.owner === agentId,\n ) as WorkboardTask[];\n }\n\n // ---- Internal ----\n\n private readUnlocked(): WorkboardState {\n try {\n return parseWorkboard(readFileSync(this.workboardPath, 'utf8'));\n } catch {\n return emptyState();\n }\n }\n\n private writeUnlocked(state: WorkboardState): void {\n atomicWriteSync(this.workboardPath, serializeWorkboard(state));\n }\n}\n\nfunction emptyState(): WorkboardState {\n return { preamble: [], agents: [], tasks: [], blocked: [], done: [], log: [], _extra: {} };\n}\n\n// Re-export for backward compat\n/** @deprecated Use registerAgent instead */\nexport const registerSession = WorkboardManager.prototype.registerAgent;\n/** @deprecated Use unregisterAgent instead */\nexport const unregisterSession = WorkboardManager.prototype.unregisterAgent;\n"],"mappings":"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","names":["readFileSync","readFileSync","readFileSync"]}