@tomkapa/tayto 0.2.0 → 0.3.0

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.js CHANGED
@@ -308,6 +308,17 @@ var SqliteProjectRepository = class {
308
308
  }
309
309
  };
310
310
 
311
+ // src/utils/search-parser.ts
312
+ var ID_PREFIX_RE = /^id:(.+)$/;
313
+ function parseSearchQuery(raw) {
314
+ const trimmed = raw.trim();
315
+ const match = ID_PREFIX_RE.exec(trimmed);
316
+ if (match?.[1]) {
317
+ return { kind: "id", value: match[1] };
318
+ }
319
+ return { kind: "fts", query: trimmed };
320
+ }
321
+
311
322
  // src/repository/task.repository.ts
312
323
  var TERMINAL_STATUS_ARRAY = [...TERMINAL_STATUSES];
313
324
  var TERMINAL_PLACEHOLDERS = TERMINAL_STATUS_ARRAY.map(() => "?").join(", ");
@@ -400,9 +411,15 @@ var SqliteTaskRepository = class {
400
411
  params.push(...filter.parentIds);
401
412
  }
402
413
  if (filter.search) {
403
- const ftsQuery = filter.search.trim().split(/\s+/).map((term) => `"${term.replace(/"/g, '""')}"*`).join(" ");
404
- conditions.push(`id IN (SELECT id FROM tasks_fts WHERE tasks_fts MATCH ?)`);
405
- params.push(ftsQuery);
414
+ const parsed = parseSearchQuery(filter.search);
415
+ if (parsed.kind === "id") {
416
+ conditions.push(`id LIKE ?`);
417
+ params.push(`%${parsed.value}%`);
418
+ } else {
419
+ const ftsQuery = parsed.query.split(/\s+/).map((term) => `"${term.replace(/"/g, '""')}"*`).join(" ");
420
+ conditions.push(`id IN (SELECT id FROM tasks_fts WHERE tasks_fts MATCH ?)`);
421
+ params.push(ftsQuery);
422
+ }
406
423
  }
407
424
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
408
425
  const sql = `SELECT * FROM tasks ${where} ORDER BY rank ASC`;
@@ -602,10 +619,33 @@ _${now}_
602
619
  return err(new AppError("DB_ERROR", "Failed to get ranked tasks by level", e));
603
620
  }
604
621
  }
