@hasna/todos 0.11.92 → 0.11.94

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/storage.js CHANGED
@@ -11772,6 +11772,27 @@ function clockColumnsForTable(table) {
11772
11772
  }
11773
11773
 
11774
11774
  // src/storage/local-sqlite.ts
11775
+ var TASK_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
11776
+ function resolveTaskRefLocal(db, ref) {
11777
+ const raw = ref.trim().toLowerCase();
11778
+ if (!raw)
11779
+ return null;
11780
+ if (TASK_UUID_RE.test(raw))
11781
+ return getTask(raw, db);
11782
+ const prefixRows = db.query("SELECT id FROM tasks WHERE LOWER(id) LIKE ? ESCAPE '\\' LIMIT 2").all(`${raw.replace(/[\\%_]/g, (c) => `\\${c}`)}%`);
11783
+ if (prefixRows.length > 1) {
11784
+ throw new Error(`Task reference is ambiguous: "${ref}"`);
11785
+ }
11786
+ if (prefixRows.length === 1)
11787
+ return getTask(prefixRows[0].id, db);
11788
+ const shortIdRows = db.query("SELECT id FROM tasks WHERE LOWER(short_id) = ? LIMIT 2").all(raw);
11789
+ if (shortIdRows.length > 1) {
11790
+ throw new Error(`Task reference is ambiguous: "${ref}"`);
11791
+ }
11792
+ if (shortIdRows.length === 1)
11793
+ return getTask(shortIdRows[0].id, db);
11794
+ return null;
11795
+ }
11775
11796
  function createLocalSqliteTodosStorageAdapter(options = {}) {
11776
11797
  const database = () => options.db ?? getDatabase();
11777
11798
  let adapter;
@@ -11787,6 +11808,7 @@ function createLocalSqliteTodosStorageAdapter(options = {}) {
11787
11808
  tasks: {
11788
11809
  create: (input) => createTask(input, database()),
11789
11810
  get: (id) => getTask(id, database()),
11811
+ resolveRef: (ref) => resolveTaskRefLocal(database(), ref),
11790
11812
  list: (filter = {}) => listTasks(filter, database()),
11791
11813
  count: (filter = {}) => countTasks(filter, database()),
11792
11814
  update: (id, input) => updateTask(id, input, database()),
@@ -12017,7 +12039,6 @@ function postgresTodosCommentCursorIndexSql(tableName = DEFAULT_TODOS_POSTGRES_S
12017
12039
  ON ${tableName} (service, (payload->>'task_id'), (payload->>'created_at'), object_id)
12018
12040
  WHERE object_type = 'comments' AND deleted_at IS NULL`;
12019
12041
  }
12020
-
12021
12042
  class PostgresTodosSyncStore {
12022
12043
  client;
12023
12044
  service;
@@ -12304,6 +12325,7 @@ function createPostgresTodosStorageAdapter(options) {
12304
12325
  tasks: {
12305
12326
  create: (input, context) => createTask2(input, store, context),
12306
12327
  get: (id) => store.get("tasks", id),
12328
+ resolveRef: (ref) => store.resolveTaskRef(ref),
12307
12329
  list: (filter = {}) => store.listTasks(filter),
12308
12330
  count: (filter = {}) => store.countTasks(filter),
12309
12331
  update: (id, input) => updateTask2(id, input, store),
@@ -12556,6 +12578,37 @@ class PostgresJsonRecordStore {
12556
12578
  const row = result.rows[0];
12557
12579
  return row ? payloadRecord2(row.payload) : null;
12558
12580
  }
12581
+ async resolveTaskRef(ref) {
12582
+ await this.ensureSchema();
12583
+ const raw = ref.trim().toLowerCase();
12584
+ if (!raw)
12585
+ return null;
12586
+ const lastCode = raw.charCodeAt(raw.length - 1);
12587
+ if (lastCode < 65535) {
12588
+ const upper = raw.slice(0, -1) + String.fromCharCode(lastCode + 1);
12589
+ const prefixResult = await this.options.client.query(`/* todos:resolve-task-ref-prefix */ SELECT payload FROM ${this.tableName}
12590
+ WHERE service = $1 AND object_type = 'tasks' AND deleted_at IS NULL
12591
+ AND object_id COLLATE "C" >= $2 AND object_id COLLATE "C" < $3
12592
+ LIMIT 2`, [this.service, raw, upper]);
12593
+ if (prefixResult.rows.length > 1) {
12594
+ throw new Error(`Task reference is ambiguous: "${ref}"`);
12595
+ }
12596
+ if (prefixResult.rows.length === 1) {
12597
+ return payloadRecord2(prefixResult.rows[0].payload);
12598
+ }
12599
+ }
12600
+ const shortIdResult = await this.options.client.query(`/* todos:resolve-task-ref-short-id */ SELECT payload FROM ${this.tableName}
12601
+ WHERE service = $1 AND object_type = 'tasks' AND deleted_at IS NULL
12602
+ AND LOWER(payload->>'short_id') = $2
12603
+ LIMIT 2`, [this.service, raw]);
12604
+ if (shortIdResult.rows.length > 1) {
12605
+ throw new Error(`Task reference is ambiguous: "${ref}"`);
12606
+ }
12607
+ if (shortIdResult.rows.length === 1) {
12608
+ return payloadRecord2(shortIdResult.rows[0].payload);
12609
+ }
12610
+ return null;
12611
+ }
12559
12612
  async countTasks(filter) {
12560
12613
  await this.ensureSchema();
12561
12614
  const { where, params } = this.buildTaskFilterSql(filter);
@@ -12977,7 +13030,7 @@ async function updateTask2(id, input, store) {
12977
13030
  tags: input.tags ?? existing.tags,
12978
13031
  metadata: input.metadata ?? existing.metadata,
12979
13032
  requires_approval: input.requires_approval ?? existing.requires_approval,
12980
- task_list_id: input.task_list_id ?? existing.task_list_id
13033
+ task_list_id: input.task_list_id !== undefined ? input.task_list_id : existing.task_list_id
12981
13034
  };
12982
13035
  await store.upsert("tasks", task);
12983
13036
  return task;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/todos",
3
- "version": "0.11.92",
3
+ "version": "0.11.94",
4
4
  "description": "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",