@hasna/todos 0.11.23 → 0.11.25

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/cli/index.js CHANGED
@@ -3623,7 +3623,9 @@ function getTodosGlobalDir() {
3623
3623
  const home = process.env["HOME"] || HOME;
3624
3624
  const newDir = join3(home, ".hasna", "todos");
3625
3625
  const legacyDir = join3(home, ".todos");
3626
- if (!existsSync3(newDir) && existsSync3(legacyDir))
3626
+ const newConfig = join3(newDir, "config.json");
3627
+ const legacyConfig = join3(legacyDir, "config.json");
3628
+ if (!existsSync3(newConfig) && existsSync3(legacyConfig))
3627
3629
  return legacyDir;
3628
3630
  return newDir;
3629
3631
  }
@@ -4426,15 +4428,16 @@ function taskFromTemplate(templateId, overrides = {}, db) {
4426
4428
  const t = getTemplate(templateId, db);
4427
4429
  if (!t)
4428
4430
  throw new Error(`Template not found: ${templateId}`);
4431
+ const cleanOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== undefined));
4429
4432
  return {
4430
- title: overrides.title || t.title_pattern,
4431
- description: overrides.description ?? t.description ?? undefined,
4432
- priority: overrides.priority ?? t.priority,
4433
- tags: overrides.tags ?? t.tags,
4434
- project_id: overrides.project_id ?? t.project_id ?? undefined,
4435
- plan_id: overrides.plan_id ?? t.plan_id ?? undefined,
4436
- metadata: overrides.metadata ?? t.metadata,
4437
- ...overrides
4433
+ title: cleanOverrides.title || t.title_pattern,
4434
+ description: cleanOverrides.description ?? t.description ?? undefined,
4435
+ priority: cleanOverrides.priority ?? t.priority,
4436
+ tags: cleanOverrides.tags ?? t.tags,
4437
+ project_id: cleanOverrides.project_id ?? t.project_id ?? undefined,
4438
+ plan_id: cleanOverrides.plan_id ?? t.plan_id ?? undefined,
4439
+ metadata: cleanOverrides.metadata ?? t.metadata,
4440
+ ...cleanOverrides
4438
4441
  };
4439
4442
  }
