@hasna/todos 0.11.84 → 0.11.86

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
@@ -11909,7 +11909,8 @@ function createPostgresTodosStorageAdapter(options) {
11909
11909
  getActiveWork: (filters) => getActiveWork2(filters, store),
11910
11910
  getChangedSince: (since, filters) => getChangedSince(since, filters, store),
11911
11911
  lock: (id, agentId) => lockTask2(id, agentId, store),
11912
- unlock: (id, agentId) => unlockTask2(id, agentId, store)
11912
+ unlock: (id, agentId) => unlockTask2(id, agentId, store),
11913
+ getByFingerprint: (fingerprint) => store.getTaskByFingerprint(fingerprint)
11913
11914
  },
11914
11915
  dependencies: {
11915
11916
  add: (taskId, dependsOn, context) => addDependency2(taskId, dependsOn, store, context),
@@ -11921,6 +11922,16 @@ function createPostgresTodosStorageAdapter(options) {
11921
11922
  add: (input, context) => addVerification(input, store, context),
11922
11923
  list: (taskId) => listVerifications(taskId, store)
11923
11924
  },
11925
+ commits: {
11926
+ add: (input, context) => addCommit(input, store, context),
11927
+ list: (taskId) => listCommits(taskId, store),
11928
+ find: (sha) => findCommit(sha, store)
11929
+ },
11930
+ gitRefs: {
11931
+ add: (input, context) => addGitRef(input, store, context),
11932
+ list: (taskId) => listGitRefs(taskId, store),
11933
+ find: (ref) => findGitRefs(ref, store)
11934
+ },
11924
11935
  projects: {
11925
11936
  create: (input, context) => createProject2(input, store, context),
11926
11937
  get: (id) => store.get("projects", id),
@@ -11941,7 +11952,9 @@ function createPostgresTodosStorageAdapter(options) {
11941
11952
  get: (id) => store.get("agents", id),
11942
11953
  getByName: async (name) => (await store.list("agents")).find((agent) => agent.name === name) ?? null,
11943
11954
  list: async (options2) => (await store.list("agents")).filter((agent) => options2?.include_archived || agent.status !== "archived").sort((a, b) => a.name.localeCompare(b.name)),
11944
- update: (id, input) => updateAgent2(id, input, store)
11955
+ update: (id, input) => updateAgent2(id, input, store),
11956
+ heartbeat: (idOrName, context) => heartbeatAgent(idOrName, store, context),
11957
+ release: (idOrName, sessionId, context) => releaseAgent2(idOrName, sessionId, store, context)
11945
11958
  },
11946
11959
  taskLists: {
11947
11960
  create: (input, context) => createTaskList2(input, store, context),
@@ -12086,6 +12099,17 @@ class PostgresJsonRecordStore {
12086
12099
  const result = await this.options.client.query(sql, params);
12087
12100
  return result.rows.map((row) => payloadRecord2(row.payload));
12088
12101
  }
12102
+ async getTaskByFingerprint(fingerprint) {
12103
+ await this.ensureSchema();
12104
+ const sql = `/* todos:task-by-fingerprint */ SELECT payload FROM ${this.tableName}
12105
+ WHERE service = $1 AND object_type = $2 AND deleted_at IS NULL
12106
+ AND payload->'metadata'->>'fingerprint' = $3
12107
+ ORDER BY payload->>'created_at' ASC
12108
+ LIMIT 1`;
12109
+ const result = await this.options.client.query(sql, [this.service, "tasks", fingerprint]);
12110
+ const row = result.rows[0];
12111
+ return row ? payloadRecord2(row.payload) : null;
12112
+ }
12089
12113
  async countTasks(filter) {
12090
12114
  await this.ensureSchema();
12091
12115
  const { where, params } = this.buildTaskFilterSql(filter);
@@ -12472,6 +12496,53 @@ async function addVerification(input, store, context) {
12472
12496
  async function listVerifications(taskId, store) {
12473
12497
  return (await store.list("verifications")).filter((verification) => verification.task_id === taskId).sort((a, b) => b.run_at.localeCompare(a.run_at));
12474
12498
  }
12499
+ async function addCommit(input, store, context) {
12500
+ if (!await store.get("tasks", input.task_id))
12501
+ throw new Error(`Task not found: ${input.task_id}`);
12502
+ const timestamp = new Date().toISOString();
12503
+ const commit = {
12504
+ id: randomUUID3(),
12505
+ task_id: input.task_id,
12506
+ sha: input.sha,
12507
+ message: input.message ?? null,
12508
+ author: input.author ?? null,
12509
+ files_changed: input.files_changed ?? null,
12510
+ created_at: timestamp
12511
+ };
12512
+ await store.upsert("commits", { ...commit, updated_at: timestamp }, context);
12513
+ return commit;
12514
+ }
12515
+ async function listCommits(taskId, store) {
12516
+ return (await store.list("commits")).filter((commit) => commit.task_id === taskId).sort((a, b) => b.created_at.localeCompare(a.created_at));
12517
+ }
12518
+ async function findCommit(sha, store) {
12519
+ const matches = (await store.list("commits")).filter((commit) => commit.sha === sha || commit.sha.startsWith(sha) || sha.startsWith(commit.sha)).sort((a, b) => b.created_at.localeCompare(a.created_at));
12520
+ return matches[0] ?? null;
12521
+ }
12522
+ async function addGitRef(input, store, context) {
12523
+ if (!await store.get("tasks", input.task_id))
12524
+ throw new Error(`Task not found: ${input.task_id}`);
12525
+ const timestamp = new Date().toISOString();
12526
+ const gitRef = {
12527
+ id: randomUUID3(),
12528
+ task_id: input.task_id,
12529
+ ref_type: input.ref_type,
12530
+ name: input.name,
12531
+ url: input.url ?? null,
12532
+ provider: input.provider ?? null,
12533
+ metadata: input.metadata ?? {},
12534
+ created_at: timestamp,
12535
+ updated_at: timestamp
12536
+ };
12537
+ await store.upsert("refs", gitRef, context);
12538
+ return gitRef;
12539
+ }
12540
+ async function listGitRefs(taskId, store) {
12541
+ return (await store.list("refs")).filter((ref) => ref.task_id === taskId).sort((a, b) => b.created_at.localeCompare(a.created_at));
12542
+ }
12543
+ async function findGitRefs(ref, store) {
12544
+ return (await store.list("refs")).filter((r) => r.name === ref).sort((a, b) => b.created_at.localeCompare(a.created_at));
12545
+ }
12475
12546
  var TASK_ORDER_BY = "ORDER BY CASE payload->>'priority' WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 ELSE 4 END ASC, payload->>'created_at' ASC, payload->>'id' ASC";
12476
12547
  function toFilterArray(value) {
12477
12548
  return Array.isArray(value) ? value : [value];
@@ -12619,6 +12690,28 @@ async function updateAgent2(id, input, store) {
12619
12690
  last_seen_at: new Date().toISOString()
12620
12691
  });
12621
12692
  }
12693
+ async function resolveAgent(idOrName, store) {
12694
+ const byId = await store.get("agents", idOrName);
12695
+ if (byId)
12696
+ return byId;
12697
+ return (await store.list("agents")).find((agent) => agent.name === idOrName) ?? null;
12698
+ }
12699
+ async function heartbeatAgent(idOrName, store, context) {
12700
+ const agent = await resolveAgent(idOrName, store);
12701
+ if (!agent)
12702
+ return null;
12703
+ return store.upsert("agents", { ...agent, last_seen_at: new Date().toISOString() }, context);
12704
+ }
12705
+ async function releaseAgent2(idOrName, sessionId, store, context) {
12706
+ const agent = await resolveAgent(idOrName, store);
12707
+ if (!agent)
12708
+ return null;
12709
+ if (sessionId && agent.session_id && agent.session_id !== sessionId) {
12710
+ return { agent, released: false };
12711
+ }
12712
+ const updated = await store.upsert("agents", { ...agent, session_id: null, last_seen_at: new Date().toISOString() }, context);
12713
+ return { agent: updated, released: true };
12714
+ }
12622
12715
  async function createTaskList2(input, store, context) {
12623
12716
  const timestamp = new Date().toISOString();
12624
12717
  return store.upsert("task_lists", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/todos",
3
- "version": "0.11.84",
3
+ "version": "0.11.86",
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",