@tomkapa/tayto 0.4.0 → 0.5.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/LICENSE +21 -0
- package/README.md +190 -111
- package/dist/index.js +53 -64
- package/dist/index.js.map +1 -1
- package/dist/{tui-4GNIGMCK.js → tui-24ZW56Q6.js} +417 -378
- package/dist/tui-24ZW56Q6.js.map +1 -0
- package/package.json +24 -1
- package/dist/tui-4GNIGMCK.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1036,7 +1036,7 @@ var ProjectServiceImpl = class {
|
|
|
1036
1036
|
deleteProject(id) {
|
|
1037
1037
|
return this.repo.delete(id);
|
|
1038
1038
|
}
|
|
1039
|
-
resolveProject(idOrName) {
|
|
1039
|
+
resolveProject(idOrName, cwd) {
|
|
1040
1040
|
return logger.startSpan("ProjectService.resolveProject", () => {
|
|
1041
1041
|
if (idOrName) {
|
|
1042
1042
|
const byId = this.repo.findById(idOrName);
|
|
@@ -1050,6 +1050,15 @@ var ProjectServiceImpl = class {
|
|
|
1050
1050
|
if (byName.value) return ok(byName.value);
|
|
1051
1051
|
return err(new AppError("NOT_FOUND", `Project not found: ${idOrName}`));
|
|
1052
1052
|
}
|
|
1053
|
+
const remoteResult = this.detectRemote(cwd);
|
|
1054
|
+
if (remoteResult.ok && remoteResult.value) {
|
|
1055
|
+
const byRemote = this.repo.findByGitRemote(remoteResult.value);
|
|
1056
|
+
if (!byRemote.ok) return byRemote;
|
|
1057
|
+
if (byRemote.value) {
|
|
1058
|
+
logger.info(`resolveProject: matched git remote to project key=${byRemote.value.key}`);
|
|
1059
|
+
return ok(byRemote.value);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1053
1062
|
const defaultProject = this.repo.findDefault();
|
|
1054
1063
|
if (!defaultProject.ok) return defaultProject;
|
|
1055
1064
|
if (defaultProject.value) return ok(defaultProject.value);
|
|
@@ -1061,25 +1070,6 @@ var ProjectServiceImpl = class {
|
|
|
1061
1070
|
);
|
|
1062
1071
|
});
|
|
1063
1072
|
}
|
|
1064
|
-
resolveProjectWithGit(idOrName, cwd) {
|
|
1065
|
-
return logger.startSpan("ProjectService.resolveProjectWithGit", () => {
|
|
1066
|
-
if (idOrName) {
|
|
1067
|
-
return this.resolveProject(idOrName);
|
|
1068
|
-
}
|
|
1069
|
-
const remoteResult = this.detectRemote(cwd);
|
|
1070
|
-
if (remoteResult.ok && remoteResult.value) {
|
|
1071
|
-
const byRemote = this.repo.findByGitRemote(remoteResult.value);
|
|
1072
|
-
if (!byRemote.ok) return byRemote;
|
|
1073
|
-
if (byRemote.value) {
|
|
1074
|
-
logger.info(
|
|
1075
|
-
`resolveProjectWithGit: matched git remote to project key=${byRemote.value.key}`
|
|
1076
|
-
);
|
|
1077
|
-
return ok(byRemote.value);
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
return this.resolveProject();
|
|
1081
|
-
});
|
|
1082
|
-
}
|
|
1083
1073
|
linkGitRemote(idOrName, remote) {
|
|
1084
1074
|
return logger.startSpan("ProjectService.linkGitRemote", () => {
|
|
1085
1075
|
const resolved = this.resolveProject(idOrName);
|
|
@@ -1154,7 +1144,6 @@ var UpdateTaskSchema = z2.object({
|
|
|
1154
1144
|
appendRequirements: z2.string().max(5e4).optional()
|
|
1155
1145
|
});
|
|
1156
1146
|
var TaskFilterSchema = z2.object({
|
|
1157
|
-
projectId: z2.string().optional(),
|
|
1158
1147
|
status: z2.enum(taskStatusValues).optional(),
|
|
1159
1148
|
type: z2.enum(taskTypeValues).optional(),
|
|
1160
1149
|
level: z2.number().int().min(1).max(2).optional(),
|
|
@@ -1184,15 +1173,12 @@ var TaskServiceImpl = class {
|
|
|
1184
1173
|
repo;
|
|
1185
1174
|
projectService;
|
|
1186
1175
|
getDependencyService;
|
|
1187
|
-
createTask(input,
|
|
1176
|
+
createTask(input, project) {
|
|
1188
1177
|
return logger.startSpan("TaskService.createTask", () => {
|
|
1189
1178
|
const parsed = CreateTaskSchema.safeParse(input);
|
|
1190
1179
|
if (!parsed.success) {
|
|
1191
1180
|
return err(new AppError("VALIDATION", parsed.error.message));
|
|
1192
1181
|
}
|
|
1193
|
-
const projectRef = parsed.data.projectId ?? projectIdOrName;
|
|
1194
|
-
const projectResult = this.projectService.resolveProject(projectRef);
|
|
1195
|
-
if (!projectResult.ok) return projectResult;
|
|
1196
1182
|
const taskLevel = getTaskLevel(parsed.data.type);
|
|
1197
1183
|
if (taskLevel === TaskLevel.Epic && parsed.data.parentId) {
|
|
1198
1184
|
return err(new AppError("VALIDATION", "Epic tasks cannot have a parent"));
|
|
@@ -1207,7 +1193,6 @@ var TaskServiceImpl = class {
|
|
|
1207
1193
|
return err(new AppError("VALIDATION", "Tasks can only be children of epic-level tasks"));
|
|
1208
1194
|
}
|
|
1209
1195
|
}
|
|
1210
|
-
const project = projectResult.value;
|
|
1211
1196
|
const taskIdResult = this.projectService.nextTaskId(project);
|
|
1212
1197
|
if (!taskIdResult.ok) return taskIdResult;
|
|
1213
1198
|
const insertResult = this.repo.insert(taskIdResult.value, {
|
|
@@ -1238,17 +1223,15 @@ var TaskServiceImpl = class {
|
|
|
1238
1223
|
return ok(result.value);
|
|
1239
1224
|
});
|
|
1240
1225
|
}
|
|
1241
|
-
listTasks(filter) {
|
|
1226
|
+
listTasks(project, filter) {
|
|
1242
1227
|
return logger.startSpan("TaskService.listTasks", () => {
|
|
1243
1228
|
const parsed = TaskFilterSchema.safeParse(filter);
|
|
1244
1229
|
if (!parsed.success) {
|
|
1245
1230
|
return err(new AppError("VALIDATION", parsed.error.message));
|
|
1246
1231
|
}
|
|
1247
|
-
const projectResult = this.projectService.resolveProject(parsed.data.projectId);
|
|
1248
|
-
if (!projectResult.ok) return projectResult;
|
|
1249
1232
|
const resolvedFilter = {
|
|
1250
1233
|
...parsed.data,
|
|
1251
|
-
projectId:
|
|
1234
|
+
projectId: project.id
|
|
1252
1235
|
};
|
|
1253
1236
|
return this.repo.findMany(resolvedFilter);
|
|
1254
1237
|
});
|
|
@@ -1353,7 +1336,7 @@ var TaskServiceImpl = class {
|
|
|
1353
1336
|
if (getTaskLevel(parent.type) !== TaskLevel.Epic) {
|
|
1354
1337
|
return err(new AppError("VALIDATION", "Breakdown parent must be an epic-level task"));
|
|
1355
1338
|
}
|
|
1356
|
-
const projectResult = this.projectService.
|
|
1339
|
+
const projectResult = this.projectService.getProject(parent.projectId);
|
|
1357
1340
|
if (!projectResult.ok) return projectResult;
|
|
1358
1341
|
const project = projectResult.value;
|
|
1359
1342
|
const created = [];
|
|
@@ -1388,7 +1371,7 @@ var TaskServiceImpl = class {
|
|
|
1388
1371
|
* If moving to the top, rank = first_rank - GAP.
|
|
1389
1372
|
* If moving to the bottom, rank = last_rank + GAP.
|
|
1390
1373
|
*/
|
|
1391
|
-
rerankTask(input,
|
|
1374
|
+
rerankTask(input, project) {
|
|
1392
1375
|
return logger.startSpan("TaskService.rerankTask", () => {
|
|
1393
1376
|
const parsed = RerankTaskSchema.safeParse(input);
|
|
1394
1377
|
if (!parsed.success) {
|
|
@@ -1419,10 +1402,7 @@ var TaskServiceImpl = class {
|
|
|
1419
1402
|
);
|
|
1420
1403
|
}
|
|
1421
1404
|
const taskLevel = getTaskLevel(task.type);
|
|
1422
|
-
const
|
|
1423
|
-
const projectResult = this.projectService.resolveProject(projectRef);
|
|
1424
|
-
if (!projectResult.ok) return projectResult;
|
|
1425
|
-
const projectId = projectResult.value.id;
|
|
1405
|
+
const projectId = project.id;
|
|
1426
1406
|
const depService = this.getDependencyService();
|
|
1427
1407
|
const blockersResult = depService.listBlockers(taskId);
|
|
1428
1408
|
if (!blockersResult.ok) return blockersResult;
|
|
@@ -1524,14 +1504,12 @@ var TaskServiceImpl = class {
|
|
|
1524
1504
|
return this.repo.rerank(taskId, newRank);
|
|
1525
1505
|
});
|
|
1526
1506
|
}
|
|
1527
|
-
searchTasks(query,
|
|
1507
|
+
searchTasks(query, project) {
|
|
1528
1508
|
return logger.startSpan("TaskService.searchTasks", () => {
|
|
1529
1509
|
if (!query.trim()) {
|
|
1530
1510
|
return err(new AppError("VALIDATION", "Search query cannot be empty"));
|
|
1531
1511
|
}
|
|
1532
|
-
|
|
1533
|
-
if (!projectResult.ok) return projectResult;
|
|
1534
|
-
return this.repo.search(query, projectResult.value.id);
|
|
1512
|
+
return this.repo.search(query, project.id);
|
|
1535
1513
|
});
|
|
1536
1514
|
}
|
|
1537
1515
|
/**
|
|
@@ -1809,20 +1787,15 @@ function parseFieldMapping(raw) {
|
|
|
1809
1787
|
|
|
1810
1788
|
// src/service/portability.service.ts
|
|
1811
1789
|
var PortabilityServiceImpl = class {
|
|
1812
|
-
constructor(taskService, depService
|
|
1790
|
+
constructor(taskService, depService) {
|
|
1813
1791
|
this.taskService = taskService;
|
|
1814
1792
|
this.depService = depService;
|
|
1815
|
-
this.projectService = projectService;
|
|
1816
1793
|
}
|
|
1817
1794
|
taskService;
|
|
1818
1795
|
depService;
|
|
1819
|
-
|
|
1820
|
-
exportTasks(projectIdOrName) {
|
|
1796
|
+
exportTasks(project) {
|
|
1821
1797
|
return logger.startSpan("PortabilityService.exportTasks", () => {
|
|
1822
|
-
const
|
|
1823
|
-
if (!projectResult.ok) return projectResult;
|
|
1824
|
-
const project = projectResult.value;
|
|
1825
|
-
const tasksResult = this.taskService.listTasks({ projectId: project.id });
|
|
1798
|
+
const tasksResult = this.taskService.listTasks(project, {});
|
|
1826
1799
|
if (!tasksResult.ok) return tasksResult;
|
|
1827
1800
|
const tasks = tasksResult.value;
|
|
1828
1801
|
const taskIds = new Set(tasks.map((t) => t.id));
|
|
@@ -1864,7 +1837,7 @@ var PortabilityServiceImpl = class {
|
|
|
1864
1837
|
});
|
|
1865
1838
|
});
|
|
1866
1839
|
}
|
|
1867
|
-
importTasks(fileData,
|
|
1840
|
+
importTasks(fileData, project, fieldMapping) {
|
|
1868
1841
|
return logger.startSpan("PortabilityService.importTasks", () => {
|
|
1869
1842
|
const parsed = ImportFileSchema.safeParse(fileData);
|
|
1870
1843
|
if (!parsed.success) {
|
|
@@ -1900,7 +1873,7 @@ var PortabilityServiceImpl = class {
|
|
|
1900
1873
|
technicalNotes: task.technicalNotes || void 0,
|
|
1901
1874
|
additionalRequirements: task.additionalRequirements || void 0
|
|
1902
1875
|
},
|
|
1903
|
-
|
|
1876
|
+
project
|
|
1904
1877
|
);
|
|
1905
1878
|
if (!createResult.ok) return createResult;
|
|
1906
1879
|
idMap.set(task.sourceId, createResult.value.id);
|
|
@@ -2032,11 +2005,7 @@ function createContainer(db, dbPath, detectGitRemote2) {
|
|
|
2032
2005
|
const projectService = new ProjectServiceImpl(projectRepo, detectGitRemote2);
|
|
2033
2006
|
const dependencyService = new DependencyServiceImpl(depRepo, taskRepo);
|
|
2034
2007
|
const taskService = new TaskServiceImpl(taskRepo, projectService, () => dependencyService);
|
|
2035
|
-
const portabilityService = new PortabilityServiceImpl(
|
|
2036
|
-
taskService,
|
|
2037
|
-
dependencyService,
|
|
2038
|
-
projectService
|
|
2039
|
-
);
|
|
2008
|
+
const portabilityService = new PortabilityServiceImpl(taskService, dependencyService);
|
|
2040
2009
|
return { dbPath, projectService, taskService, dependencyService, portabilityService };
|
|
2041
2010
|
}
|
|
2042
2011
|
|
|
@@ -2151,10 +2120,17 @@ function registerProjectUnlink(parent, container) {
|
|
|
2151
2120
|
});
|
|
2152
2121
|
}
|
|
2153
2122
|
|
|
2123
|
+
// src/cli/helpers/project.ts
|
|
2124
|
+
function withProject(container, projectIdOrName) {
|
|
2125
|
+
return container.projectService.resolveProject(projectIdOrName);
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2154
2128
|
// src/cli/commands/task/create.ts
|
|
2155
2129
|
function registerTaskCreate(parent, container) {
|
|
2156
2130
|
parent.command("create").description("Create a new task (appended to bottom of backlog)").requiredOption("-n, --name <name>", "Task name").option("-p, --project <project>", "Project id or name").option("-d, --description <description>", "Task description").option("-t, --type <type>", "Task type: epic, story, tech-debt, bug", "story").option("-s, --status <status>", "Task status", "backlog").option("--parent <parentId>", "Parent task id for subtask").option("--technical-notes <notes>", "Technical notes (markdown)").option("--additional-requirements <requirements>", "Additional requirements (markdown)").option("--depends-on <ids...>", "Task ids this task depends on (blocks relationship)").action(
|
|
2157
2131
|
(opts) => {
|
|
2132
|
+
const projectResult = withProject(container, opts.project);
|
|
2133
|
+
if (!projectResult.ok) return printError(projectResult.error);
|
|
2158
2134
|
const result = container.taskService.createTask(
|
|
2159
2135
|
{
|
|
2160
2136
|
name: opts.name,
|
|
@@ -2166,7 +2142,7 @@ function registerTaskCreate(parent, container) {
|
|
|
2166
2142
|
additionalRequirements: opts.additionalRequirements,
|
|
2167
2143
|
dependsOn: opts.dependsOn?.map((id) => ({ id }))
|
|
2168
2144
|
},
|
|
2169
|
-
|
|
2145
|
+
projectResult.value
|
|
2170
2146
|
);
|
|
2171
2147
|
handleResult(result);
|
|
2172
2148
|
}
|
|
@@ -2177,8 +2153,9 @@ function registerTaskCreate(parent, container) {
|
|
|
2177
2153
|
function registerTaskList(parent, container) {
|
|
2178
2154
|
parent.command("list").description("List tasks in rank order (defaults to level 2 backlog tasks)").option("-p, --project <project>", "Filter by project id or name").option("-s, --status <status>", "Filter by status (default: backlog)").option("-t, --type <type>", "Filter by type (epic, story, tech-debt, bug)").option("-l, --level <level>", "Filter by level (1=epic, 2=work). Default: 2").option("--parent <parentId>", "Filter by parent task id").option("--search <text>", "Search in name, description, and notes").action(
|
|
2179
2155
|
(opts) => {
|
|
2180
|
-
const
|
|
2181
|
-
|
|
2156
|
+
const projectResult = withProject(container, opts.project);
|
|
2157
|
+
if (!projectResult.ok) return printError(projectResult.error);
|
|
2158
|
+
const result = container.taskService.listTasks(projectResult.value, {
|
|
2182
2159
|
status: opts.status ?? "backlog",
|
|
2183
2160
|
type: opts.type,
|
|
2184
2161
|
level: opts.level ? parseInt(opts.level, 10) : void 0,
|
|
@@ -2257,6 +2234,8 @@ function registerTaskBreakdown(parent, container) {
|
|
|
2257
2234
|
function registerTaskRank(parent, container) {
|
|
2258
2235
|
parent.command("rank <id>").description("Re-rank a task in the backlog (Jira-style positioning)").option("--after <taskId>", "Place immediately after this task").option("--before <taskId>", "Place immediately before this task").option("--position <n>", "Place at 1-based position in backlog").option("--top", "Move to the top of active tasks").option("--bottom", "Move to the bottom of active tasks (above done tasks)").option("-p, --project <project>", "Project id or name").action(
|
|
2259
2236
|
(id, opts) => {
|
|
2237
|
+
const projectResult = withProject(container, opts.project);
|
|
2238
|
+
if (!projectResult.ok) return printError(projectResult.error);
|
|
2260
2239
|
const result = container.taskService.rerankTask(
|
|
2261
2240
|
{
|
|
2262
2241
|
taskId: id,
|
|
@@ -2266,7 +2245,7 @@ function registerTaskRank(parent, container) {
|
|
|
2266
2245
|
top: opts.top,
|
|
2267
2246
|
bottom: opts.bottom
|
|
2268
2247
|
},
|
|
2269
|
-
|
|
2248
|
+
projectResult.value
|
|
2270
2249
|
);
|
|
2271
2250
|
handleResult(result);
|
|
2272
2251
|
}
|
|
@@ -2276,7 +2255,9 @@ function registerTaskRank(parent, container) {
|
|
|
2276
2255
|
// src/cli/commands/task/search.ts
|
|
2277
2256
|
function registerTaskSearch(parent, container) {
|
|
2278
2257
|
parent.command("search <query>").description("Full-text search tasks with relevance ranking (FTS5)").option("-p, --project <project>", "Limit search to a project").action((query, opts) => {
|
|
2279
|
-
const
|
|
2258
|
+
const projectResult = withProject(container, opts.project);
|
|
2259
|
+
if (!projectResult.ok) return printError(projectResult.error);
|
|
2260
|
+
const result = container.taskService.searchTasks(query, projectResult.value);
|
|
2280
2261
|
handleResult(result);
|
|
2281
2262
|
});
|
|
2282
2263
|
}
|
|
@@ -2285,7 +2266,9 @@ function registerTaskSearch(parent, container) {
|
|
|
2285
2266
|
import { writeFileSync } from "fs";
|
|
2286
2267
|
function registerTaskExport(parent, container) {
|
|
2287
2268
|
parent.command("export").description("Export tasks to JSON file").option("-p, --project <project>", "Project id or name").option("-o, --output <file>", "Output file path (defaults to stdout)").action((opts) => {
|
|
2288
|
-
const
|
|
2269
|
+
const projectResult = withProject(container, opts.project);
|
|
2270
|
+
if (!projectResult.ok) return printError(projectResult.error);
|
|
2271
|
+
const result = container.portabilityService.exportTasks(projectResult.value);
|
|
2289
2272
|
if (!result.ok) {
|
|
2290
2273
|
return printError(result.error);
|
|
2291
2274
|
}
|
|
@@ -2326,7 +2309,13 @@ function registerTaskImport(parent, container) {
|
|
|
2326
2309
|
);
|
|
2327
2310
|
}
|
|
2328
2311
|
const fieldMapping = opts.map ? parseFieldMapping(opts.map) : void 0;
|
|
2329
|
-
const
|
|
2312
|
+
const projectResult = withProject(container, opts.project);
|
|
2313
|
+
if (!projectResult.ok) return printError(projectResult.error);
|
|
2314
|
+
const result = container.portabilityService.importTasks(
|
|
2315
|
+
fileData,
|
|
2316
|
+
projectResult.value,
|
|
2317
|
+
fieldMapping
|
|
2318
|
+
);
|
|
2330
2319
|
handleResult(result);
|
|
2331
2320
|
});
|
|
2332
2321
|
}
|
|
@@ -2412,7 +2401,7 @@ function buildCLI(container) {
|
|
|
2412
2401
|
registerDepList(dep, container);
|
|
2413
2402
|
registerDepGraph(dep, container);
|
|
2414
2403
|
program.command("tui").description("Launch interactive terminal UI").option("-p, --project <project>", "Start with specific project").action(async (opts) => {
|
|
2415
|
-
const { launchTUI } = await import("./tui-
|
|
2404
|
+
const { launchTUI } = await import("./tui-24ZW56Q6.js");
|
|
2416
2405
|
await launchTUI(container, opts.project);
|
|
2417
2406
|
});
|
|
2418
2407
|
return program;
|
|
@@ -2428,7 +2417,7 @@ async function main() {
|
|
|
2428
2417
|
const container = createContainer(db, config.dbPath);
|
|
2429
2418
|
const args = process.argv.slice(2);
|
|
2430
2419
|
if (args.length === 0) {
|
|
2431
|
-
const { launchTUI } = await import("./tui-
|
|
2420
|
+
const { launchTUI } = await import("./tui-24ZW56Q6.js");
|
|
2432
2421
|
await launchTUI(container);
|
|
2433
2422
|
} else {
|
|
2434
2423
|
const program = buildCLI(container);
|