4440
4443
  function addTemplateTasks(templateId, tasks, db) {
@@ -32726,6 +32729,29 @@ function autoDetectProject(opts) {
32726
32729
  function autoProject(opts) {
32727
32730
  return autoDetectProject(opts)?.id;
32728
32731
  }
32732
+ function normalizeStatus(s) {
32733
+ switch (s.toLowerCase().trim()) {
32734
+ case "done":
32735
+ return "completed";
32736
+ case "complete":
32737
+ return "completed";
32738
+ case "active":
32739
+ return "in_progress";
32740
+ case "wip":
32741
+ return "in_progress";
32742
+ case "cancelled":
32743
+ return "cancelled";
32744
+ case "canceled":
32745
+ return "cancelled";
32746
+ default:
32747
+ return s;
32748
+ }
32749
+ }
32750
+ function normalizeStatusList(statuses) {
32751
+ if (Array.isArray(statuses))
32752
+ return statuses.map(normalizeStatus);
32753
+ return normalizeStatus(statuses);
32754
+ }
32729
32755
  function output(data, jsonMode) {
32730
32756
  if (jsonMode) {
32731
32757
  console.log(JSON.stringify(data, null, 2));
@@ -32784,7 +32810,7 @@ program2.command("add <title>").description("Create a new task").option("-d, --d
32784
32810
  return id;
32785
32811
  })() : undefined,
32786
32812
  assigned_to: opts.assign,
32787
- status: opts.status,
32813
+ status: opts.status ? normalizeStatus(opts.status) : undefined,
32788
32814
  task_list_id: taskListId,
32789
32815
  agent_id: globalOpts.agent,
32790
32816
  session_id: globalOpts.session,
@@ -32821,7 +32847,7 @@ program2.command("list").description("List tasks").option("-s, --status <status>
32821
32847
  filter["task_list_id"] = listId;
32822
32848
  }
32823
32849
  if (opts.status) {
32824
- filter["status"] = opts.status.includes(",") ? opts.status.split(",").map((s) => s.trim()) : opts.status;
32850
+ filter["status"] = opts.status.includes(",") ? opts.status.split(",").map((s) => normalizeStatus(s.trim())) : normalizeStatus(opts.status);
32825
32851
  } else if (!opts.all) {
32826
32852
  filter["status"] = ["pending", "in_progress"];
32827
32853
  }
@@ -33198,7 +33224,7 @@ program2.command("update <id>").description("Update a task").option("--title <te
33198
33224
  version: current.version,
33199
33225
  title: opts.title,
33200
33226
  description: opts.description,
33201
- status: opts.status,
33227
+ status: opts.status ? normalizeStatus(opts.status) : undefined,
33202
33228
  priority: opts.priority,
33203
33229
  assigned_to: opts.assign,
33204
33230
  tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : undefined,
@@ -33484,7 +33510,7 @@ program2.command("plans").description("List and manage plans").option("--add <na
33484
33510
  console.log(`${chalk3.dim(p.id.slice(0, 8))} ${chalk3.bold(p.name)} ${chalk3.cyan(`[${p.status}]`)}${desc}`);
33485
33511
  }
33486
33512
  });
33487
- program2.command("templates").description("List and manage task templates").option("--add <name>", "Create a template").option("--title <pattern>", "Title pattern (with --add)").option("-d, --description <text>", "Default description").option("-p, --priority <level>", "Default priority").option("-t, --tags <tags>", "Default tags (comma-separated)").option("--delete <id>", "Delete a template").option("--update <id>", "Update a template").option("--use <id>", "Create a task from a template").action((opts) => {
33513
+ program2.command("templates").description("List and manage task templates").option("--add <name>", "Create a template").option("--title <pattern>", "Title pattern (with --add)").option("-d, --description <text>", "Default description").option("-p, --priority <level>", "Default priority").option("-t, --tags <tags>", "Default tags (comma-separated)").option("--delete <id>", "Delete a template").option("--update <id>", "Update a template").option("--use <id>", "Create a task from a template").option("--var <vars...>", "Variable substitutions: key=value (e.g. --var feature=login)").action((opts) => {
33488
33514
  const globalOpts = program2.opts();
33489
33515
  const { createTemplate: createTemplate2, listTemplates: listTemplates2, deleteTemplate: deleteTemplate2, updateTemplate: updateTemplate2, taskFromTemplate: taskFromTemplate2 } = (init_templates(), __toCommonJS(exports_templates));
33490
33516
  if (opts.add) {
@@ -33546,12 +33572,30 @@ program2.command("templates").description("List and manage task templates").opti
33546
33572
  }
33547
33573
  if (opts.use) {
33548
33574
  try {
33575
+ const variables = {};
33576
+ if (opts.var) {
33577
+ for (const v of opts.var) {
33578
+ const eq = v.indexOf("=");
33579
+ if (eq === -1) {
33580
+ console.error(chalk3.red(`Invalid variable format: ${v} (expected key=value)`));
33581
+ process.exit(1);
33582
+ }
33583
+ variables[v.slice(0, eq)] = v.slice(eq + 1);
33584
+ }
33585
+ }
33549
33586
  const input = taskFromTemplate2(opts.use, {
33550
33587
  title: opts.title,
33551
33588
  description: opts.description,
33552
33589
  priority: opts.priority
33553
33590
  });
33554
- const task = createTask({ ...input, project_id: input.project_id || autoProject(globalOpts) });
33591
+ if (input.title) {
33592
+ let title = input.title;
33593
+ for (const [k, v] of Object.entries(variables)) {
33594
+ title = title.replace(new RegExp(`\\{${k}\\}`, "g"), v);
33595
+ }
33596
+ input.title = title;
33597
+ }
33598
+ const task = createTask({ ...input, agent_id: globalOpts.agent, project_id: input.project_id || autoProject(globalOpts) });
33555
33599
  if (globalOpts.json) {
33556
33600
  output(task, true);
33557
33601
  } else {
@@ -33640,16 +33684,17 @@ program2.command("template-export <id>").alias("templates-export").description("
33640
33684
  handleError(e);
33641
33685
  }
33642
33686
  });
33643
- program2.command("template-import").alias("templates-import").description("Import a template from a JSON file").option("--file <path>", "Path to template JSON file").action((opts) => {
33687
+ program2.command("template-import [file]").alias("templates-import").description("Import a template from a JSON file").option("--file <path>", "Path to template JSON file (alternative to positional arg)").action((file, opts) => {
33644
33688
  const globalOpts = program2.opts();
33645
33689
  const { importTemplate: importTemplate2 } = (init_templates(), __toCommonJS(exports_templates));
33646
33690
  const { readFileSync: readFileSync8 } = __require("fs");
33647
33691
  try {
33648
- if (!opts.file) {
33649
- console.error(chalk3.red("--file is required"));
33692
+ const filePath = file || opts.file;
33693
+ if (!filePath) {
33694
+ console.error(chalk3.red("Provide a file path: todos template-import <file> or --file <path>"));
33650
33695
  process.exit(1);
33651
33696
  }
33652
- const content = readFileSync8(opts.file, "utf-8");
33697
+ const content = readFileSync8(filePath, "utf-8");
33653
33698
  const json2 = JSON.parse(content);
33654
33699
  const template = importTemplate2(json2);
33655
33700
  if (globalOpts.json) {
@@ -33708,7 +33753,7 @@ program2.command("search <query>").description("Search tasks").option("--status
33708
33753
  const projectId = autoProject(globalOpts);
33709
33754
  const searchOpts = { query, project_id: projectId };
33710
33755
  if (opts.status)
33711
- searchOpts.status = opts.status;
33756
+ searchOpts.status = normalizeStatusList(opts.status);
33712
33757
  if (opts.priority)
33713
33758
  searchOpts.priority = opts.priority;
33714
33759
  if (opts.assigned)
@@ -34735,7 +34780,10 @@ Updated to ${latestVersion}!`));
34735
34780
  });
34736
34781
  program2.command("config").description("View or update configuration").option("--get <key>", "Get a config value").option("--set <key=value>", "Set a config value (e.g. completion_guard.enabled=true)").action((opts) => {
34737
34782
  const globalOpts = program2.opts();
34738
- const configPath = join12(process.env["HOME"] || "~", ".todos", "config.json");
34783
+ const home = process.env["HOME"] || "~";
34784
+ const newPath = join12(home, ".hasna", "todos", "config.json");
34785
+ const legacyPath = join12(home, ".todos", "config.json");
34786
+ const configPath = !existsSync10(newPath) && existsSync10(legacyPath) ? legacyPath : newPath;
34739
34787
  if (opts.get) {
34740
34788
  const config2 = loadConfig();
34741
34789
  const keys = opts.get.split(".");
@@ -34810,7 +34858,7 @@ program2.command("watch").description("Live-updating task list (refreshes every
34810
34858
  const globalOpts = program2.opts();
34811
34859
  const projectId = autoProject(globalOpts);
34812
34860
  const interval = parseInt(opts.interval, 10) * 1000;
34813
- const statusFilter = opts.status ? opts.status.split(",").map((s) => s.trim()) : ["pending", "in_progress"];
34861
+ const statusFilter = opts.status ? opts.status.split(",").map((s) => normalizeStatus(s.trim())) : ["pending", "in_progress"];
34814
34862
  function render2() {
34815
34863
  const tasks = listTasks({ project_id: projectId, status: statusFilter });
34816
34864
  const all = listTasks({ project_id: projectId });
package/dist/index.js CHANGED
@@ -1850,7 +1850,9 @@ function getTodosGlobalDir() {
1850
1850
  const home = process.env["HOME"] || HOME;
1851
1851
  const newDir = join3(home, ".hasna", "todos");
1852
1852
  const legacyDir = join3(home, ".todos");
1853
- if (!existsSync3(newDir) && existsSync3(legacyDir))
1853
+ const newConfig = join3(newDir, "config.json");
1854
+ const legacyConfig = join3(legacyDir, "config.json");
1855
+ if (!existsSync3(newConfig) && existsSync3(legacyConfig))
1854
1856
  return legacyDir;
1855
1857
  return newDir;
1856
1858
  }
@@ -2553,15 +2555,16 @@ function taskFromTemplate(templateId, overrides = {}, db) {
2553
2555
  const t = getTemplate(templateId, db);
2554
2556
  if (!t)
2555
2557
  throw new Error(`Template not found: ${templateId}`);
2558
+ const cleanOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== undefined));
2556
2559
  return {
2557
- title: overrides.title || t.title_pattern,
2558
- description: overrides.description ?? t.description ?? undefined,
2559
- priority: overrides.priority ?? t.priority,
2560
- tags: overrides.tags ?? t.tags,
2561
- project_id: overrides.project_id ?? t.project_id ?? undefined,
2562
- plan_id: overrides.plan_id ?? t.plan_id ?? undefined,
2563
- metadata: overrides.metadata ?? t.metadata,
2564
- ...overrides
2560
+ title: cleanOverrides.title || t.title_pattern,
2561
+ description: cleanOverrides.description ?? t.description ?? undefined,
2562
+ priority: cleanOverrides.priority ?? t.priority,
2563
+ tags: cleanOverrides.tags ?? t.tags,
2564
+ project_id: cleanOverrides.project_id ?? t.project_id ?? undefined,
2565
+ plan_id: cleanOverrides.plan_id ?? t.plan_id ?? undefined,
2566
+ metadata: cleanOverrides.metadata ?? t.metadata,
2567
+ ...cleanOverrides
2565
2568
  };
2566
2569
  }
2567
2570
  function addTemplateTasks(templateId, tasks, db) {
package/dist/mcp/index.js CHANGED
@@ -12602,7 +12602,9 @@ function getTodosGlobalDir() {
12602
12602
  const home = process.env["HOME"] || HOME;
12603
12603
  const newDir = join9(home, ".hasna", "todos");
12604
12604
  const legacyDir = join9(home, ".todos");
12605
- if (!existsSync9(newDir) && existsSync9(legacyDir))
12605
+ const newConfig = join9(newDir, "config.json");
12606
+ const legacyConfig = join9(legacyDir, "config.json");
12607
+ if (!existsSync9(newConfig) && existsSync9(legacyConfig))
12606
12608
  return legacyDir;
12607
12609
  return newDir;
12608
12610
  }
@@ -13283,15 +13285,16 @@ function taskFromTemplate(templateId, overrides = {}, db) {
13283
13285
  const t = getTemplate(templateId, db);
13284
13286
  if (!t)
13285
13287
  throw new Error(`Template not found: ${templateId}`);
13288
+ const cleanOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== undefined));
13286
13289
  return {
13287
- title: overrides.title || t.title_pattern,
13288
- description: overrides.description ?? t.description ?? undefined,
13289
- priority: overrides.priority ?? t.priority,
13290
- tags: overrides.tags ?? t.tags,
13291
- project_id: overrides.project_id ?? t.project_id ?? undefined,
13292
- plan_id: overrides.plan_id ?? t.plan_id ?? undefined,
13293
- metadata: overrides.metadata ?? t.metadata,
13294
- ...overrides
13290
+ title: cleanOverrides.title || t.title_pattern,
13291
+ description: cleanOverrides.description ?? t.description ?? undefined,
13292
+ priority: cleanOverrides.priority ?? t.priority,
13293
+ tags: cleanOverrides.tags ?? t.tags,
13294
+ project_id: cleanOverrides.project_id ?? t.project_id ?? undefined,
13295
+ plan_id: cleanOverrides.plan_id ?? t.plan_id ?? undefined,
13296
+ metadata: cleanOverrides.metadata ?? t.metadata,
13297
+ ...cleanOverrides
13295
13298
  };
13296
13299
  }
13297
13300
  function addTemplateTasks(templateId, tasks, db) {
@@ -1403,7 +1403,9 @@ function getTodosGlobalDir() {
1403
1403
  const home = process.env["HOME"] || HOME;
1404
1404
  const newDir = join2(home, ".hasna", "todos");
1405
1405
  const legacyDir = join2(home, ".todos");
1406
- if (!existsSync3(newDir) && existsSync3(legacyDir))
1406
+ const newConfig = join2(newDir, "config.json");
1407
+ const legacyConfig = join2(legacyDir, "config.json");
1408
+ if (!existsSync3(newConfig) && existsSync3(legacyConfig))
1407
1409
  return legacyDir;
1408
1410
  return newDir;
1409
1411
  }
@@ -2151,15 +2153,16 @@ function taskFromTemplate(templateId, overrides = {}, db) {
2151
2153
  const t = getTemplate(templateId, db);
2152
2154
  if (!t)
2153
2155
  throw new Error(`Template not found: ${templateId}`);
2156
+ const cleanOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== undefined));
2154
2157
  return {
2155
- title: overrides.title || t.title_pattern,
2156
- description: overrides.description ?? t.description ?? undefined,
2157
- priority: overrides.priority ?? t.priority,
2158
- tags: overrides.tags ?? t.tags,
2159
- project_id: overrides.project_id ?? t.project_id ?? undefined,
2160
- plan_id: overrides.plan_id ?? t.plan_id ?? undefined,
2161
- metadata: overrides.metadata ?? t.metadata,
2162
- ...overrides
2158
+ title: cleanOverrides.title || t.title_pattern,
2159
+ description: cleanOverrides.description ?? t.description ?? undefined,
2160
+ priority: cleanOverrides.priority ?? t.priority,
2161
+ tags: cleanOverrides.tags ?? t.tags,
2162
+ project_id: cleanOverrides.project_id ?? t.project_id ?? undefined,
2163
+ plan_id: cleanOverrides.plan_id ?? t.plan_id ?? undefined,
2164
+ metadata: cleanOverrides.metadata ?? t.metadata,
2165
+ ...cleanOverrides
2163
2166
  };
2164
2167
  }
2165
2168
  function addTemplateTasks(templateId, tasks, db) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/todos",
3
- "version": "0.11.23",
3
+ "version": "0.11.25",
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",