@axiom-lattice/local-stores 1.0.2 → 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,
@@ -1511,7 +1530,16 @@ var LocalWorkflowTrackingStore = class {
1511
1530
  const row = this.db.prepare(
1512
1531
  `SELECT * FROM lt_workflow_steps WHERE run_id = ? AND step_type = ? AND step_name = ?`
1513
1532
  ).get(request.runId, request.stepType, request.stepName);
1514
- if (row) return mapRowToStep(row);
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
+ }
1515
1543
  return this.createRunStep(request);
1516
1544
  }
1517
1545
  async updateRunStep(runId, stepId, updates) {
@@ -1599,6 +1627,7 @@ function mapRowToStep(row) {
1599
1627
  tenantId: row.tenant_id,
1600
1628
  stepType: row.step_type,
1601
1629
  stepName: row.step_name,
1630
+ threadId: row.thread_id,
1602
1631
  edgeFrom: row.edge_from || void 0,
1603
1632
  edgeTo: row.edge_to || void 0,
1604
1633
  edgePurpose: row.edge_purpose || void 0,
@@ -2384,6 +2413,19 @@ var LocalChannelInstallationStore = class {
2384
2413
  }
2385
2414
  return rows.map(mapRow);
2386
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
+ }
2387
2429
  async createInstallation(tenantId, installationId, data) {
2388
2430
  const now = nowISO();
2389
2431
  this.db.prepare(
@@ -2633,6 +2675,8 @@ CREATE TABLE IF NOT EXISTS lt_thread_message_queue (
2633
2675
  thread_id TEXT NOT NULL,
2634
2676
  tenant_id TEXT NOT NULL,
2635
2677
  assistant_id TEXT NOT NULL,
2678
+ workspace_id TEXT,
2679
+ project_id TEXT,
2636
2680
  message_content TEXT NOT NULL,
2637
2681
  message_type TEXT NOT NULL DEFAULT 'human',
2638
2682
  sequence_order INTEGER NOT NULL DEFAULT 0,
@@ -2658,13 +2702,15 @@ var LocalThreadMessageQueueStore = class {
2658
2702
  ).get(params.threadId);
2659
2703
  const nextSeq = seqRow.next_seq;
2660
2704
  this.db.prepare(
2661
- `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)
2662
- 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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
2663
2707
  ).run(
2664
2708
  id,
2665
2709
  params.threadId,
2666
2710
  params.tenantId,
2667
2711
  params.assistantId,
2712
+ params.workspaceId || null,
2713
+ params.projectId || null,
2668
2714
  JSON.stringify(params.content),
2669
2715
  params.type || "human",
2670
2716
  nextSeq,
@@ -2682,13 +2728,15 @@ var LocalThreadMessageQueueStore = class {
2682
2728
  `SELECT COALESCE(MAX(sequence_order), 0) + 1 as next_seq FROM lt_thread_message_queue WHERE thread_id = ?`
2683
2729
  ).get(params.threadId);
2684
2730
  this.db.prepare(
2685
- `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)
2686
- 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, ?, ?, ?)`
2687
2733
  ).run(
2688
2734
  id,
2689
2735
  params.threadId,
2690
2736
  params.tenantId,
2691
2737
  params.assistantId,
2738
+ params.workspaceId || null,
2739
+ params.projectId || null,
2692
2740
  JSON.stringify(params.content),
2693
2741
  params.type || "human",
2694
2742
  seqRow.next_seq,
@@ -2718,12 +2766,14 @@ var LocalThreadMessageQueueStore = class {
2718
2766
  }
2719
2767
  async getThreadsWithPendingMessages() {
2720
2768
  const rows = this.db.prepare(
2721
- `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`
2722
2770
  ).all();
2723
2771
  return rows.map((r) => ({
2724
2772
  tenantId: r.tenant_id,
2725
2773
  assistantId: r.assistant_id,
2726
- threadId: r.thread_id
2774
+ threadId: r.thread_id,
2775
+ workspaceId: r.workspace_id || void 0,
2776
+ projectId: r.project_id || void 0
2727
2777
  }));
2728
2778
  }
2729
2779
  async removeMessage(messageId) {
@@ -3256,6 +3306,192 @@ function mapRowToTask(row) {
3256
3306
  };
3257
3307
  }
3258
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
+
3259
3495
  // src/createLocalStoreConfig.ts
3260
3496
  async function createLocalStoreConfig(options = {}) {
3261
3497
  const dbPath = options.dbPath || "~/.axiom/lattice.db";
@@ -3279,6 +3515,7 @@ async function createLocalStoreConfig(options = {}) {
3279
3515
  threadMessageQueue: new LocalThreadMessageQueueStore(db),
3280
3516
  skill: new LocalSkillStore(db),
3281
3517
  schedule: new LocalScheduleStorage(db),
3518
+ task: new LocalTaskStore(db),
3282
3519
  checkpoint: SqliteSaver.fromConnString(dbPath)
3283
3520
  };
3284
3521
  }
@@ -3295,6 +3532,7 @@ export {
3295
3532
  LocalProjectStore,
3296
3533
  LocalScheduleStorage,
3297
3534
  LocalSkillStore,
3535
+ LocalTaskStore,
3298
3536
  LocalTenantStore,
3299
3537
  LocalThreadMessageQueueStore,
3300
3538
  LocalThreadStore,