@hasna/todos 0.13.12 → 0.15.1

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.
Files changed (47) hide show
  1. package/README.md +2 -0
  2. package/dist/cli/commands/agent-commands.d.ts +39 -0
  3. package/dist/cli/commands/agent-commands.d.ts.map +1 -1
  4. package/dist/cli/commands/config-serve-commands.d.ts.map +1 -1
  5. package/dist/cli/commands/dispatch.d.ts.map +1 -1
  6. package/dist/cli/commands/mcp-hooks-commands.d.ts.map +1 -1
  7. package/dist/cli/commands/project-commands.d.ts.map +1 -1
  8. package/dist/cli/commands/task-commands.d.ts.map +1 -1
  9. package/dist/cli/helpers.d.ts +64 -2
  10. package/dist/cli/helpers.d.ts.map +1 -1
  11. package/dist/cli/index.js +624 -98
  12. package/dist/cli/stage-a.d.ts.map +1 -1
  13. package/dist/contracts.js +123 -116
  14. package/dist/db/database.d.ts.map +1 -1
  15. package/dist/db/task-crud.d.ts.map +1 -1
  16. package/dist/index.js +135 -127
  17. package/dist/lib/bulk-tags.d.ts +57 -0
  18. package/dist/lib/bulk-tags.d.ts.map +1 -0
  19. package/dist/lib/enum-vocabulary.d.ts +72 -0
  20. package/dist/lib/enum-vocabulary.d.ts.map +1 -0
  21. package/dist/lib/run-records.d.ts.map +1 -1
  22. package/dist/lib/sandbox-profiles.d.ts.map +1 -1
  23. package/dist/lib/saved-search-views.d.ts +12 -1
  24. package/dist/lib/saved-search-views.d.ts.map +1 -1
  25. package/dist/lib/sync-utils.d.ts +1 -1
  26. package/dist/lib/sync-utils.d.ts.map +1 -1
  27. package/dist/mcp/index.d.ts.map +1 -1
  28. package/dist/mcp/index.js +289 -82
  29. package/dist/mcp/tools/agents.d.ts.map +1 -1
  30. package/dist/mcp/tools/task-auto-tools.d.ts.map +1 -1
  31. package/dist/mcp/tools/task-crud.d.ts +1 -0
  32. package/dist/mcp/tools/task-crud.d.ts.map +1 -1
  33. package/dist/mcp.js +1 -1
  34. package/dist/registry.js +123 -116
  35. package/dist/release-provenance.json +5 -5
  36. package/dist/sdk/index.js +3 -2
  37. package/dist/sdk/v1.generated.d.ts +2 -2
  38. package/dist/sdk/v1.generated.d.ts.map +1 -1
  39. package/dist/server/index.js +245 -38
  40. package/dist/server/openapi.d.ts +58 -0
  41. package/dist/server/openapi.d.ts.map +1 -1
  42. package/dist/server/routes.d.ts.map +1 -1
  43. package/dist/server/v1.d.ts.map +1 -1
  44. package/dist/storage.js +124 -115
  45. package/dist/types/index.d.ts +11 -0
  46. package/dist/types/index.d.ts.map +1 -1
  47. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"stage-a.d.ts","sourceRoot":"","sources":["../../src/cli/stage-a.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,WAAW,CAAC;AAO1C,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,MAAM,MAAM,+BAA+B,GACvC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,IAAI,CAAA;CAAE,GACrC;IAAE,KAAK,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC1D;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,aAAa,GAAG,YAAY,CAAC;AAyB/E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;CA8BgB,CAAC;AAsBvD,wBAAgB,kCAAkC,IAAI,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAE9F;AAED;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,+BAA+B,CAAC,OAAO,CAAC,GAC9C,OAAO,CAKT;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,+BAA+B,CAAC,OAAO,CAAC,GAAG,IAAI,CASnH;AAkTD;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,GAAE,MAAM,EAA0B,EACtC,GAAG,GAAE,GAAwB,GAC5B,+BAA+B,CAgBjC"}