622
+ getRankedNonTerminalTasksByLevel(projectId, level) {
623
+ try {
624
+ const types = this.getTypesForLevel(level);
625
+ const typePlaceholders = types.map(() => "?").join(", ");
626
+ const sql = `SELECT * FROM tasks WHERE project_id = ? AND ${NOT_DELETED} AND type IN (${typePlaceholders}) AND status NOT IN (${TERMINAL_PLACEHOLDERS}) ORDER BY rank ASC`;
627
+ const rows = this.db.prepare(sql).all(projectId, ...types, ...TERMINAL_STATUS_ARRAY);
628
+ return ok(rows.map(rowToTask));
629
+ } catch (e) {
630
+ return err(new AppError("DB_ERROR", "Failed to get ranked non-terminal tasks by level", e));
631
+ }
632
+ }
605
633
  search(query, projectId) {
606
634
  return logger.startSpan("TaskRepository.search", () => {
607
635
  try {
608
- const ftsQuery = query.trim().split(/\s+/).map((term) => `"${term.replace(/"/g, '""')}"*`).join(" ");
636
+ const parsed = parseSearchQuery(query);
637
+ if (parsed.kind === "id") {
638
+ const conditions = ["t.id LIKE ?", "t.deleted_at IS NULL"];
639
+ const params2 = [`%${parsed.value}%`];
640
+ if (projectId) {
641
+ conditions.push("t.project_id = ?");
642
+ params2.push(projectId);
643
+ }
644
+ const sql2 = `SELECT t.*, 0 AS fts_rank FROM tasks t WHERE ${conditions.join(" AND ")} ORDER BY t.rank ASC`;
645
+ const rows2 = this.db.prepare(sql2).all(...params2);
646
+ return ok(rows2.map((row) => ({ task: rowToTask(row), rank: row.fts_rank })));
647
+ }
648
+ const ftsQuery = parsed.query.split(/\s+/).map((term) => `"${term.replace(/"/g, '""')}"*`).join(" ");
609
649
  let sql;
610
650
  let params;
611
651
  if (projectId) {
@@ -1213,18 +1253,14 @@ var TaskServiceImpl = class {
1213
1253
  const projectResult = this.projectService.resolveProject(projectRef);
1214
1254
  if (!projectResult.ok) return projectResult;
1215
1255
  const projectId = projectResult.value.id;
1216
- const rankedResult = this.repo.getRankedTasksByLevel(
1217
- projectId,
1218
- taskLevel,
1219
- TaskStatus.Backlog
1220
- );
1256
+ const rankedResult = this.repo.getRankedNonTerminalTasksByLevel(projectId, taskLevel);
1221
1257
  if (!rankedResult.ok) return rankedResult;
1222
1258
  const ranked = rankedResult.value.filter((t) => t.id !== taskId);
1223
1259
  let newRank;
1224
1260
  if (afterId) {
1225
1261
  const anchor = ranked.find((t) => t.id === afterId);
1226
1262
  if (!anchor) {
1227
- return err(new AppError("NOT_FOUND", `Anchor task not found in backlog: ${afterId}`));
1263
+ return err(new AppError("NOT_FOUND", `Anchor task not found among active tasks: ${afterId}`));
1228
1264
  }
1229
1265
  const anchorIndex = ranked.indexOf(anchor);
1230
1266
  const next = ranked[anchorIndex + 1];
@@ -1232,7 +1268,7 @@ var TaskServiceImpl = class {
1232
1268
  } else if (beforeId) {
1233
1269
  const anchor = ranked.find((t) => t.id === beforeId);
1234
1270
  if (!anchor) {
1235
- return err(new AppError("NOT_FOUND", `Anchor task not found in backlog: ${beforeId}`));
1271
+ return err(new AppError("NOT_FOUND", `Anchor task not found among active tasks: ${beforeId}`));
1236
1272
  }
1237
1273
  const anchorIndex = ranked.indexOf(anchor);
1238
1274
  const prev = ranked[anchorIndex - 1];
@@ -1750,7 +1786,7 @@ var PortabilityServiceImpl = class {
1750
1786
  };
1751
1787
 
1752
1788
  // src/cli/container.ts
1753
- function createContainer(db) {
1789
+ function createContainer(db, dbPath) {
1754
1790
  const projectRepo = new SqliteProjectRepository(db);
1755
1791
  const taskRepo = new SqliteTaskRepository(db);
1756
1792
  const depRepo = new SqliteDependencyRepository(db);
@@ -1762,7 +1798,7 @@ function createContainer(db) {
1762
1798
  dependencyService,
1763
1799
  projectService
1764
1800
  );
1765
- return { projectService, taskService, dependencyService, portabilityService };
1801
+ return { dbPath, projectService, taskService, dependencyService, portabilityService };
1766
1802
  }
1767
1803
 
1768
1804
  // src/cli/index.ts
@@ -2114,7 +2150,7 @@ function buildCLI(container) {
2114
2150
  registerDepList(dep, container);
2115
2151
  registerDepGraph(dep, container);
2116
2152
  program.command("tui").description("Launch interactive terminal UI").option("-p, --project <project>", "Start with specific project").action(async (opts) => {
2117
- const { launchTUI } = await import("./tui-FTXYP3HM.js");
2153
+ const { launchTUI } = await import("./tui-5JJH67YY.js");
2118
2154
  await launchTUI(container, opts.project);
2119
2155
  });
2120
2156
  return program;
@@ -2127,10 +2163,10 @@ async function main() {
2127
2163
  initTelemetry(config);
2128
2164
  const db = createDatabase(config.dbPath);
2129
2165
  runMigrations(db);
2130
- const container = createContainer(db);
2166
+ const container = createContainer(db, config.dbPath);
2131
2167
  const args = process.argv.slice(2);
2132
2168
  if (args.length === 0) {
2133
- const { launchTUI } = await import("./tui-FTXYP3HM.js");
2169
+ const { launchTUI } = await import("./tui-5JJH67YY.js");
2134
2170
  await launchTUI(container);
2135
2171
  } else {
2136
2172
  const program = buildCLI(container);