@axiom-lattice/local-stores 1.0.1 → 1.0.3

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/dist/index.mjs CHANGED
@@ -278,6 +278,7 @@ CREATE TABLE IF NOT EXISTS lt_assistants (
278
278
  name TEXT NOT NULL,
279
279
  description TEXT,
280
280
  graph_definition TEXT NOT NULL,
281
+ owner_user_id TEXT,
281
282
  created_at TEXT NOT NULL,
282
283
  updated_at TEXT NOT NULL,
283
284
  PRIMARY KEY (tenant_id, id)
@@ -303,20 +304,22 @@ var LocalAssistantStore = class {
303
304
  async createAssistant(tenantId, id, data) {
304
305
  const now = nowISO();
305
306
  this.db.prepare(
306
- `INSERT INTO lt_assistants (id, tenant_id, name, description, graph_definition, created_at, updated_at)
307
- VALUES (?, ?, ?, ?, ?, ?, ?)
307
+ `INSERT INTO lt_assistants (id, tenant_id, name, description, graph_definition, owner_user_id, created_at, updated_at)
308
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
308
309
  ON CONFLICT(tenant_id, id) DO UPDATE SET
309
310
  name = excluded.name,
310
311
  description = excluded.description,
311
312
  graph_definition = excluded.graph_definition,
313
+ owner_user_id = excluded.owner_user_id,
312
314
  updated_at = excluded.updated_at`
313
- ).run(id, tenantId, data.name, data.description || null, JSON.stringify(data.graphDefinition), now, now);
315
+ ).run(id, tenantId, data.name, data.description || null, JSON.stringify(data.graphDefinition), data.ownerUserId || null, now, now);
314
316
  return {
315
317
  id,
316
318
  tenantId,
317
319
  name: data.name,
318
320
  description: data.description,
319
321
  graphDefinition: data.graphDefinition,
322
+ ownerUserId: data.ownerUserId,
320
323
  createdAt: parseISO(now),
321
324
  updatedAt: parseISO(now)
322
325
  };
@@ -338,6 +341,10 @@ var LocalAssistantStore = class {
338
341
  setClauses.push("graph_definition = ?");
339
342
  values.push(JSON.stringify(updates.graphDefinition));
340
343
  }
344
+ if (updates.ownerUserId !== void 0) {
345
+ setClauses.push("owner_user_id = ?");
346
+ values.push(updates.ownerUserId || null);
347
+ }
341
348
  if (setClauses.length === 0) return existing;
342
349
  const now = nowISO();
343
350
  setClauses.push("updated_at = ?");
@@ -360,6 +367,12 @@ var LocalAssistantStore = class {
360
367
  ).get(tenantId, id);
361
368
  return row !== void 0;
362
369
  }
370
+ async getByOwner(tenantId, userId) {
371
+ const row = this.db.prepare(
372
+ `SELECT * FROM lt_assistants WHERE tenant_id = ? AND owner_user_id = ? LIMIT 1`
373
+ ).get(tenantId, userId);
374
+ return row ? mapRowToAssistant(row) : null;
375
+ }
363
376
  };
364
377
  function mapRowToAssistant(row) {
365
378
  return {
@@ -368,6 +381,7 @@ function mapRowToAssistant(row) {
368
381
  name: row.name,
369
382
  description: row.description || void 0,
370
383
  graphDefinition: JSON.parse(row.graph_definition),
384
+ ownerUserId: row.owner_user_id || void 0,
371
385
  createdAt: parseISO(row.created_at),
372
386
  updatedAt: parseISO(row.updated_at)
373
387
  };
@@ -1356,6 +1370,7 @@ CREATE TABLE IF NOT EXISTS lt_workflow_steps (
1356
1370
  tenant_id TEXT NOT NULL,
1357
1371
  step_type TEXT NOT NULL,
1358
1372
  step_name TEXT NOT NULL,
1373
+ thread_id TEXT,
1359
1374
  edge_from TEXT,
1360
1375
  edge_to TEXT,
1361
1376
  edge_purpose TEXT,
@@ -1371,6 +1386,8 @@ CREATE TABLE IF NOT EXISTS lt_workflow_steps (
1371
1386
  PRIMARY KEY (run_id, id)
1372
1387
  );
1373
1388
  CREATE INDEX IF NOT EXISTS idx_lt_ws_type ON lt_workflow_steps(run_id, step_type);
1389
+ -- Backfill for existing databases that don't have the column
1390
+ ALTER TABLE lt_workflow_steps ADD COLUMN IF NOT EXISTS thread_id TEXT;
1374
1391
  `;
1375
1392
  var LocalWorkflowTrackingStore = class {
1376
1393
  constructor(db) {
@@ -1475,14 +1492,15 @@ var LocalWorkflowTrackingStore = class {
1475
1492
  const now = nowISO();
1476
1493
  const id = `step_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1477
1494
  this.db.prepare(
1478
- `INSERT INTO lt_workflow_steps (id, run_id, tenant_id, step_type, step_name, edge_from, edge_to, edge_purpose, input, status, started_at, created_at, updated_at)
1479
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'running', ?, ?, ?)`
1495
+ `INSERT INTO lt_workflow_steps (id, run_id, tenant_id, step_type, step_name, thread_id, edge_from, edge_to, edge_purpose, input, status, started_at, created_at, updated_at)
1496
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'running', ?, ?, ?)`
1480
1497
  ).run(
1481
1498
  id,
1482
1499
  request.runId,
1483
1500
  request.tenantId,
1484
1501
  request.stepType,
1485
1502
  request.stepName,
1503
+ request.threadId || null,
1486
1504
  request.edgeFrom || null,
1487
1505
  request.edgeTo || null,
1488
1506
  request.edgePurpose || null,
@@ -1497,6 +1515,7 @@ var LocalWorkflowTrackingStore = class {
1497
1515
  tenantId: request.tenantId,
1498
1516
  stepType: request.stepType,
1499
1517
  stepName: request.stepName,
1518
+ threadId: request.threadId,
1500
1519
  edgeFrom: request.edgeFrom,
1501
1520
  edgeTo: request.edgeTo,
1502
1521
  edgePurpose: request.edgePurpose,
@@ -1507,6 +1526,22 @@ var LocalWorkflowTrackingStore = class {
1507
1526
  updatedAt: parseISO(now)
1508
1527
  };
1509
1528
  }
1529
+ async upsertRunStep(request) {
1530
+ const row = this.db.prepare(
1531
+ `SELECT * FROM lt_workflow_steps WHERE run_id = ? AND step_type = ? AND step_name = ?`
1532
+ ).get(request.runId, request.stepType, request.stepName);
1533
+ if (row) {
1534
+ const existing = mapRowToStep(row);
1535
+ if (!existing.threadId && request.threadId) {
1536
+ this.db.prepare(
1537
+ `UPDATE lt_workflow_steps SET thread_id = ?, updated_at = ? WHERE run_id = ? AND id = ?`
1538
+ ).run(request.threadId, nowISO(), request.runId, existing.id);
1539
+ existing.threadId = request.threadId;
1540
+ }
1541
+ return existing;
1542
+ }
1543
+ return this.createRunStep(request);
1544
+ }
1510
1545
  async updateRunStep(runId, stepId, updates) {
1511
1546
  const setClauses = [];
1512
1547
  const values = [];
@@ -1592,6 +1627,7 @@ function mapRowToStep(row) {
1592
1627
  tenantId: row.tenant_id,
1593
1628
  stepType: row.step_type,
1594
1629
  stepName: row.step_name,
1630
+ threadId: row.thread_id,
1595
1631
  edgeFrom: row.edge_from || void 0,
1596
1632
  edgeTo: row.edge_to || void 0,
1597
1633
  edgePurpose: row.edge_purpose || void 0,
@@ -2377,6 +2413,19 @@ var LocalChannelInstallationStore = class {
2377
2413
  }
2378
2414
  return rows.map(mapRow);
2379
2415
  }
2416
+ async getAllInstallations(channel) {
2417
+ let rows;
2418
+ if (channel) {
2419
+ rows = this.db.prepare(
2420
+ `SELECT * FROM lt_channel_installations WHERE channel = ? ORDER BY created_at DESC`
2421
+ ).all(channel);
2422
+ } else {
2423
+ rows = this.db.prepare(
2424
+ `SELECT * FROM lt_channel_installations ORDER BY created_at DESC`
2425
+ ).all();
2426
+ }
2427
+ return rows.map(mapRow);
2428
+ }
2380
2429
  async createInstallation(tenantId, installationId, data) {
2381
2430
  const now = nowISO();
2382
2431
  this.db.prepare(
@@ -2626,6 +2675,8 @@ CREATE TABLE IF NOT EXISTS lt_thread_message_queue (
2626
2675
  thread_id TEXT NOT NULL,
2627
2676
  tenant_id TEXT NOT NULL,
2628
2677
  assistant_id TEXT NOT NULL,
2678
+ workspace_id TEXT,
2679
+ project_id TEXT,
2629
2680
  message_content TEXT NOT NULL,
2630
2681
  message_type TEXT NOT NULL DEFAULT 'human',
2631
2682
  sequence_order INTEGER NOT NULL DEFAULT 0,
@@ -2651,13 +2702,15 @@ var LocalThreadMessageQueueStore = class {
2651
2702
  ).get(params.threadId);
2652
2703
  const nextSeq = seqRow.next_seq;
2653
2704
  this.db.prepare(
2654
- `INSERT INTO lt_thread_message_queue (id, thread_id, tenant_id, assistant_id, message_content, message_type, sequence_order, priority, command, custom_run_config, created_at)
2655
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
2705
+ `INSERT INTO lt_thread_message_queue (id, thread_id, tenant_id, assistant_id, workspace_id, project_id, message_content, message_type, sequence_order, priority, command, custom_run_config, created_at)
2706
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
2656
2707
  ).run(
2657
2708
  id,
2658
2709
  params.threadId,
2659
2710
  params.tenantId,
2660
2711
  params.assistantId,
2712
+ params.workspaceId || null,
2713
+ params.projectId || null,
2661
2714
  JSON.stringify(params.content),
2662
2715
  params.type || "human",
2663
2716
  nextSeq,
@@ -2675,13 +2728,15 @@ var LocalThreadMessageQueueStore = class {
2675
2728
  `SELECT COALESCE(MAX(sequence_order), 0) + 1 as next_seq FROM lt_thread_message_queue WHERE thread_id = ?`
2676
2729
  ).get(params.threadId);
2677
2730
  this.db.prepare(
2678
- `INSERT INTO lt_thread_message_queue (id, thread_id, tenant_id, assistant_id, message_content, message_type, sequence_order, priority, command, custom_run_config, created_at)
2679
- VALUES (?, ?, ?, ?, ?, ?, ?, 100, ?, ?, ?)`
2731
+ `INSERT INTO lt_thread_message_queue (id, thread_id, tenant_id, assistant_id, workspace_id, project_id, message_content, message_type, sequence_order, priority, command, custom_run_config, created_at)
2732
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 100, ?, ?, ?)`
2680
2733
  ).run(
2681
2734
  id,
2682
2735
  params.threadId,
2683
2736
  params.tenantId,
2684
2737
  params.assistantId,
2738
+ params.workspaceId || null,
2739
+ params.projectId || null,
2685
2740
  JSON.stringify(params.content),
2686
2741
  params.type || "human",
2687
2742
  seqRow.next_seq,
@@ -2711,12 +2766,14 @@ var LocalThreadMessageQueueStore = class {
2711
2766
  }
2712
2767
  async getThreadsWithPendingMessages() {
2713
2768
  const rows = this.db.prepare(
2714
- `SELECT DISTINCT tenant_id, assistant_id, thread_id FROM lt_thread_message_queue WHERE status IN ('pending', 'processing') ORDER BY thread_id`
2769
+ `SELECT DISTINCT ON (thread_id) tenant_id, assistant_id, thread_id, workspace_id, project_id FROM lt_thread_message_queue WHERE status IN ('pending', 'processing') ORDER BY thread_id`
2715
2770
  ).all();
2716
2771
  return rows.map((r) => ({
2717
2772
  tenantId: r.tenant_id,
2718
2773
  assistantId: r.assistant_id,
2719
- threadId: r.thread_id
2774
+ threadId: r.thread_id,
2775
+ workspaceId: r.workspace_id || void 0,
2776
+ projectId: r.project_id || void 0
2720
2777
  }));
2721
2778
  }
2722
2779
  async removeMessage(messageId) {
@@ -3249,6 +3306,192 @@ function mapRowToTask(row) {
3249
3306
  };
3250
3307
  }
3251
3308
 
3309
+ // src/stores/LocalTaskStore.ts
3310
+ import { randomUUID as randomUUID5 } from "crypto";
3311
+ var DDL19 = `
3312
+ CREATE TABLE IF NOT EXISTS lt_tasks (
3313
+ id TEXT NOT NULL,
3314
+ tenant_id TEXT NOT NULL,
3315
+ owner_type TEXT NOT NULL DEFAULT 'user',
3316
+ owner_id TEXT NOT NULL,
3317
+ title TEXT NOT NULL,
3318
+ description TEXT,
3319
+ status TEXT NOT NULL DEFAULT 'pending',
3320
+ priority TEXT NOT NULL DEFAULT 'medium',
3321
+ due_date TEXT,
3322
+ metadata TEXT,
3323
+ parent_id TEXT,
3324
+ source_id TEXT,
3325
+ context TEXT,
3326
+ created_at TEXT NOT NULL,
3327
+ updated_at TEXT NOT NULL,
3328
+ PRIMARY KEY (tenant_id, id)
3329
+ );
3330
+ `;
3331
+ function mapRowToTask2(row) {
3332
+ return {
3333
+ id: row.id,
3334
+ tenantId: row.tenant_id,
3335
+ ownerType: row.owner_type,
3336
+ ownerId: row.owner_id,
3337
+ title: row.title,
3338
+ description: row.description ?? void 0,
3339
+ status: row.status,
3340
+ priority: row.priority,
3341
+ dueDate: row.due_date ?? void 0,
3342
+ metadata: row.metadata ? JSON.parse(row.metadata) : void 0,
3343
+ parentId: row.parent_id ?? void 0,
3344
+ sourceId: row.source_id ?? void 0,
3345
+ context: row.context ? JSON.parse(row.context) : void 0,
3346
+ createdAt: parseISO(row.created_at),
3347
+ updatedAt: parseISO(row.updated_at)
3348
+ };
3349
+ }
3350
+ var LocalTaskStore = class {
3351
+ constructor(db) {
3352
+ this.db = db;
3353
+ ensureTable(db, DDL19);
3354
+ }
3355
+ async create(params) {
3356
+ const id = randomUUID5();
3357
+ const now = nowISO();
3358
+ this.db.prepare(
3359
+ `INSERT INTO lt_tasks (id, tenant_id, owner_type, owner_id, title, description, status, priority, due_date, metadata, parent_id, source_id, context, created_at, updated_at)
3360
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
3361
+ ).run(
3362
+ id,
3363
+ params.tenantId,
3364
+ params.ownerType,
3365
+ params.ownerId,
3366
+ params.title,
3367
+ params.description || null,
3368
+ params.status || "pending",
3369
+ params.priority || "medium",
3370
+ params.dueDate || null,
3371
+ params.metadata ? JSON.stringify(params.metadata) : null,
3372
+ params.parentId || null,
3373
+ params.sourceId || null,
3374
+ params.context ? JSON.stringify(params.context) : null,
3375
+ now,
3376
+ now
3377
+ );
3378
+ return await this.getById(params.tenantId, id);
3379
+ }
3380
+ async getById(tenantId, id) {
3381
+ const row = this.db.prepare(
3382
+ `SELECT * FROM lt_tasks WHERE tenant_id = ? AND id = ?`
3383
+ ).get(tenantId, id);
3384
+ return row ? mapRowToTask2(row) : null;
3385
+ }
3386
+ async list(filter) {
3387
+ const conditions = ["tenant_id = ?"];
3388
+ const params = [filter.tenantId];
3389
+ if (filter.ownerType) {
3390
+ conditions.push("owner_type = ?");
3391
+ params.push(filter.ownerType);
3392
+ }
3393
+ if (filter.ownerId) {
3394
+ conditions.push("owner_id = ?");
3395
+ params.push(filter.ownerId);
3396
+ }
3397
+ if (filter.status) {
3398
+ conditions.push("status = ?");
3399
+ params.push(filter.status);
3400
+ }
3401
+ if (filter.priority) {
3402
+ conditions.push("priority = ?");
3403
+ params.push(filter.priority);
3404
+ }
3405
+ if (filter.parentId) {
3406
+ conditions.push("parent_id = ?");
3407
+ params.push(filter.parentId);
3408
+ }
3409
+ if (filter.sourceId) {
3410
+ conditions.push("source_id = ?");
3411
+ params.push(filter.sourceId);
3412
+ }
3413
+ if (filter.metadata) {
3414
+ for (const [key, value] of Object.entries(filter.metadata)) {
3415
+ const safeKey = key.replace(/[^a-zA-Z0-9_]/g, "");
3416
+ if (safeKey) {
3417
+ conditions.push(`json_extract(metadata, '$.${safeKey}') = ?`);
3418
+ params.push(String(value));
3419
+ }
3420
+ }
3421
+ }
3422
+ const where = conditions.join(" AND ");
3423
+ const limit = filter.limit || 100;
3424
+ const offset = filter.offset || 0;
3425
+ const rows = this.db.prepare(
3426
+ `SELECT * FROM lt_tasks WHERE ${where} ORDER BY created_at DESC LIMIT ? OFFSET ?`
3427
+ ).all(...params, limit, offset);
3428
+ return rows.map(mapRowToTask2);
3429
+ }
3430
+ async update(tenantId, id, updates) {
3431
+ const existing = await this.getById(tenantId, id);
3432
+ if (!existing) return null;
3433
+ const now = nowISO();
3434
+ const setClauses = ["updated_at = ?"];
3435
+ const values = [now];
3436
+ if (updates.title !== void 0) {
3437
+ setClauses.push("title = ?");
3438
+ values.push(updates.title);
3439
+ }
3440
+ if (updates.description !== void 0) {
3441
+ setClauses.push("description = ?");
3442
+ values.push(updates.description);
3443
+ }
3444
+ if (updates.status !== void 0) {
3445
+ setClauses.push("status = ?");
3446
+ values.push(updates.status);
3447
+ }
3448
+ if (updates.priority !== void 0) {
3449
+ setClauses.push("priority = ?");
3450
+ values.push(updates.priority);
3451
+ }
3452
+ if (updates.dueDate !== void 0) {
3453
+ setClauses.push("due_date = ?");
3454
+ values.push(updates.dueDate);
3455
+ }
3456
+ if (updates.metadata !== void 0) {
3457
+ setClauses.push("metadata = ?");
3458
+ values.push(JSON.stringify(updates.metadata));
3459
+ }
3460
+ if (updates.parentId !== void 0) {
3461
+ setClauses.push("parent_id = ?");
3462
+ values.push(updates.parentId);
3463
+ }
3464
+ if (updates.sourceId !== void 0) {
3465
+ setClauses.push("source_id = ?");
3466
+ values.push(updates.sourceId);
3467
+ }
3468
+ if (updates.context !== void 0) {
3469
+ setClauses.push("context = ?");
3470
+ values.push(JSON.stringify(updates.context));
3471
+ }
3472
+ if (updates.ownerType !== void 0) {
3473
+ setClauses.push("owner_type = ?");
3474
+ values.push(updates.ownerType);
3475
+ }
3476
+ if (updates.ownerId !== void 0) {
3477
+ setClauses.push("owner_id = ?");
3478
+ values.push(updates.ownerId);
3479
+ }
3480
+ if (setClauses.length === 1) return existing;
3481
+ values.push(tenantId, id);
3482
+ this.db.prepare(
3483
+ `UPDATE lt_tasks SET ${setClauses.join(", ")} WHERE tenant_id = ? AND id = ?`
3484
+ ).run(...values);
3485
+ return this.getById(tenantId, id);
3486
+ }
3487
+ async delete(tenantId, id) {
3488
+ const result = this.db.prepare(
3489
+ `DELETE FROM lt_tasks WHERE tenant_id = ? AND id = ?`
3490
+ ).run(tenantId, id);
3491
+ return result.changes > 0;
3492
+ }
3493
+ };
3494
+
3252
3495
  // src/createLocalStoreConfig.ts
3253
3496
  async function createLocalStoreConfig(options = {}) {
3254
3497
  const dbPath = options.dbPath || "~/.axiom/lattice.db";
@@ -3272,6 +3515,7 @@ async function createLocalStoreConfig(options = {}) {
3272
3515
  threadMessageQueue: new LocalThreadMessageQueueStore(db),
3273
3516
  skill: new LocalSkillStore(db),
3274
3517
  schedule: new LocalScheduleStorage(db),
3518
+ task: new LocalTaskStore(db),
3275
3519
  checkpoint: SqliteSaver.fromConnString(dbPath)
3276
3520
  };
3277
3521
  }
@@ -3288,6 +3532,7 @@ export {
3288
3532
  LocalProjectStore,
3289
3533
  LocalScheduleStorage,
3290
3534
  LocalSkillStore,
3535
+ LocalTaskStore,
3291
3536
  LocalTenantStore,
3292
3537
  LocalThreadMessageQueueStore,
3293
3538
  LocalThreadStore,