@revealui/harnesses 0.1.8 → 0.1.10

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/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # @revealui/harnesses
2
2
 
3
- > **Commercial package**requires a [RevealUI Pro license](https://revealui.com/pro). Free to install and evaluate; a license key is required for production use.
3
+ > **Commercial package** - requires a [RevealUI Pro license](https://revealui.com/pro). Free to install and evaluate; a license key is required for production use.
4
4
 
5
5
 
6
- AI harness coordination for RevealUIenables multiple AI coding tools to work on the same codebase safely and in parallel.
6
+ AI harness coordination for RevealUI - enables multiple AI coding tools to work on the same codebase safely and in parallel.
7
7
 
8
8
  ## Features
9
9
 
@@ -99,10 +99,10 @@ pnpm --filter @revealui/harnesses build
99
99
 
100
100
  ## Related Documentation
101
101
 
102
- - [Coordination Rules](../../.claude/rules/coordination.md)Multi-instance protocol
103
- - [Architecture Guide](../../docs/ARCHITECTURE.md)System architecture
104
- - [Editors Package](../editors/README.md)Editor daemon (parallel architecture)
102
+ - [Coordination Rules](../../.claude/rules/coordination.md) - Multi-instance protocol
103
+ - [Architecture Guide](../../docs/ARCHITECTURE.md) - System architecture
104
+ - [Editors Package](../editors/README.md) - Editor daemon (parallel architecture)
105
105
 
106
106
  ## License
107
107
 
108
- Commercialsee [LICENSE.commercial](../../LICENSE.commercial)
108
+ Commercial - see [LICENSE.commercial](../../LICENSE.commercial)
@@ -8,4 +8,3 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
8
8
  export {
9
9
  __require
10
10
  };
11
- //# sourceMappingURL=chunk-DGUM43GV.js.map
@@ -89,11 +89,31 @@ function lockPathFor(workboardPath) {
89
89
  // src/workboard/session-identity.ts
90
90
  import { readFileSync as readFileSync2 } from "fs";
91
91
  function detectSessionType() {
92
+ const vaughnId = process.env.VAUGHN_AGENT_ID;
93
+ if (vaughnId) {
94
+ const tool = vaughnId.split("-")[0]?.toLowerCase();
95
+ if (tool === "claude") return "claude";
96
+ if (tool === "codex") return "codex";
97
+ if (tool === "cursor") return "cursor";
98
+ if (tool === "zed") return "zed";
99
+ return "terminal";
100
+ }
101
+ if (process.env.CLAUDE_AGENT_ROLE) return "claude";
102
+ try {
103
+ const cachePath = `/tmp/vaughn-session-${process.ppid}.id`;
104
+ const cached = readFileSync2(cachePath, "utf8").trim();
105
+ if (cached === "claude" || cached === "codex" || cached === "zed" || cached === "cursor") {
106
+ return cached;
107
+ }
108
+ } catch {
109
+ }
92
110
  try {
93
111
  let pid = process.ppid;
94
112
  for (let depth = 0; depth < 8; depth++) {
95
113
  if (!pid || pid <= 1) break;
96
114
  const cmdline = readFileSync2(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ").toLowerCase();
115
+ if (cmdline.includes("claude")) return "claude";
116
+ if (cmdline.includes("codex")) return "codex";
97
117
  if (cmdline.includes("zed")) return "zed";
98
118
  if (cmdline.includes("cursor")) return "cursor";
99
119
  const status = readFileSync2(`/proc/${pid}/status`, "utf8");
@@ -158,7 +178,7 @@ function parseTable(lines) {
158
178
  for (let j = 0; j < columns.length; j++) {
159
179
  const col = columns[j];
160
180
  const raw = (cells[j] || "").trim();
161
- row[col] = raw === "\u2014" ? "" : raw;
181
+ row[col] = raw === "-" ? "" : raw;
162
182
  }
163
183
  rows.push(row);
164
184
  }
@@ -204,13 +224,13 @@ function parseWorkboard(content) {
204
224
  return state;
205
225
  }
206
226
  function padCell(value, width) {
207
- const str = String(value || "\u2014");
227
+ const str = String(value || " - ");
208
228
  return str.length >= width ? str : str + " ".repeat(width - str.length);
209
229
  }
210
230
  function serializeTable(headers, rows) {
211
231
  if (headers.length === 0) return "(none)";
212
232
  const widths = headers.map((h) => {
213
- const dataMax = rows.reduce((max, row) => Math.max(max, String(row[h] || "\u2014").length), 0);
233
+ const dataMax = rows.reduce((max, row) => Math.max(max, String(row[h] || " - ").length), 0);
214
234
  return Math.max(h.length, dataMax, 3);
215
235
  });
216
236
  const headerLine = `| ${headers.map((h, i) => padCell(h, widths[i])).join(" | ")} |`;
@@ -287,6 +307,7 @@ var WorkboardManager = class {
287
307
  }
288
308
  this.lockPath = lockPathFor(resolved);
289
309
  }
310
+ workboardPath;
290
311
  lockPath;
291
312
  // ---- Read/Write ----
292
313
  read() {
@@ -522,20 +543,15 @@ var WorkboardManager = class {
522
543
  function emptyState() {
523
544
  return { preamble: [], agents: [], tasks: [], blocked: [], done: [], log: [], _extra: {} };
524
545
  }
525
- var registerSession = WorkboardManager.prototype.registerAgent;
526
- var unregisterSession = WorkboardManager.prototype.unregisterAgent;
527
546
 
528
547
  export {
548
+ detectSessionType,
549
+ deriveSessionId,
529
550
  acquireLock,
530
551
  releaseLock,
531
552
  withLock,
532
553
  withLockAsync,
533
554
  atomicWriteSync,
534
555
  lockPathFor,
535
- WorkboardManager,
536
- registerSession,
537
- unregisterSession,
538
- detectSessionType,
539
- deriveSessionId
556
+ WorkboardManager
540
557
  };
541
- //# sourceMappingURL=chunk-4F4ANKIZ.js.map
@@ -62,6 +62,52 @@ var SCHEMA_SQL = `
62
62
 
63
63
  CREATE INDEX IF NOT EXISTS idx_events_agent
64
64
  ON events (agent_id, created_at DESC);
65
+
66
+ CREATE TABLE IF NOT EXISTS worktrees (
67
+ agent_id TEXT PRIMARY KEY,
68
+ branch TEXT NOT NULL,
69
+ worktree_path TEXT NOT NULL,
70
+ base_branch TEXT NOT NULL DEFAULT 'test',
71
+ status TEXT NOT NULL DEFAULT 'active',
72
+ created_at TIMESTAMP NOT NULL DEFAULT NOW()
73
+ );
74
+
75
+ CREATE TABLE IF NOT EXISTS agent_memory (
76
+ id SERIAL PRIMARY KEY,
77
+ agent_id TEXT NOT NULL,
78
+ memory_type TEXT NOT NULL,
79
+ content TEXT NOT NULL,
80
+ metadata JSONB NOT NULL DEFAULT '{}',
81
+ created_at TIMESTAMP NOT NULL DEFAULT NOW()
82
+ );
83
+
84
+ CREATE INDEX IF NOT EXISTS idx_memory_agent_type
85
+ ON agent_memory (agent_id, memory_type, created_at DESC);
86
+
87
+ CREATE TABLE IF NOT EXISTS merge_requests (
88
+ id TEXT PRIMARY KEY,
89
+ agent_id TEXT NOT NULL,
90
+ task_id TEXT,
91
+ source_branch TEXT NOT NULL,
92
+ base_branch TEXT NOT NULL DEFAULT 'test',
93
+ status TEXT NOT NULL DEFAULT 'pending',
94
+ pr_number INTEGER,
95
+ pr_url TEXT,
96
+ retry_count INTEGER NOT NULL DEFAULT 0,
97
+ error_message TEXT,
98
+ ci_output TEXT,
99
+ created_at TIMESTAMP NOT NULL DEFAULT NOW(),
100
+ updated_at TIMESTAMP NOT NULL DEFAULT NOW()
101
+ );
102
+
103
+ CREATE INDEX IF NOT EXISTS idx_merge_requests_agent
104
+ ON merge_requests (agent_id, status);
105
+
106
+ CREATE INDEX IF NOT EXISTS idx_merge_requests_branch
107
+ ON merge_requests (source_branch);
108
+
109
+ CREATE INDEX IF NOT EXISTS idx_merge_requests_pr
110
+ ON merge_requests (pr_number) WHERE pr_number IS NOT NULL;
65
111
  `;
66
112
 
67
113
  // src/storage/daemon-store.ts
@@ -85,7 +131,7 @@ var DaemonStore = class {
85
131
  }
86
132
  }
87
133
  getDb() {
88
- if (!this.db) throw new Error("DaemonStore not initialized \u2014 call init() first");
134
+ if (!this.db) throw new Error("DaemonStore not initialized - call init() first");
89
135
  return this.db;
90
136
  }
91
137
  // ---------------------------------------------------------------------------
@@ -371,10 +417,235 @@ var DaemonStore = class {
371
417
  );
372
418
  return result.affectedRows ?? 0;
373
419
  }
420
+ // ---------------------------------------------------------------------------
421
+ // Worktrees
422
+ // ---------------------------------------------------------------------------
423
+ /** Register a worktree for an agent. */
424
+ async registerWorktree(wt) {
425
+ const db = this.getDb();
426
+ const result = await db.query(
427
+ `INSERT INTO worktrees (agent_id, branch, worktree_path, base_branch)
428
+ VALUES ($1, $2, $3, $4)
429
+ ON CONFLICT (agent_id) DO UPDATE SET
430
+ branch = EXCLUDED.branch,
431
+ worktree_path = EXCLUDED.worktree_path,
432
+ base_branch = EXCLUDED.base_branch,
433
+ status = 'active'
434
+ RETURNING *`,
435
+ [wt.agentId, wt.branch, wt.worktreePath, wt.baseBranch ?? "test"]
436
+ );
437
+ return result.rows[0];
438
+ }
439
+ /** Get a worktree by agent ID. */
440
+ async getWorktree(agentId) {
441
+ const db = this.getDb();
442
+ const result = await db.query("SELECT * FROM worktrees WHERE agent_id = $1", [
443
+ agentId
444
+ ]);
445
+ return result.rows[0] ?? null;
446
+ }
447
+ /** List all active worktrees. */
448
+ async getActiveWorktrees() {
449
+ const db = this.getDb();
450
+ const result = await db.query(
451
+ "SELECT * FROM worktrees WHERE status = 'active' ORDER BY created_at"
452
+ );
453
+ return result.rows;
454
+ }
455
+ /** Update worktree status (active → merged | abandoned). */
456
+ async updateWorktreeStatus(agentId, status) {
457
+ const db = this.getDb();
458
+ const result = await db.query(
459
+ "UPDATE worktrees SET status = $2 WHERE agent_id = $1 RETURNING agent_id",
460
+ [agentId, status]
461
+ );
462
+ return (result.rows?.length ?? 0) > 0;
463
+ }
464
+ /** Remove a worktree record. */
465
+ async removeWorktree(agentId) {
466
+ const db = this.getDb();
467
+ const result = await db.query("DELETE FROM worktrees WHERE agent_id = $1 RETURNING agent_id", [
468
+ agentId
469
+ ]);
470
+ return (result.rows?.length ?? 0) > 0;
471
+ }
472
+ // ---------------------------------------------------------------------------
473
+ // Agent Memory
474
+ // ---------------------------------------------------------------------------
475
+ /** Store a memory entry. */
476
+ async storeMemory(entry) {
477
+ const db = this.getDb();
478
+ const result = await db.query(
479
+ `INSERT INTO agent_memory (agent_id, memory_type, content, metadata)
480
+ VALUES ($1, $2, $3, $4)
481
+ RETURNING *`,
482
+ [entry.agentId, entry.memoryType, entry.content, JSON.stringify(entry.metadata ?? {})]
483
+ );
484
+ return result.rows[0];
485
+ }
486
+ /** Recall memory entries by agent and type (newest first). */
487
+ async recallMemory(query) {
488
+ const db = this.getDb();
489
+ const conditions = [];
490
+ const params = [];
491
+ let paramIdx = 1;
492
+ if (query.agentId) {
493
+ conditions.push(`agent_id = $${paramIdx++}`);
494
+ params.push(query.agentId);
495
+ }
496
+ if (query.memoryType) {
497
+ conditions.push(`memory_type = $${paramIdx++}`);
498
+ params.push(query.memoryType);
499
+ }
500
+ if (query.keyword) {
501
+ conditions.push(`content ILIKE $${paramIdx++}`);
502
+ params.push(`%${query.keyword}%`);
503
+ }
504
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
505
+ const limit = query.limit ?? 20;
506
+ params.push(limit);
507
+ const result = await db.query(
508
+ `SELECT * FROM agent_memory ${where} ORDER BY created_at DESC LIMIT $${paramIdx}`,
509
+ params
510
+ );
511
+ return result.rows;
512
+ }
513
+ /** Get a summary of recent memory (last N per type for context injection). */
514
+ async summarizeMemory(agentId, perType) {
515
+ const db = this.getDb();
516
+ const result = await db.query(
517
+ `SELECT * FROM (
518
+ SELECT *, ROW_NUMBER() OVER (PARTITION BY memory_type ORDER BY created_at DESC) AS rn
519
+ FROM agent_memory WHERE agent_id = $1
520
+ ) sub WHERE rn <= $2
521
+ ORDER BY memory_type, created_at DESC`,
522
+ [agentId, perType]
523
+ );
524
+ return result.rows;
525
+ }
526
+ /** Prune old memory entries (keep last N per agent). */
527
+ async pruneMemory(keepPerAgent) {
528
+ const db = this.getDb();
529
+ const result = await db.query(
530
+ `DELETE FROM agent_memory WHERE id IN (
531
+ SELECT id FROM (
532
+ SELECT id, ROW_NUMBER() OVER (PARTITION BY agent_id ORDER BY created_at DESC) AS rn
533
+ FROM agent_memory
534
+ ) sub WHERE rn > $1
535
+ )`,
536
+ [keepPerAgent]
537
+ );
538
+ return result.affectedRows ?? 0;
539
+ }
540
+ // ---------------------------------------------------------------------------
541
+ // Merge Requests
542
+ // ---------------------------------------------------------------------------
543
+ /** Create a merge request for an agent's branch. */
544
+ async createMergeRequest(mr) {
545
+ const db = this.getDb();
546
+ const result = await db.query(
547
+ `INSERT INTO merge_requests (id, agent_id, task_id, source_branch, base_branch)
548
+ VALUES ($1, $2, $3, $4, $5)
549
+ ON CONFLICT (id) DO UPDATE SET
550
+ status = 'pending',
551
+ retry_count = merge_requests.retry_count,
552
+ updated_at = NOW()
553
+ RETURNING *`,
554
+ [mr.id, mr.agentId, mr.taskId ?? null, mr.sourceBranch, mr.baseBranch ?? "test"]
555
+ );
556
+ return result.rows[0];
557
+ }
558
+ /** Get a merge request by ID. */
559
+ async getMergeRequest(id) {
560
+ const db = this.getDb();
561
+ const result = await db.query("SELECT * FROM merge_requests WHERE id = $1", [id]);
562
+ return result.rows[0] ?? null;
563
+ }
564
+ /** Get a merge request by source branch. */
565
+ async getMergeRequestByBranch(branch) {
566
+ const db = this.getDb();
567
+ const result = await db.query(
568
+ "SELECT * FROM merge_requests WHERE source_branch = $1 AND status NOT IN ('merged', 'escalated') ORDER BY created_at DESC LIMIT 1",
569
+ [branch]
570
+ );
571
+ return result.rows[0] ?? null;
572
+ }
573
+ /** Get a merge request by PR number. */
574
+ async getMergeRequestByPr(prNumber) {
575
+ const db = this.getDb();
576
+ const result = await db.query(
577
+ "SELECT * FROM merge_requests WHERE pr_number = $1 ORDER BY created_at DESC LIMIT 1",
578
+ [prNumber]
579
+ );
580
+ return result.rows[0] ?? null;
581
+ }
582
+ /** Update a merge request's fields. */
583
+ async updateMergeRequest(id, updates) {
584
+ const db = this.getDb();
585
+ const sets = ["updated_at = NOW()"];
586
+ const params = [];
587
+ let paramIdx = 1;
588
+ if (updates.status !== void 0) {
589
+ sets.push(`status = $${paramIdx++}`);
590
+ params.push(updates.status);
591
+ }
592
+ if (updates.prNumber !== void 0) {
593
+ sets.push(`pr_number = $${paramIdx++}`);
594
+ params.push(updates.prNumber);
595
+ }
596
+ if (updates.prUrl !== void 0) {
597
+ sets.push(`pr_url = $${paramIdx++}`);
598
+ params.push(updates.prUrl);
599
+ }
600
+ if (updates.errorMessage !== void 0) {
601
+ sets.push(`error_message = $${paramIdx++}`);
602
+ params.push(updates.errorMessage);
603
+ }
604
+ if (updates.ciOutput !== void 0) {
605
+ sets.push(`ci_output = $${paramIdx++}`);
606
+ params.push(updates.ciOutput);
607
+ }
608
+ params.push(id);
609
+ const result = await db.query(
610
+ `UPDATE merge_requests SET ${sets.join(", ")} WHERE id = $${paramIdx} RETURNING *`,
611
+ params
612
+ );
613
+ return result.rows[0] ?? null;
614
+ }
615
+ /** Increment the retry count for a merge request. */
616
+ async incrementMergeRetry(id) {
617
+ const db = this.getDb();
618
+ const result = await db.query(
619
+ `UPDATE merge_requests SET retry_count = retry_count + 1, updated_at = NOW()
620
+ WHERE id = $1 RETURNING retry_count`,
621
+ [id]
622
+ );
623
+ return result.rows[0]?.retry_count ?? 0;
624
+ }
625
+ /** List merge requests, optionally filtered by status and/or agent. */
626
+ async listMergeRequests(filter) {
627
+ const db = this.getDb();
628
+ const conditions = [];
629
+ const params = [];
630
+ let paramIdx = 1;
631
+ if (filter?.status) {
632
+ conditions.push(`status = $${paramIdx++}`);
633
+ params.push(filter.status);
634
+ }
635
+ if (filter?.agentId) {
636
+ conditions.push(`agent_id = $${paramIdx++}`);
637
+ params.push(filter.agentId);
638
+ }
639
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
640
+ const result = await db.query(
641
+ `SELECT * FROM merge_requests ${where} ORDER BY created_at DESC`,
642
+ params
643
+ );
644
+ return result.rows;
645
+ }
374
646
  };
375
647
 
376
648
  export {
377
649
  SCHEMA_SQL,
378
650
  DaemonStore
379
651
  };
380
- //# sourceMappingURL=chunk-DGQ5OB6L.js.map