@tomkapa/tayto 0.4.0 → 0.4.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 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, projectIdOrName) {
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: projectResult.value.id
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.resolveProject(parent.projectId);
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, projectIdOrName) {
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 projectRef = projectIdOrName ?? task.projectId;
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, projectIdOrName) {
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
- const projectResult = this.projectService.resolveProject(projectIdOrName);
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, projectService) {
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
- projectService;
1820
- exportTasks(projectIdOrName) {
1796
+ exportTasks(project) {
1821
1797
  return logger.startSpan("PortabilityService.exportTasks", () => {
1822
- const projectResult = this.projectService.resolveProject(projectIdOrName);
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, projectIdOrName, fieldMapping) {
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
- projectIdOrName
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
- opts.project
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 result = container.taskService.listTasks({
2181
- projectId: opts.project,
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
- opts.project
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 result = container.taskService.searchTasks(query, opts.project);
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 result = container.portabilityService.exportTasks(opts.project);
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 result = container.portabilityService.importTasks(fileData, opts.project, fieldMapping);
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-4GNIGMCK.js");
2404
+ const { launchTUI } = await import("./tui-IXZGQMWN.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-4GNIGMCK.js");
2420
+ const { launchTUI } = await import("./tui-IXZGQMWN.js");
2432
2421
  await launchTUI(container);
2433
2422
  } else {
2434
2423
  const program = buildCLI(container);