@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 +52 -16
- package/dist/index.js.map +1 -1
- package/dist/{tui-FTXYP3HM.js → tui-5JJH67YY.js} +321 -246
- package/dist/tui-5JJH67YY.js.map +1 -0
- package/package.json +1 -1
- package/dist/tui-FTXYP3HM.js.map +0 -1
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
|
|
404
|
-
|
|
405
|
-
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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-
|
|
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-
|
|
2169
|
+
const { launchTUI } = await import("./tui-5JJH67YY.js");
|
|
2134
2170
|
await launchTUI(container);
|
|
2135
2171
|
} else {
|
|
2136
2172
|
const program = buildCLI(container);
|