@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.
@@ -14,8 +14,8 @@ declare const AgentSchema: z.ZodObject<{
14
14
  name: z.ZodString;
15
15
  description: z.ZodString;
16
16
  tier: z.ZodDefault<z.ZodEnum<{
17
- pro: "pro";
18
17
  oss: "oss";
18
+ pro: "pro";
19
19
  }>>;
20
20
  isolation: z.ZodDefault<z.ZodEnum<{
21
21
  worktree: "worktree";
@@ -31,8 +31,8 @@ declare const CommandSchema: z.ZodObject<{
31
31
  name: z.ZodString;
32
32
  description: z.ZodString;
33
33
  tier: z.ZodDefault<z.ZodEnum<{
34
- pro: "pro";
35
34
  oss: "oss";
35
+ pro: "pro";
36
36
  }>>;
37
37
  disableModelInvocation: z.ZodDefault<z.ZodBoolean>;
38
38
  argumentHint: z.ZodOptional<z.ZodString>;
@@ -53,8 +53,8 @@ declare const ManifestSchema: z.ZodObject<{
53
53
  }>;
54
54
  preambleTier: z.ZodDefault<z.ZodNumber>;
55
55
  tier: z.ZodDefault<z.ZodEnum<{
56
- pro: "pro";
57
56
  oss: "oss";
57
+ pro: "pro";
58
58
  }>>;
59
59
  tags: z.ZodDefault<z.ZodArray<z.ZodString>>;
60
60
  content: z.ZodString;
@@ -64,8 +64,8 @@ declare const ManifestSchema: z.ZodObject<{
64
64
  name: z.ZodString;
65
65
  description: z.ZodString;
66
66
  tier: z.ZodDefault<z.ZodEnum<{
67
- pro: "pro";
68
67
  oss: "oss";
68
+ pro: "pro";
69
69
  }>>;
70
70
  disableModelInvocation: z.ZodDefault<z.ZodBoolean>;
71
71
  argumentHint: z.ZodOptional<z.ZodString>;
@@ -76,8 +76,8 @@ declare const ManifestSchema: z.ZodObject<{
76
76
  name: z.ZodString;
77
77
  description: z.ZodString;
78
78
  tier: z.ZodDefault<z.ZodEnum<{
79
- pro: "pro";
80
79
  oss: "oss";
80
+ pro: "pro";
81
81
  }>>;
82
82
  isolation: z.ZodDefault<z.ZodEnum<{
83
83
  worktree: "worktree";
@@ -91,8 +91,8 @@ declare const ManifestSchema: z.ZodObject<{
91
91
  name: z.ZodString;
92
92
  description: z.ZodString;
93
93
  tier: z.ZodDefault<z.ZodEnum<{
94
- pro: "pro";
95
94
  oss: "oss";
95
+ pro: "pro";
96
96
  }>>;
97
97
  disableModelInvocation: z.ZodDefault<z.ZodBoolean>;
98
98
  skipFrontmatter: z.ZodDefault<z.ZodBoolean>;
@@ -128,8 +128,8 @@ declare const RuleSchema: z.ZodObject<{
128
128
  }>;
129
129
  preambleTier: z.ZodDefault<z.ZodNumber>;
130
130
  tier: z.ZodDefault<z.ZodEnum<{
131
- pro: "pro";
132
131
  oss: "oss";
132
+ pro: "pro";
133
133
  }>>;
134
134
  tags: z.ZodDefault<z.ZodArray<z.ZodString>>;
135
135
  content: z.ZodString;
@@ -141,8 +141,8 @@ declare const SkillSchema: z.ZodObject<{
141
141
  name: z.ZodString;
142
142
  description: z.ZodString;
143
143
  tier: z.ZodDefault<z.ZodEnum<{
144
- pro: "pro";
145
144
  oss: "oss";
145
+ pro: "pro";
146
146
  }>>;
147
147
  disableModelInvocation: z.ZodDefault<z.ZodBoolean>;
148
148
  skipFrontmatter: z.ZodDefault<z.ZodBoolean>;
@@ -16,7 +16,7 @@ import {
16
16
  registerResolver,
17
17
  resolveTemplate,
18
18
  validateManifest
19
- } from "../chunk-XXEKWC6F.js";
19
+ } from "../chunk-PROC6EJC.js";
20
20
  import "../chunk-DGUM43GV.js";
21
21
  export {
22
22
  AgentSchema,
package/dist/index.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import { HarnessAdapter, HarnessCapabilities, HarnessInfo, HarnessCommand, HarnessCommandResult, HarnessEvent, ConfigDiffEntry, ConfigSyncDirection, ConfigSyncResult, HealthCheckResult, HarnessProcessInfo } from './types/index.js';
2
2
  export { Agent, Command, ContentGenerator, ContentSummary, DiffEntry, GeneratedFile, Manifest, PreambleTier, ResolverContext, Rule, Skill, ValidationResult, buildManifest, diffContent, generateContent, listContent, validateManifest } from './content/index.js';
3
+ import { DaemonStore } from './storage/index.js';
4
+ export { AgentMessage, AgentSession, AgentTask, DaemonEvent, DaemonStoreConfig, FileReservation, SCHEMA_SQL } from './storage/index.js';
5
+ import { EventEmitter } from 'node:events';
3
6
  import { WorkboardManager } from './workboard/index.js';
4
7
  export { ConflictResult, SessionType, WorkboardEntry, WorkboardSession, WorkboardState, acquireLock, atomicWriteSync, deriveSessionId, detectSessionType, lockPathFor, releaseLock, withLock, withLockAsync } from './workboard/index.js';
5
8
  import 'zod';
@@ -107,6 +110,247 @@ declare class HarnessRegistry {
107
110
  disposeAll(): Promise<void>;
108
111
  }
109
112
 
113
+ interface OllamaStatus {
114
+ installed: boolean;
115
+ running: boolean;
116
+ version: string | null;
117
+ }
118
+ interface OllamaModel {
119
+ name: string;
120
+ size: string;
121
+ modified: string;
122
+ }
123
+ interface ModelPullResult {
124
+ success: boolean;
125
+ message: string;
126
+ }
127
+ interface BitNetStatus {
128
+ installed: boolean;
129
+ modelPath: string | null;
130
+ }
131
+ interface SnapStatus {
132
+ installed: boolean;
133
+ running: boolean;
134
+ snapName: string;
135
+ endpoint: string | null;
136
+ version: string | null;
137
+ }
138
+ interface SnapModel {
139
+ name: string;
140
+ description: string;
141
+ installed: boolean;
142
+ }
143
+ /**
144
+ * Manages local inference engines (Ollama, Snaps, BitNet) on the daemon host.
145
+ * Each method mirrors the equivalent Tauri command from `inference.rs`.
146
+ */
147
+ declare class InferenceService {
148
+ ollamaStatus(): Promise<OllamaStatus>;
149
+ ollamaModels(): Promise<OllamaModel[]>;
150
+ ollamaPull(modelName: string): Promise<ModelPullResult>;
151
+ ollamaDelete(modelName: string): Promise<void>;
152
+ ollamaStart(): Promise<void>;
153
+ ollamaStop(): Promise<void>;
154
+ bitnetStatus(): Promise<BitNetStatus>;
155
+ snapList(): Promise<SnapModel[]>;
156
+ snapStatus(snapName: string): Promise<SnapStatus>;
157
+ snapInstall(snapName: string): Promise<ModelPullResult>;
158
+ snapRemove(snapName: string): Promise<void>;
159
+ }
160
+
161
+ type AgentBackend = 'Snap' | 'BitNet' | 'Ollama';
162
+ interface AgentSessionInfo {
163
+ id: string;
164
+ name: string;
165
+ model: string;
166
+ backend: AgentBackend;
167
+ prompt: string;
168
+ status: 'running' | 'stopped' | 'errored';
169
+ pid: number | null;
170
+ }
171
+ interface SpawnerConfig {
172
+ /** Inference snap OpenAI-compatible endpoint (default: http://localhost:9090) */
173
+ snapEndpoint: string;
174
+ /** Max concurrent agent sessions (default: 8) */
175
+ maxSessions: number;
176
+ }
177
+ /**
178
+ * Manages agent process lifecycle on the daemon host.
179
+ *
180
+ * Emits:
181
+ * 'output' → AgentOutputEvent (each stdout/stderr line)
182
+ * 'exit' → AgentExitEvent (process termination)
183
+ */
184
+ declare class SpawnerService extends EventEmitter {
185
+ private readonly sessions;
186
+ private readonly config;
187
+ constructor(overrides?: Partial<SpawnerConfig>);
188
+ /** Spawn a new agent process. Returns the session ID. */
189
+ spawn(name: string, backend: AgentBackend, model: string, prompt: string): string;
190
+ /** Stop a running agent by killing its process. */
191
+ stop(sessionId: string): void;
192
+ /** List all agent sessions. */
193
+ list(): AgentSessionInfo[];
194
+ /** Remove a stopped/errored session. */
195
+ remove(sessionId: string): void;
196
+ /** Kill all running agents (called on daemon shutdown). */
197
+ stopAll(): void;
198
+ }
199
+
200
+ interface JsonRpcResponse {
201
+ jsonrpc: '2.0';
202
+ id: number | string | null;
203
+ result?: unknown;
204
+ error?: {
205
+ code: number;
206
+ message: string;
207
+ data?: unknown;
208
+ };
209
+ }
210
+ /**
211
+ * JSON-RPC 2.0 server over a Unix domain socket.
212
+ * Mirrors RpcServer from packages/editors.
213
+ *
214
+ * Methods:
215
+ * ping → { status: 'ok', pid }
216
+ * harness.list → HarnessInfo[]
217
+ * harness.execute → HarnessCommandResult
218
+ * harness.info → HarnessInfo
219
+ * harness.listRunning → HarnessProcessInfo[]
220
+ * harness.syncConfig → ConfigSyncResult
221
+ * harness.diffConfig → ConfigDiffEntry
222
+ * harness.health → HealthCheckResult
223
+ * session.register → AgentSession
224
+ * session.update → AgentSession
225
+ * session.end → { ok: true }
226
+ * session.list → AgentSession[]
227
+ * session.history → AgentSession[]
228
+ * mail.send → AgentMessage
229
+ * mail.broadcast → { sent: number }
230
+ * mail.inbox → AgentMessage[]
231
+ * mail.markRead → { ok: true }
232
+ * files.reserve → { success, holder? }
233
+ * files.check → FileReservation | null
234
+ * files.release → { released: number }
235
+ * files.list → FileReservation[]
236
+ * tasks.create → AgentTask
237
+ * tasks.claim → { success, owner? }
238
+ * tasks.complete → { ok: boolean }
239
+ * tasks.release → { ok: boolean }
240
+ * tasks.list → AgentTask[]
241
+ * events.log → DaemonEvent
242
+ * events.recent → DaemonEvent[]
243
+ * agent.spawn → { sessionId: string }
244
+ * agent.stop → { ok: true }
245
+ * agent.list → AgentSessionInfo[]
246
+ * agent.remove → { ok: true }
247
+ * inference.ollama.status → OllamaStatus
248
+ * inference.ollama.models → OllamaModel[]
249
+ * inference.ollama.pull → ModelPullResult
250
+ * inference.ollama.delete → { ok: true }
251
+ * inference.ollama.start → { ok: true }
252
+ * inference.ollama.stop → { ok: true }
253
+ * inference.bitnet.status → BitNetStatus
254
+ * inference.snap.list → SnapModel[]
255
+ * inference.snap.status → SnapStatus
256
+ * inference.snap.install → ModelPullResult
257
+ * inference.snap.remove → { ok: true }
258
+ */
259
+ declare class RpcServer {
260
+ private readonly registry;
261
+ private readonly socketPath;
262
+ private readonly store?;
263
+ private server;
264
+ private healthCheckFn;
265
+ private spawner;
266
+ private inference;
267
+ constructor(registry: HarnessRegistry, socketPath: string, store?: DaemonStore | undefined);
268
+ private handleLine;
269
+ private dispatch;
270
+ /** Helper: store not configured error. */
271
+ private noStore;
272
+ /** Helper: missing parameter error. */
273
+ private missingParam;
274
+ /** Helper: service not configured error. */
275
+ private noService;
276
+ /**
277
+ * Dispatch an HTTP request body (JSON-RPC) and call the reply callback.
278
+ * Used by HttpGateway to proxy requests without going through a socket.
279
+ */
280
+ dispatchHttp(body: string, reply: (response: JsonRpcResponse) => void): void;
281
+ /** Set the health check function (called by coordinator after construction). */
282
+ setHealthCheck(fn: () => Promise<unknown>): void;
283
+ /** Attach the spawner service (called by coordinator after construction). */
284
+ setSpawner(spawner: SpawnerService): void;
285
+ /** Attach the inference service (called by coordinator after construction). */
286
+ setInference(inference: InferenceService): void;
287
+ /** Get the spawner service (used by HTTP gateway for SSE). */
288
+ getSpawner(): SpawnerService | null;
289
+ start(): Promise<void>;
290
+ stop(): Promise<void>;
291
+ }
292
+
293
+ /**
294
+ * HTTP gateway that exposes the harness daemon over TCP.
295
+ *
296
+ * Routes:
297
+ * POST /rpc — JSON-RPC 2.0 proxy (same protocol as Unix socket)
298
+ * GET /api/pair — Returns pairing status (requires valid token or no token set)
299
+ * POST /api/pair — Submit pairing code to get a session token
300
+ * GET /api/stream/:id — SSE stream of agent output (real-time)
301
+ * GET / — Serves Studio static frontend (index.html)
302
+ * GET /assets/* — Serves static assets
303
+ *
304
+ * Auth:
305
+ * All /rpc and /api/* requests (except POST /api/pair) require:
306
+ * Authorization: Bearer <session-token>
307
+ * The session token is obtained via the pairing flow.
308
+ */
309
+ interface HttpGatewayConfig {
310
+ /** TCP port to listen on (default: 7890) */
311
+ port: number;
312
+ /** Bind address (default: '0.0.0.0' for Tailscale access) */
313
+ host: string;
314
+ /** Path to Studio static build directory (optional — disables static serving if absent) */
315
+ staticDir?: string;
316
+ /** Reference to the Unix-socket RPC server for dispatching */
317
+ rpcDispatch: RpcServer;
318
+ /** Reference to the spawner service (enables SSE streaming) */
319
+ spawner?: SpawnerService;
320
+ }
321
+ declare class HttpGateway {
322
+ private server;
323
+ private readonly config;
324
+ /** 6-digit pairing code (regenerated on each start) */
325
+ private pairingCode;
326
+ /** Active session tokens (bearer tokens granted after pairing) */
327
+ private sessionTokens;
328
+ /** Whether pairing has been completed at least once */
329
+ private paired;
330
+ constructor(config: HttpGatewayConfig);
331
+ /** The current pairing code (display this in Studio/terminal) */
332
+ getPairingCode(): string;
333
+ /** Regenerate the pairing code (invalidates previous code) */
334
+ regeneratePairingCode(): string;
335
+ start(): Promise<void>;
336
+ stop(): Promise<void>;
337
+ private handleRequest;
338
+ /** Verify the Authorization: Bearer <token> header */
339
+ private checkAuth;
340
+ /** POST /api/pair — submit pairing code, receive session token */
341
+ private handlePair;
342
+ /** GET /api/pair — check pairing status */
343
+ private handlePairStatus;
344
+ /** GET /api/status — daemon status summary */
345
+ private handleStatus;
346
+ /** POST /rpc — proxy JSON-RPC to the daemon's dispatch */
347
+ private handleRpc;
348
+ /** GET /api/stream[/:sessionId] — SSE for agent output and exit events */
349
+ private handleStream;
350
+ /** Serve static files from the Studio build directory */
351
+ private handleStatic;
352
+ }
353
+
110
354
  interface CoordinatorOptions {
111
355
  /** Absolute path to the project root (where .claude/workboard.md lives) */
112
356
  projectRoot: string;
@@ -114,6 +358,12 @@ interface CoordinatorOptions {
114
358
  socketPath?: string;
115
359
  /** Session task description shown in the workboard */
116
360
  task?: string;
361
+ /** Enable HTTP gateway for remote access (default: disabled) */
362
+ httpPort?: number;
363
+ /** HTTP gateway bind address (default: '0.0.0.0') */
364
+ httpHost?: string;
365
+ /** Path to Studio static build for serving via HTTP gateway */
366
+ httpStaticDir?: string;
117
367
  }
118
368
  /**
119
369
  * HarnessCoordinator — single entry point for harness-to-harness coordination.
@@ -132,6 +382,10 @@ declare class HarnessCoordinator {
132
382
  private readonly options;
133
383
  private readonly registry;
134
384
  private rpcServer;
385
+ private httpGateway;
386
+ private store;
387
+ private spawner;
388
+ private inference;
135
389
  private sessionId;
136
390
  private readonly workboard;
137
391
  constructor(options: CoordinatorOptions);
@@ -141,8 +395,12 @@ declare class HarnessCoordinator {
141
395
  getRegistry(): HarnessRegistry;
142
396
  /** The workboard manager. */
143
397
  getWorkboard(): WorkboardManager;
398
+ /** The daemon persistent store (available after start()). */
399
+ getStore(): DaemonStore | null;
144
400
  /** Register a custom adapter (must be called before start()). */
145
401
  registerAdapter(adapter: HarnessAdapter): void;
402
+ /** The HTTP gateway (available after start() if httpPort was set). */
403
+ getHttpGateway(): HttpGateway | null;
146
404
  /** Run a health check across all registered harnesses and the workboard. */
147
405
  healthCheck(): Promise<HealthCheckResult>;
148
406
  }
@@ -168,33 +426,6 @@ declare function findAllHarnessProcesses(): Promise<HarnessProcessInfo[]>;
168
426
  /** Finds Claude Code Unix socket files (used for IPC). */
169
427
  declare function findClaudeCodeSockets(): Promise<string[]>;
170
428
 
171
- /**
172
- * JSON-RPC 2.0 server over a Unix domain socket.
173
- * Mirrors RpcServer from packages/editors.
174
- *
175
- * Methods:
176
- * harness.list → HarnessInfo[]
177
- * harness.execute → HarnessCommandResult
178
- * harness.info → HarnessInfo
179
- * harness.listRunning → HarnessProcessInfo[]
180
- * harness.syncConfig → ConfigSyncResult
181
- * harness.diffConfig → ConfigDiffEntry
182
- * harness.health → HealthCheckResult
183
- */
184
- declare class RpcServer {
185
- private readonly registry;
186
- private readonly socketPath;
187
- private server;
188
- private healthCheckFn;
189
- constructor(registry: HarnessRegistry, socketPath: string);
190
- private handleLine;
191
- private dispatch;
192
- /** Set the health check function (called by coordinator after construction). */
193
- setHealthCheck(fn: () => Promise<unknown>): void;
194
- start(): Promise<void>;
195
- stop(): Promise<void>;
196
- }
197
-
198
429
  /**
199
430
  * @revealui/harnesses — AI Harness Integration System (Server-side)
200
431
  *
@@ -209,4 +440,4 @@ declare class RpcServer {
209
440
  /** Check whether the harnesses feature is licensed for this installation. */
210
441
  declare function checkHarnessesLicense(): Promise<boolean>;
211
442
 
212
- export { ClaudeCodeAdapter, ConfigDiffEntry, ConfigSyncDirection, ConfigSyncResult, type CoordinatorOptions, CursorAdapter, HarnessAdapter, HarnessCapabilities, HarnessCommand, HarnessCommandResult, HarnessCoordinator, HarnessEvent, HarnessInfo, HarnessProcessInfo, HarnessRegistry, HealthCheckResult, RpcServer, WorkboardManager, autoDetectHarnesses, checkHarnessesLicense, diffAllConfigs, diffConfig, findAllHarnessProcesses, findClaudeCodeSockets, findHarnessProcesses, findProcesses, getConfigurableHarnesses, getLocalConfigPath, getRootConfigPath, syncAllConfigs, syncConfig, validateConfigJson };
443
+ export { ClaudeCodeAdapter, ConfigDiffEntry, ConfigSyncDirection, ConfigSyncResult, type CoordinatorOptions, CursorAdapter, DaemonStore, HarnessAdapter, HarnessCapabilities, HarnessCommand, HarnessCommandResult, HarnessCoordinator, HarnessEvent, HarnessInfo, HarnessProcessInfo, HarnessRegistry, HealthCheckResult, RpcServer, WorkboardManager, autoDetectHarnesses, checkHarnessesLicense, diffAllConfigs, diffConfig, findAllHarnessProcesses, findClaudeCodeSockets, findHarnessProcesses, findProcesses, getConfigurableHarnesses, getLocalConfigPath, getRootConfigPath, syncAllConfigs, syncConfig, validateConfigJson };
package/dist/index.js CHANGED
@@ -18,14 +18,18 @@ import {
18
18
  syncAllConfigs,
19
19
  syncConfig,
20
20
  validateConfigJson
21
- } from "./chunk-XLIKSLM3.js";
21
+ } from "./chunk-6E2BKO6U.js";
22
22
  import {
23
23
  buildManifest,
24
24
  diffContent,
25
25
  generateContent,
26
26
  listContent,
27
27
  validateManifest
28
- } from "./chunk-XXEKWC6F.js";
28
+ } from "./chunk-PROC6EJC.js";
29
+ import {
30
+ DaemonStore,
31
+ SCHEMA_SQL
32
+ } from "./chunk-DGQ5OB6L.js";
29
33
  import {
30
34
  WorkboardManager,
31
35
  acquireLock,
@@ -36,14 +40,16 @@ import {
36
40
  releaseLock,
37
41
  withLock,
38
42
  withLockAsync
39
- } from "./chunk-JG6CAG4A.js";
43
+ } from "./chunk-4F4ANKIZ.js";
40
44
  import "./chunk-DGUM43GV.js";
41
45
  export {
42
46
  ClaudeCodeAdapter,
43
47
  CursorAdapter,
48
+ DaemonStore,
44
49
  HarnessCoordinator,
45
50
  HarnessRegistry,
46
51
  RpcServer,
52
+ SCHEMA_SQL,
47
53
  WorkboardManager,
48
54
  acquireLock,
49
55
  atomicWriteSync,
@@ -0,0 +1,170 @@
1
+ /**
2
+ * PGlite schema for the RevDev Harness daemon.
3
+ *
4
+ * Five tables provide persistent state for multi-agent coordination:
5
+ * - agent_sessions: active and historical agent sessions
6
+ * - agent_messages: inter-agent mailbox (point-to-point + broadcast)
7
+ * - file_reservations: advisory file locks with CAS semantics
8
+ * - tasks: claimable work items with CAS ownership
9
+ * - events: append-only event log for audit trail
10
+ *
11
+ * Uses raw SQL (no Drizzle ORM) to keep the daemon dependency-free.
12
+ * PGlite runs in-process — no external database needed.
13
+ */
14
+ /** SQL statements to initialize the daemon database. */
15
+ declare const SCHEMA_SQL = "\n CREATE TABLE IF NOT EXISTS agent_sessions (\n id TEXT PRIMARY KEY,\n env TEXT NOT NULL DEFAULT '',\n task TEXT NOT NULL DEFAULT '(starting)',\n files TEXT NOT NULL DEFAULT '',\n pid INTEGER,\n started_at TIMESTAMP NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMP NOT NULL DEFAULT NOW(),\n ended_at TIMESTAMP,\n exit_summary TEXT\n );\n\n CREATE TABLE IF NOT EXISTS agent_messages (\n id SERIAL PRIMARY KEY,\n from_agent TEXT NOT NULL,\n to_agent TEXT NOT NULL,\n subject TEXT NOT NULL DEFAULT '',\n body TEXT NOT NULL DEFAULT '',\n read BOOLEAN NOT NULL DEFAULT FALSE,\n created_at TIMESTAMP NOT NULL DEFAULT NOW()\n );\n\n CREATE INDEX IF NOT EXISTS idx_messages_to_unread\n ON agent_messages (to_agent, read) WHERE read = FALSE;\n\n CREATE TABLE IF NOT EXISTS file_reservations (\n file_path TEXT PRIMARY KEY,\n agent_id TEXT NOT NULL,\n reserved_at TIMESTAMP NOT NULL DEFAULT NOW(),\n expires_at TIMESTAMP NOT NULL,\n reason TEXT NOT NULL DEFAULT ''\n );\n\n CREATE INDEX IF NOT EXISTS idx_reservations_agent\n ON file_reservations (agent_id);\n\n CREATE TABLE IF NOT EXISTS tasks (\n id TEXT PRIMARY KEY,\n description TEXT NOT NULL DEFAULT '',\n status TEXT NOT NULL DEFAULT 'open',\n owner TEXT,\n claimed_at TIMESTAMP,\n completed_at TIMESTAMP,\n created_at TIMESTAMP NOT NULL DEFAULT NOW()\n );\n\n CREATE INDEX IF NOT EXISTS idx_tasks_status\n ON tasks (status);\n\n CREATE INDEX IF NOT EXISTS idx_tasks_owner\n ON tasks (owner) WHERE owner IS NOT NULL;\n\n CREATE TABLE IF NOT EXISTS events (\n id SERIAL PRIMARY KEY,\n agent_id TEXT NOT NULL,\n event_type TEXT NOT NULL,\n payload JSONB NOT NULL DEFAULT '{}',\n created_at TIMESTAMP NOT NULL DEFAULT NOW()\n );\n\n CREATE INDEX IF NOT EXISTS idx_events_agent\n ON events (agent_id, created_at DESC);\n";
16
+ /** Session row shape. */
17
+ interface AgentSession {
18
+ id: string;
19
+ env: string;
20
+ task: string;
21
+ files: string;
22
+ pid: number | null;
23
+ started_at: string;
24
+ updated_at: string;
25
+ ended_at: string | null;
26
+ exit_summary: string | null;
27
+ }
28
+ /** Message row shape. */
29
+ interface AgentMessage {
30
+ id: number;
31
+ from_agent: string;
32
+ to_agent: string;
33
+ subject: string;
34
+ body: string;
35
+ read: boolean;
36
+ created_at: string;
37
+ }
38
+ /** File reservation row shape. */
39
+ interface FileReservation {
40
+ file_path: string;
41
+ agent_id: string;
42
+ reserved_at: string;
43
+ expires_at: string;
44
+ reason: string;
45
+ }
46
+ /** Task row shape. */
47
+ interface AgentTask {
48
+ id: string;
49
+ description: string;
50
+ status: 'open' | 'claimed' | 'completed';
51
+ owner: string | null;
52
+ claimed_at: string | null;
53
+ completed_at: string | null;
54
+ created_at: string;
55
+ }
56
+ /** Event row shape. */
57
+ interface DaemonEvent {
58
+ id: number;
59
+ agent_id: string;
60
+ event_type: string;
61
+ payload: Record<string, unknown>;
62
+ created_at: string;
63
+ }
64
+
65
+ /**
66
+ * DaemonStore — persistent state for the RevDev Harness daemon.
67
+ *
68
+ * Backed by PGlite (in-process PostgreSQL). The database file lives at
69
+ * ~/.local/share/revealui/harness.db and survives daemon restarts.
70
+ *
71
+ * All methods are async (PGlite queries return promises).
72
+ */
73
+
74
+ /** Configuration for DaemonStore. */
75
+ interface DaemonStoreConfig {
76
+ /** PGlite data directory (default: ~/.local/share/revealui/harness.db) */
77
+ dataDir: string;
78
+ }
79
+ declare class DaemonStore {
80
+ private db;
81
+ private readonly dataDir;
82
+ constructor(config: DaemonStoreConfig);
83
+ /** Initialize PGlite and create tables. */
84
+ init(): Promise<void>;
85
+ /** Shut down the database. */
86
+ close(): Promise<void>;
87
+ private getDb;
88
+ /** Register or update an agent session. */
89
+ registerSession(session: {
90
+ id: string;
91
+ env: string;
92
+ task?: string;
93
+ pid?: number;
94
+ }): Promise<AgentSession>;
95
+ /** Update a session's task and/or files. */
96
+ updateSession(id: string, updates: {
97
+ task?: string;
98
+ files?: string;
99
+ }): Promise<AgentSession | null>;
100
+ /** End a session (mark ended_at, record exit summary). */
101
+ endSession(id: string, exitSummary?: string): Promise<void>;
102
+ /** Get all active sessions (ended_at IS NULL). */
103
+ getActiveSessions(): Promise<AgentSession[]>;
104
+ /** Get session history for an agent (most recent first). */
105
+ getSessionHistory(agentId: string, limit: number): Promise<AgentSession[]>;
106
+ /** Send a message from one agent to another. */
107
+ sendMessage(msg: {
108
+ fromAgent: string;
109
+ toAgent: string;
110
+ subject: string;
111
+ body?: string;
112
+ }): Promise<AgentMessage>;
113
+ /** Broadcast a message to all active agents (except sender). */
114
+ broadcastMessage(msg: {
115
+ fromAgent: string;
116
+ subject: string;
117
+ body?: string;
118
+ }): Promise<number>;
119
+ /** Get unread messages for an agent. */
120
+ getInbox(agentId: string, unreadOnly: boolean): Promise<AgentMessage[]>;
121
+ /** Mark messages as read. */
122
+ markRead(messageIds: number[]): Promise<void>;
123
+ /** Reserve a file for an agent (CAS: fails if already reserved by another). */
124
+ reserveFile(reservation: {
125
+ filePath: string;
126
+ agentId: string;
127
+ ttlSeconds: number;
128
+ reason?: string;
129
+ }): Promise<{
130
+ success: boolean;
131
+ holder?: string;
132
+ }>;
133
+ /** Check who holds a file reservation. */
134
+ checkReservation(filePath: string): Promise<FileReservation | null>;
135
+ /** Release all reservations held by an agent. */
136
+ releaseAllReservations(agentId: string): Promise<number>;
137
+ /** Get all reservations for an agent. */
138
+ getReservations(agentId: string): Promise<FileReservation[]>;
139
+ /** Create a new task. */
140
+ createTask(task: {
141
+ id: string;
142
+ description: string;
143
+ }): Promise<AgentTask>;
144
+ /** Claim a task atomically (CAS: fails if already claimed by another agent). */
145
+ claimTask(taskId: string, agentId: string): Promise<{
146
+ success: boolean;
147
+ owner?: string;
148
+ }>;
149
+ /** Complete a task (only the owner can complete it). */
150
+ completeTask(taskId: string, agentId: string): Promise<boolean>;
151
+ /** Release a claimed task back to open (only the owner can release). */
152
+ releaseTask(taskId: string, agentId: string): Promise<boolean>;
153
+ /** List tasks, optionally filtered by status and/or owner. */
154
+ listTasks(filter?: {
155
+ status?: string;
156
+ owner?: string;
157
+ }): Promise<AgentTask[]>;
158
+ /** Append an event to the audit log. */
159
+ logEvent(event: {
160
+ agentId: string;
161
+ eventType: string;
162
+ payload?: Record<string, unknown>;
163
+ }): Promise<DaemonEvent>;
164
+ /** Get recent events (newest first). */
165
+ getRecentEvents(limit: number): Promise<DaemonEvent[]>;
166
+ /** Prune events older than a given number of days. */
167
+ pruneEvents(olderThanDays: number): Promise<number>;
168
+ }
169
+
170
+ export { type AgentMessage, type AgentSession, type AgentTask, type DaemonEvent, DaemonStore, type DaemonStoreConfig, type FileReservation, SCHEMA_SQL };
@@ -0,0 +1,10 @@
1
+ import {
2
+ DaemonStore,
3
+ SCHEMA_SQL
4
+ } from "../chunk-DGQ5OB6L.js";
5
+ import "../chunk-DGUM43GV.js";
6
+ export {
7
+ DaemonStore,
8
+ SCHEMA_SQL
9
+ };
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -10,7 +10,7 @@ import {
10
10
  unregisterSession,
11
11
  withLock,
12
12
  withLockAsync
13
- } from "../chunk-JG6CAG4A.js";
13
+ } from "../chunk-4F4ANKIZ.js";
14
14
  import "../chunk-DGUM43GV.js";
15
15
  export {
16
16
  WorkboardManager,