1
+ {"version":3,"file":"stage-a.d.ts","sourceRoot":"","sources":["../../src/cli/stage-a.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,WAAW,CAAC;AAO1C,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,MAAM,MAAM,+BAA+B,GACvC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,IAAI,CAAA;CAAE,GACrC;IAAE,KAAK,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC1D;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,aAAa,GAAG,YAAY,CAAC;AAyB/E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;CA8BgB,CAAC;AAoEvD,wBAAgB,kCAAkC,IAAI,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAE9F;AAED;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,+BAA+B,CAAC,OAAO,CAAC,GAC9C,OAAO,CAKT;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,+BAA+B,CAAC,OAAO,CAAC,GAAG,IAAI,CASnH;AAuWD;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,GAAE,MAAM,EAA0B,EACtC,GAAG,GAAE,GAAwB,GAC5B,+BAA+B,CAgBjC"}
package/dist/contracts.js CHANGED
@@ -3430,6 +3430,9 @@ var init_machines = __esm(() => {
3430
3430
  function isBlockingDependencyStatus(status) {
3431
3431
  return status !== "completed" && status !== "cancelled";
3432
3432
  }
3433
+ function isTerminalStatus(status) {
3434
+ return status === "completed" || status === "failed" || status === "cancelled";
3435
+ }
3433
3436
  var TASK_STATUSES, TASK_PRIORITIES, PLAN_STATUSES, VersionConflictError, TaskNotFoundError, TaskNotStartableError, TaskReferenceAmbiguousError, ProjectNotFoundError, ResourceConflictError, PlanNotFoundError, LockError, AgentNotFoundError, IdentityAliasAmbiguousError, IdentityIdImmutableError, TaskListNotFoundError, DependencyCycleError, CompletionGuardError, DISPATCH_STATUSES, DispatchNotFoundError;
3434
3437
  var init_types = __esm(() => {
3435
3438
  TASK_STATUSES = [
@@ -3787,6 +3790,103 @@ var init_identity_mapping = __esm(() => {
3787
3790
  });
3788
3791
  });
3789
3792
 
3793
+ // src/lib/sync-utils.ts
3794
+ import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
3795
+ import { createHash } from "crypto";
3796
+ import { homedir } from "os";
3797
+ import { join } from "path";
3798
+ function getHomeDir() {
3799
+ return process.env["HOME"] || process.env["USERPROFILE"] || homedir();
3800
+ }
3801
+ function getTodosGlobalDir() {
3802
+ return join(getHomeDir(), ".hasna", "todos");
3803
+ }
3804
+ function ensureDir(dir) {
3805
+ if (!existsSync2(dir))
3806
+ mkdirSync(dir, { recursive: true });
3807
+ }
3808
+ function listJsonFiles(dir) {
3809
+ if (!existsSync2(dir))
3810
+ return [];
3811
+ return readdirSync(dir).filter((f) => f.endsWith(".json"));
3812
+ }
3813
+ function readJsonFile(path) {
3814
+ try {
3815
+ return JSON.parse(readFileSync(path, "utf-8"));
3816
+ } catch {
3817
+ return null;
3818
+ }
3819
+ }
3820
+ function writeJsonFile(path, data) {
3821
+ writeFileSync(path, JSON.stringify(data, null, 2) + `
3822
+ `);
3823
+ }
3824
+ function readHighWaterMark(dir) {
3825
+ const path = join(dir, ".highwatermark");
3826
+ if (!existsSync2(path))
3827
+ return 1;
3828
+ const val = parseInt(readFileSync(path, "utf-8").trim(), 10);
3829
+ return isNaN(val) ? 1 : val;
3830
+ }
3831
+ function writeHighWaterMark(dir, value) {
3832
+ writeFileSync(join(dir, ".highwatermark"), String(value));
3833
+ }
3834
+ function getFileMtimeMs(path) {
3835
+ try {
3836
+ return statSync(path).mtimeMs;
3837
+ } catch {
3838
+ return null;
3839
+ }
3840
+ }
3841
+ function parseTimestamp(value) {
3842
+ if (typeof value !== "string")
3843
+ return null;
3844
+ const parsed = Date.parse(value);
3845
+ return Number.isNaN(parsed) ? null : parsed;
3846
+ }
3847
+ function appendSyncConflict(metadata, conflict, limit = 5) {
3848
+ const current = Array.isArray(metadata["sync_conflicts"]) ? metadata["sync_conflicts"] : [];
3849
+ const next = [conflict, ...current].slice(0, limit);
3850
+ return { ...metadata, sync_conflicts: next };
3851
+ }
3852
+ function canonicalize(value) {
3853
+ if (Array.isArray(value))
3854
+ return value.map(canonicalize);
3855
+ if (!value || typeof value !== "object")
3856
+ return value;
3857
+ const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== undefined).sort(([a], [b]) => a.localeCompare(b));
3858
+ return Object.fromEntries(entries.map(([key, entryValue]) => [key, canonicalize(entryValue)]));
3859
+ }
3860
+ function withoutSyncFingerprintMetadata(metadata) {
3861
+ const { [TODO_SYNC_FINGERPRINT_KEY]: _fingerprint, ...rest } = metadata;
3862
+ return rest;
3863
+ }
3864
+ function syncFingerprint(record) {
3865
+ const metadata = withoutSyncFingerprintMetadata(record.metadata || {});
3866
+ const canonical = canonicalize({ ...record, metadata });
3867
+ return `sha256:${createHash("sha256").update(JSON.stringify(canonical)).digest("hex")}`;
3868
+ }
3869
+ function withSyncFingerprint(record) {
3870
+ const metadata = withoutSyncFingerprintMetadata(record.metadata);
3871
+ return {
3872
+ ...record,
3873
+ metadata: {
3874
+ ...metadata,
3875
+ [TODO_SYNC_FINGERPRINT_KEY]: syncFingerprint({ ...record, metadata })
3876
+ }
3877
+ };
3878
+ }
3879
+ function hasSyncFingerprintChanged(record) {
3880
+ const stored = record.metadata?.[TODO_SYNC_FINGERPRINT_KEY];
3881
+ if (typeof stored !== "string" || stored.length === 0)
3882
+ return null;
3883
+ return stored !== syncFingerprint(record);
3884
+ }
3885
+ var TODO_SYNC_FINGERPRINT_KEY = "todos_sync_fingerprint", HOME;
3886
+ var init_sync_utils = __esm(() => {
3887
+ HOME = getHomeDir();
3888
+ });
3889
+
3790
3890
  // src/storage/config.ts
3791
3891
  var exports_config = {};
3792
3892
  __export(exports_config, {
@@ -4117,8 +4217,8 @@ __export(exports_database, {
4117
4217
  LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
4118
4218
  });
4119
4219
  import { Database } from "bun:sqlite";
4120
- import { existsSync as existsSync2, mkdirSync } from "fs";
4121
- import { dirname, join, resolve as resolve2 } from "path";
4220
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
4221
+ import { dirname, join as join2, resolve as resolve2 } from "path";
4122
4222
  function isInMemoryDb(path) {
4123
4223
  return path === ":memory:" || path.startsWith("file::memory:");
4124
4224
  }
@@ -4127,8 +4227,8 @@ function findNearestProjectDb(startDir) {
4127
4227
  const stopAt = gitRoot ? resolve2(gitRoot) : resolve2(startDir);
4128
4228
  let dir = resolve2(startDir);
4129
4229
  while (true) {
4130
- const candidate = join(dir, ".hasna", "todos", "todos.db");
4131
- if (existsSync2(candidate))
4230
+ const candidate = join2(dir, ".hasna", "todos", "todos.db");
4231
+ if (existsSync3(candidate))
4132
4232
  return candidate;
4133
4233
  if (dir === stopAt)
4134
4234
  break;
@@ -4142,7 +4242,7 @@ function findNearestProjectDb(startDir) {
4142
4242
  function findGitRoot(startDir) {
4143
4243
  let dir = resolve2(startDir);
4144
4244
  while (true) {
4145
- if (existsSync2(join(dir, ".git")))
4245
+ if (existsSync3(join2(dir, ".git")))
4146
4246
  return dir;
4147
4247
  const parent = dirname(dir);
4148
4248
  if (parent === dir)
@@ -4152,8 +4252,7 @@ function findGitRoot(startDir) {
4152
4252
  return null;
4153
4253
  }
4154
4254
  function getGlobalDbPath() {
4155
- const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
4156
- return join(home, ".hasna", "todos", "todos.db");
4255
+ return join2(getHomeDir(), ".hasna", "todos", "todos.db");
4157
4256
  }
4158
4257
  function hasExplicitProjectArg(args = process.argv.slice(2)) {
4159
4258
  return args.some((arg) => arg === "--project" || arg.startsWith("--project="));
@@ -4191,7 +4290,7 @@ function getDbPath() {
4191
4290
  if (process.env["TODOS_DB_SCOPE"] === "project") {
4192
4291
  const gitRoot = findGitRoot(cwd);
4193
4292
  if (gitRoot && canCreateScopedProjectDb()) {
4194
- return join(gitRoot, ".hasna", "todos", "todos.db");
4293
+ return join2(gitRoot, ".hasna", "todos", "todos.db");
4195
4294
  }
4196
4295
  }
4197
4296
  return getGlobalDbPath();
@@ -4199,16 +4298,16 @@ function getDbPath() {
4199
4298
  function getDatabasePath() {
4200
4299
  return getDbPath();
4201
4300
  }
4202
- function ensureDir(filePath) {
4301
+ function ensureDir2(filePath) {
4203
4302
  if (isInMemoryDb(filePath))
4204
4303
  return;
4205
4304
  const dir = dirname(resolve2(filePath));
4206
- if (!existsSync2(dir)) {
4207
- mkdirSync(dir, { recursive: true });
4305
+ if (!existsSync3(dir)) {
4306
+ mkdirSync2(dir, { recursive: true });
4208
4307
  }
4209
4308
  }
4210
4309
  function openDatabase(path) {
4211
- ensureDir(path);
4310
+ ensureDir2(path);
4212
4311
  const db = new Database(path);
4213
4312
  db.run("PRAGMA busy_timeout = 5000");
4214
4313
  db.run("PRAGMA journal_mode = WAL");
@@ -4375,105 +4474,10 @@ var init_database = __esm(() => {
4375
4474
  init_machines();
4376
4475
  init_identity_mapping();
4377
4476
  init_types();
4477
+ init_sync_utils();
4378
4478
  ALLOWED_TABLES = new Set(["tasks", "projects", "agents", "plans", "task_lists", "task_templates", "project_knowledge_records", "project_risks", "local_retrospectives"]);
4379
4479
  });
4380
4480
 
4381
- // src/lib/sync-utils.ts
4382
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
4383
- import { createHash } from "crypto";
4384
- import { join as join2 } from "path";
4385
- function getHomeDir() {
4386
- return process.env["HOME"] || process.env["USERPROFILE"] || "~";
4387
- }
4388
- function getTodosGlobalDir() {
4389
- return join2(getHomeDir(), ".hasna", "todos");
4390
- }
4391
- function ensureDir2(dir) {
4392
- if (!existsSync3(dir))
4393
- mkdirSync2(dir, { recursive: true });
4394
- }
4395
- function listJsonFiles(dir) {
4396
- if (!existsSync3(dir))
4397
- return [];
4398
- return readdirSync(dir).filter((f) => f.endsWith(".json"));
4399
- }
4400
- function readJsonFile(path) {
4401
- try {
4402
- return JSON.parse(readFileSync(path, "utf-8"));
4403
- } catch {
4404
- return null;
4405
- }
4406
- }
4407
- function writeJsonFile(path, data) {
4408
- writeFileSync(path, JSON.stringify(data, null, 2) + `
4409
- `);
4410
- }
4411
- function readHighWaterMark(dir) {
4412
- const path = join2(dir, ".highwatermark");
4413
- if (!existsSync3(path))
4414
- return 1;
4415
- const val = parseInt(readFileSync(path, "utf-8").trim(), 10);
4416
- return isNaN(val) ? 1 : val;
4417
- }
4418
- function writeHighWaterMark(dir, value) {
4419
- writeFileSync(join2(dir, ".highwatermark"), String(value));
4420
- }
4421
- function getFileMtimeMs(path) {
4422
- try {
4423
- return statSync(path).mtimeMs;
4424
- } catch {
4425
- return null;
4426
- }
4427
- }
4428
- function parseTimestamp(value) {
4429
- if (typeof value !== "string")
4430
- return null;
4431
- const parsed = Date.parse(value);
4432
- return Number.isNaN(parsed) ? null : parsed;
4433
- }
4434
- function appendSyncConflict(metadata, conflict, limit = 5) {
4435
- const current = Array.isArray(metadata["sync_conflicts"]) ? metadata["sync_conflicts"] : [];
4436
- const next = [conflict, ...current].slice(0, limit);
4437
- return { ...metadata, sync_conflicts: next };
4438
- }
4439
- function canonicalize(value) {
4440
- if (Array.isArray(value))
4441
- return value.map(canonicalize);
4442
- if (!value || typeof value !== "object")
4443
- return value;
4444
- const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== undefined).sort(([a], [b]) => a.localeCompare(b));
4445
- return Object.fromEntries(entries.map(([key, entryValue]) => [key, canonicalize(entryValue)]));
4446
- }
4447
- function withoutSyncFingerprintMetadata(metadata) {
4448
- const { [TODO_SYNC_FINGERPRINT_KEY]: _fingerprint, ...rest } = metadata;
4449
- return rest;
4450
- }
4451
- function syncFingerprint(record) {
4452
- const metadata = withoutSyncFingerprintMetadata(record.metadata || {});
4453
- const canonical = canonicalize({ ...record, metadata });
4454
- return `sha256:${createHash("sha256").update(JSON.stringify(canonical)).digest("hex")}`;
4455
- }
4456
- function withSyncFingerprint(record) {
4457
- const metadata = withoutSyncFingerprintMetadata(record.metadata);
4458
- return {
4459
- ...record,
4460
- metadata: {
4461
- ...metadata,
4462
- [TODO_SYNC_FINGERPRINT_KEY]: syncFingerprint({ ...record, metadata })
4463
- }
4464
- };
4465
- }
4466
- function hasSyncFingerprintChanged(record) {
4467
- const stored = record.metadata?.[TODO_SYNC_FINGERPRINT_KEY];
4468
- if (typeof stored !== "string" || stored.length === 0)
4469
- return null;
4470
- return stored !== syncFingerprint(record);
4471
- }
4472
- var TODO_SYNC_FINGERPRINT_KEY = "todos_sync_fingerprint", HOME;
4473
- var init_sync_utils = __esm(() => {
4474
- HOME = process.env["HOME"] || process.env["USERPROFILE"] || "~";
4475
- });
4476
-
4477
4481
  // src/lib/config.ts
4478
4482
  import { existsSync as existsSync4 } from "fs";
4479
4483
  import { dirname as dirname2, join as join3 } from "path";
@@ -4499,7 +4503,7 @@ function loadConfig() {
4499
4503
  }
4500
4504
  function saveConfig(config) {
4501
4505
  const configPath = getConfigPath();
4502
- ensureDir2(dirname2(configPath));
4506
+ ensureDir(dirname2(configPath));
4503
4507
  writeJsonFile(configPath, config);
4504
4508
  cached = config;
4505
4509
  return config;
@@ -5844,7 +5848,7 @@ var init_event_hooks = __esm(() => {
5844
5848
  // node_modules/.bun/@hasna+events@0.1.11/node_modules/@hasna/events/dist/index.js
5845
5849
  import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
5846
5850
  import { existsSync as existsSync5 } from "fs";
5847
- import { homedir } from "os";
5851
+ import { homedir as homedir2 } from "os";
5848
5852
  import { join as join4 } from "path";
5849
5853
  import { createHmac, timingSafeEqual } from "crypto";
5850
5854
  import { randomUUID as randomUUID2 } from "crypto";
@@ -5946,7 +5950,7 @@ function channelMatchesEvent(channel, event) {
5946
5950
  return channel.filters.some((filter) => eventMatchesFilter(event, filter));
5947
5951
  }
5948
5952
  function getEventsDataDir(override) {
5949
- return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join4(homedir(), ".hasna", "events");
5953
+ return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join4(homedir2(), ".hasna", "events");
5950
5954
  }
5951
5955
 
5952
5956
  class JsonEventsStore {
@@ -9286,11 +9290,13 @@ function updateTask(id, input, db) {
9286
9290
  }
9287
9291
  sets.push("status = ?");
9288
9292
  params.push(input.status);
9293
+ if (isTerminalStatus(input.status)) {
9294
+ sets.push("locked_by = NULL");
9295
+ sets.push("locked_at = NULL");
9296
+ }
9289
9297
  if (input.status === "completed") {
9290
9298
  sets.push("completed_at = ?");
9291
9299
  params.push(completionTimestamp);
9292
- sets.push("locked_by = NULL");
9293
- sets.push("locked_at = NULL");
9294
9300
  } else if (task.status === "completed" && input.completed_at === undefined) {
9295
9301
  sets.push("completed_at = NULL");
9296
9302
  }
@@ -9414,6 +9420,7 @@ function updateTask(id, input, db) {
9414
9420
  logTaskChange(id, "approve", "approved_by", null, input.approved_by, agentId, d);
9415
9421
  const reopened = input.status !== undefined && input.status !== "completed" && task.status === "completed" && input.completed_at === undefined;
9416
9422
  const completedNow = input.status === "completed";
9423
+ const terminalNow = input.status !== undefined && isTerminalStatus(input.status);
9417
9424
  const updatedTask = {
9418
9425
  ...task,
9419
9426
  ...Object.fromEntries(Object.entries(input).filter(([, v]) => v !== undefined)),
@@ -9421,8 +9428,8 @@ function updateTask(id, input, db) {
9421
9428
  metadata: input.metadata ?? task.metadata,
9422
9429
  version: task.version + 1,
9423
9430
  updated_at: timestamp2,
9424
- locked_by: completedNow ? null : task.locked_by,
9425
- locked_at: completedNow ? null : task.locked_at,
9431
+ locked_by: terminalNow ? null : task.locked_by,
9432
+ locked_at: terminalNow ? null : task.locked_at,
9426
9433
  completed_at: completedNow ? completionTimestamp : reopened ? null : input.completed_at !== undefined ? input.completed_at : task.completed_at,
9427
9434
  sla_minutes: input.sla_minutes !== undefined ? input.sla_minutes : task.sla_minutes,
9428
9435
  actual_minutes: input.actual_minutes ?? task.actual_minutes,
@@ -12025,7 +12032,7 @@ var init_tasks = __esm(() => {
12025
12032
  // package.json
12026
12033
  var package_default = {
12027
12034
  name: "@hasna/todos",
12028
- version: "0.13.12",
12035
+ version: "0.15.1",
12029
12036
  description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
12030
12037
  type: "module",
12031
12038
  main: "dist/index.js",
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAQtC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AA6FtC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AA2DD,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAarD;AAED,wBAAgB,aAAa,IAAI,IAAI,CAMpC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAQpC;AAED,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED,wBAAgB,IAAI,IAAI,MAAM,CAE7B;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,SAAa,GAAG,OAAO,CAKlF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,SAAa,GAAG,MAAM,CAG3D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGpD;AAQD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA8E9F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAe5E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAEzE;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAIlG"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAStC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AA4FtC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AA2DD,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAarD;AAED,wBAAgB,aAAa,IAAI,IAAI,CAMpC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAQpC;AAED,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED,wBAAgB,IAAI,IAAI,MAAM,CAE7B;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,SAAa,GAAG,OAAO,CAKlF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,SAAa,GAAG,MAAM,CAG3D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGpD;AAQD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA8E9F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAe5E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAEzE;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAIlG"}
@@ -1 +1 @@
1
- {"version":3,"file":"task-crud.d.ts","sourceRoot":"","sources":["../../src/db/task-crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EACV,eAAe,EACf,IAAI,EACJ,UAAU,EACV,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,mBAAmB,CAAC;AAO3B,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAY5F,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAS5C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAMjF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGlF;AAwCD,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,CAwFtE;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAK9D;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,MAAM,EACV,EAAE,CAAC,EAAE,QAAQ,GACZ,iBAAiB,GAAG,IAAI,CA4D1B;AAQD,wBAAgB,SAAS,CAAC,MAAM,GAAE,UAAe,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,EAAE,CA0JxE;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,GAAG,IAAI,CAKb;AAcD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,4BAA4B,EACnC,EAAE,CAAC,EAAE,QAAQ,GACZ,6BAA6B,CAmD/B;AAED,wBAAgB,UAAU,CAAC,MAAM,GAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,CA0HnG;AAED,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,eAAe,EACtB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,CAkPN;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAY7D"}
1
+ {"version":3,"file":"task-crud.d.ts","sourceRoot":"","sources":["../../src/db/task-crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EACV,eAAe,EACf,IAAI,EACJ,UAAU,EACV,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,mBAAmB,CAAC;AAQ3B,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAY5F,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAS5C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAMjF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGlF;AAwCD,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,CAwFtE;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAK9D;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,MAAM,EACV,EAAE,CAAC,EAAE,QAAQ,GACZ,iBAAiB,GAAG,IAAI,CA4D1B;AAQD,wBAAgB,SAAS,CAAC,MAAM,GAAE,UAAe,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,EAAE,CA0JxE;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,GAAG,IAAI,CAKb;AAcD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,4BAA4B,EACnC,EAAE,CAAC,EAAE,QAAQ,GACZ,6BAA6B,CAmD/B;AAED,wBAAgB,UAAU,CAAC,MAAM,GAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,CA0HnG;AAED,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,eAAe,EACtB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,CA8PN;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAY7D"}