@tomkapa/tayto 0.2.0 → 0.3.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.
- package/dist/index.js +58 -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,16 @@ 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(
|
|
1263
|
+
return err(
|
|
1264
|
+
new AppError("NOT_FOUND", `Anchor task not found among active tasks: ${afterId}`)
|
|
1265
|
+
);
|
|
1228
1266
|
}
|
|
1229
1267
|
const anchorIndex = ranked.indexOf(anchor);
|
|
1230
1268
|
const next = ranked[anchorIndex + 1];
|
|
@@ -1232,7 +1270,9 @@ var TaskServiceImpl = class {
|
|
|
1232
1270
|
} else if (beforeId) {
|
|
1233
1271
|
const anchor = ranked.find((t) => t.id === beforeId);
|
|
1234
1272
|
if (!anchor) {
|
|
1235
|
-
return err(
|
|
1273
|
+
return err(
|
|
1274
|
+
new AppError("NOT_FOUND", `Anchor task not found among active tasks: ${beforeId}`)
|
|
1275
|
+
);
|
|
1236
1276
|
}
|
|
1237
1277
|
const anchorIndex = ranked.indexOf(anchor);
|
|
1238
1278
|
const prev = ranked[anchorIndex - 1];
|
|
@@ -1261,6 +1301,7 @@ var TaskServiceImpl = class {
|
|
|
1261
1301
|
const blockersResult = depService.listBlockers(taskId);
|
|
1262
1302
|
if (blockersResult.ok) {
|
|
1263
1303
|
for (const blocker of blockersResult.value) {
|
|
1304
|
+
if (isTerminalStatus(blocker.status)) continue;
|
|
1264
1305
|
if (blocker.projectId === projectId && newRank < blocker.rank) {
|
|
1265
1306
|
return err(
|
|
1266
1307
|
new AppError(
|
|
@@ -1274,6 +1315,7 @@ var TaskServiceImpl = class {
|
|
|
1274
1315
|
const dependentsResult = depService.listDependents(taskId);
|
|
1275
1316
|
if (dependentsResult.ok) {
|
|
1276
1317
|
for (const dep of dependentsResult.value) {
|
|
1318
|
+
if (isTerminalStatus(dep.status)) continue;
|
|
1277
1319
|
if (dep.projectId === projectId && newRank > dep.rank) {
|
|
1278
1320
|
return err(
|
|
1279
1321
|
new AppError(
|
|
@@ -1750,7 +1792,7 @@ var PortabilityServiceImpl = class {
|
|
|
1750
1792
|
};
|
|
1751
1793
|
|
|
1752
1794
|
// src/cli/container.ts
|
|
1753
|
-
function createContainer(db) {
|
|
1795
|
+
function createContainer(db, dbPath) {
|
|
1754
1796
|
const projectRepo = new SqliteProjectRepository(db);
|
|
1755
1797
|
const taskRepo = new SqliteTaskRepository(db);
|
|
1756
1798
|
const depRepo = new SqliteDependencyRepository(db);
|
|
@@ -1762,7 +1804,7 @@ function createContainer(db) {
|
|
|
1762
1804
|
dependencyService,
|
|
1763
1805
|
projectService
|
|
1764
1806
|
);
|
|
1765
|
-
return { projectService, taskService, dependencyService, portabilityService };
|
|
1807
|
+
return { dbPath, projectService, taskService, dependencyService, portabilityService };
|
|
1766
1808
|
}
|
|
1767
1809
|
|
|
1768
1810
|
// src/cli/index.ts
|
|
@@ -2114,7 +2156,7 @@ function buildCLI(container) {
|
|
|
2114
2156
|
registerDepList(dep, container);
|
|
2115
2157
|
registerDepGraph(dep, container);
|
|
2116
2158
|
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-
|
|
2159
|
+
const { launchTUI } = await import("./tui-5JJH67YY.js");
|
|
2118
2160
|
await launchTUI(container, opts.project);
|
|
2119
2161
|
});
|
|
2120
2162
|
return program;
|
|
@@ -2127,10 +2169,10 @@ async function main() {
|
|
|
2127
2169
|
initTelemetry(config);
|
|
2128
2170
|
const db = createDatabase(config.dbPath);
|
|
2129
2171
|
runMigrations(db);
|
|
2130
|
-
const container = createContainer(db);
|
|
2172
|
+
const container = createContainer(db, config.dbPath);
|
|
2131
2173
|
const args = process.argv.slice(2);
|
|
2132
2174
|
if (args.length === 0) {
|
|
2133
|
-
const { launchTUI } = await import("./tui-
|
|
2175
|
+
const { launchTUI } = await import("./tui-5JJH67YY.js");
|
|
2134
2176
|
await launchTUI(container);
|
|
2135
2177
|
} else {
|
|
2136
2178
|
const program = buildCLI(container);
|