@obsfx/trekker 0.1.5

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.
Files changed (199) hide show
  1. package/bin/trekker.js +15 -0
  2. package/dist/index.js +2278 -0
  3. package/package.json +57 -0
  4. package/webapp-dist/.next/BUILD_ID +1 -0
  5. package/webapp-dist/.next/app-path-routes-manifest.json +14 -0
  6. package/webapp-dist/.next/build-manifest.json +19 -0
  7. package/webapp-dist/.next/package.json +1 -0
  8. package/webapp-dist/.next/prerender-manifest.json +85 -0
  9. package/webapp-dist/.next/required-server-files.json +323 -0
  10. package/webapp-dist/.next/routes-manifest.json +125 -0
  11. package/webapp-dist/.next/server/app/_global-error/page/app-paths-manifest.json +3 -0
  12. package/webapp-dist/.next/server/app/_global-error/page/build-manifest.json +16 -0
  13. package/webapp-dist/.next/server/app/_global-error/page/next-font-manifest.json +6 -0
  14. package/webapp-dist/.next/server/app/_global-error/page/react-loadable-manifest.json +1 -0
  15. package/webapp-dist/.next/server/app/_global-error/page/server-reference-manifest.json +4 -0
  16. package/webapp-dist/.next/server/app/_global-error/page.js +10 -0
  17. package/webapp-dist/.next/server/app/_global-error/page.js.map +5 -0
  18. package/webapp-dist/.next/server/app/_global-error/page.js.nft.json +1 -0
  19. package/webapp-dist/.next/server/app/_global-error/page_client-reference-manifest.js +2 -0
  20. package/webapp-dist/.next/server/app/_global-error.html +2 -0
  21. package/webapp-dist/.next/server/app/_global-error.meta +15 -0
  22. package/webapp-dist/.next/server/app/_global-error.rsc +12 -0
  23. package/webapp-dist/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +5 -0
  24. package/webapp-dist/.next/server/app/_global-error.segments/_full.segment.rsc +12 -0
  25. package/webapp-dist/.next/server/app/_global-error.segments/_head.segment.rsc +5 -0
  26. package/webapp-dist/.next/server/app/_global-error.segments/_index.segment.rsc +4 -0
  27. package/webapp-dist/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
  28. package/webapp-dist/.next/server/app/_not-found/page/app-paths-manifest.json +3 -0
  29. package/webapp-dist/.next/server/app/_not-found/page/build-manifest.json +16 -0
  30. package/webapp-dist/.next/server/app/_not-found/page/next-font-manifest.json +6 -0
  31. package/webapp-dist/.next/server/app/_not-found/page/react-loadable-manifest.json +1 -0
  32. package/webapp-dist/.next/server/app/_not-found/page/server-reference-manifest.json +4 -0
  33. package/webapp-dist/.next/server/app/_not-found/page.js +13 -0
  34. package/webapp-dist/.next/server/app/_not-found/page.js.map +5 -0
  35. package/webapp-dist/.next/server/app/_not-found/page.js.nft.json +1 -0
  36. package/webapp-dist/.next/server/app/_not-found/page_client-reference-manifest.js +2 -0
  37. package/webapp-dist/.next/server/app/_not-found.html +17 -0
  38. package/webapp-dist/.next/server/app/_not-found.meta +16 -0
  39. package/webapp-dist/.next/server/app/_not-found.rsc +14 -0
  40. package/webapp-dist/.next/server/app/_not-found.segments/_full.segment.rsc +14 -0
  41. package/webapp-dist/.next/server/app/_not-found.segments/_head.segment.rsc +5 -0
  42. package/webapp-dist/.next/server/app/_not-found.segments/_index.segment.rsc +6 -0
  43. package/webapp-dist/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -0
  44. package/webapp-dist/.next/server/app/_not-found.segments/_not-found.segment.rsc +4 -0
  45. package/webapp-dist/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -0
  46. package/webapp-dist/.next/server/app/api/comments/[id]/route/app-paths-manifest.json +3 -0
  47. package/webapp-dist/.next/server/app/api/comments/[id]/route/build-manifest.json +11 -0
  48. package/webapp-dist/.next/server/app/api/comments/[id]/route/server-reference-manifest.json +4 -0
  49. package/webapp-dist/.next/server/app/api/comments/[id]/route.js +7 -0
  50. package/webapp-dist/.next/server/app/api/comments/[id]/route.js.map +5 -0
  51. package/webapp-dist/.next/server/app/api/comments/[id]/route.js.nft.json +1 -0
  52. package/webapp-dist/.next/server/app/api/comments/[id]/route_client-reference-manifest.js +2 -0
  53. package/webapp-dist/.next/server/app/api/dependencies/route/app-paths-manifest.json +3 -0
  54. package/webapp-dist/.next/server/app/api/dependencies/route/build-manifest.json +11 -0
  55. package/webapp-dist/.next/server/app/api/dependencies/route/server-reference-manifest.json +4 -0
  56. package/webapp-dist/.next/server/app/api/dependencies/route.js +7 -0
  57. package/webapp-dist/.next/server/app/api/dependencies/route.js.map +5 -0
  58. package/webapp-dist/.next/server/app/api/dependencies/route.js.nft.json +1 -0
  59. package/webapp-dist/.next/server/app/api/dependencies/route_client-reference-manifest.js +2 -0
  60. package/webapp-dist/.next/server/app/api/epics/[id]/route/app-paths-manifest.json +3 -0
  61. package/webapp-dist/.next/server/app/api/epics/[id]/route/build-manifest.json +11 -0
  62. package/webapp-dist/.next/server/app/api/epics/[id]/route/server-reference-manifest.json +4 -0
  63. package/webapp-dist/.next/server/app/api/epics/[id]/route.js +7 -0
  64. package/webapp-dist/.next/server/app/api/epics/[id]/route.js.map +5 -0
  65. package/webapp-dist/.next/server/app/api/epics/[id]/route.js.nft.json +1 -0
  66. package/webapp-dist/.next/server/app/api/epics/[id]/route_client-reference-manifest.js +2 -0
  67. package/webapp-dist/.next/server/app/api/epics/route/app-paths-manifest.json +3 -0
  68. package/webapp-dist/.next/server/app/api/epics/route/build-manifest.json +11 -0
  69. package/webapp-dist/.next/server/app/api/epics/route/server-reference-manifest.json +4 -0
  70. package/webapp-dist/.next/server/app/api/epics/route.js +7 -0
  71. package/webapp-dist/.next/server/app/api/epics/route.js.map +5 -0
  72. package/webapp-dist/.next/server/app/api/epics/route.js.nft.json +1 -0
  73. package/webapp-dist/.next/server/app/api/epics/route_client-reference-manifest.js +2 -0
  74. package/webapp-dist/.next/server/app/api/events/route/app-paths-manifest.json +3 -0
  75. package/webapp-dist/.next/server/app/api/events/route/build-manifest.json +11 -0
  76. package/webapp-dist/.next/server/app/api/events/route/server-reference-manifest.json +4 -0
  77. package/webapp-dist/.next/server/app/api/events/route.js +6 -0
  78. package/webapp-dist/.next/server/app/api/events/route.js.map +5 -0
  79. package/webapp-dist/.next/server/app/api/events/route.js.nft.json +1 -0
  80. package/webapp-dist/.next/server/app/api/events/route_client-reference-manifest.js +2 -0
  81. package/webapp-dist/.next/server/app/api/project/route/app-paths-manifest.json +3 -0
  82. package/webapp-dist/.next/server/app/api/project/route/build-manifest.json +11 -0
  83. package/webapp-dist/.next/server/app/api/project/route/server-reference-manifest.json +4 -0
  84. package/webapp-dist/.next/server/app/api/project/route.js +7 -0
  85. package/webapp-dist/.next/server/app/api/project/route.js.map +5 -0
  86. package/webapp-dist/.next/server/app/api/project/route.js.nft.json +1 -0
  87. package/webapp-dist/.next/server/app/api/project/route_client-reference-manifest.js +2 -0
  88. package/webapp-dist/.next/server/app/api/tasks/[id]/comments/route/app-paths-manifest.json +3 -0
  89. package/webapp-dist/.next/server/app/api/tasks/[id]/comments/route/build-manifest.json +11 -0
  90. package/webapp-dist/.next/server/app/api/tasks/[id]/comments/route/server-reference-manifest.json +4 -0
  91. package/webapp-dist/.next/server/app/api/tasks/[id]/comments/route.js +7 -0
  92. package/webapp-dist/.next/server/app/api/tasks/[id]/comments/route.js.map +5 -0
  93. package/webapp-dist/.next/server/app/api/tasks/[id]/comments/route.js.nft.json +1 -0
  94. package/webapp-dist/.next/server/app/api/tasks/[id]/comments/route_client-reference-manifest.js +2 -0
  95. package/webapp-dist/.next/server/app/api/tasks/[id]/route/app-paths-manifest.json +3 -0
  96. package/webapp-dist/.next/server/app/api/tasks/[id]/route/build-manifest.json +11 -0
  97. package/webapp-dist/.next/server/app/api/tasks/[id]/route/server-reference-manifest.json +4 -0
  98. package/webapp-dist/.next/server/app/api/tasks/[id]/route.js +7 -0
  99. package/webapp-dist/.next/server/app/api/tasks/[id]/route.js.map +5 -0
  100. package/webapp-dist/.next/server/app/api/tasks/[id]/route.js.nft.json +1 -0
  101. package/webapp-dist/.next/server/app/api/tasks/[id]/route_client-reference-manifest.js +2 -0
  102. package/webapp-dist/.next/server/app/api/tasks/route/app-paths-manifest.json +3 -0
  103. package/webapp-dist/.next/server/app/api/tasks/route/build-manifest.json +11 -0
  104. package/webapp-dist/.next/server/app/api/tasks/route/server-reference-manifest.json +4 -0
  105. package/webapp-dist/.next/server/app/api/tasks/route.js +7 -0
  106. package/webapp-dist/.next/server/app/api/tasks/route.js.map +5 -0
  107. package/webapp-dist/.next/server/app/api/tasks/route.js.nft.json +1 -0
  108. package/webapp-dist/.next/server/app/api/tasks/route_client-reference-manifest.js +2 -0
  109. package/webapp-dist/.next/server/app/index.html +17 -0
  110. package/webapp-dist/.next/server/app/index.meta +14 -0
  111. package/webapp-dist/.next/server/app/index.rsc +18 -0
  112. package/webapp-dist/.next/server/app/index.segments/__PAGE__.segment.rsc +9 -0
  113. package/webapp-dist/.next/server/app/index.segments/_full.segment.rsc +18 -0
  114. package/webapp-dist/.next/server/app/index.segments/_head.segment.rsc +5 -0
  115. package/webapp-dist/.next/server/app/index.segments/_index.segment.rsc +6 -0
  116. package/webapp-dist/.next/server/app/index.segments/_tree.segment.rsc +2 -0
  117. package/webapp-dist/.next/server/app/page/app-paths-manifest.json +3 -0
  118. package/webapp-dist/.next/server/app/page/build-manifest.json +16 -0
  119. package/webapp-dist/.next/server/app/page/next-font-manifest.json +6 -0
  120. package/webapp-dist/.next/server/app/page/react-loadable-manifest.json +1 -0
  121. package/webapp-dist/.next/server/app/page/server-reference-manifest.json +4 -0
  122. package/webapp-dist/.next/server/app/page.js +15 -0
  123. package/webapp-dist/.next/server/app/page.js.map +5 -0
  124. package/webapp-dist/.next/server/app/page.js.nft.json +1 -0
  125. package/webapp-dist/.next/server/app/page_client-reference-manifest.js +2 -0
  126. package/webapp-dist/.next/server/app-paths-manifest.json +14 -0
  127. package/webapp-dist/.next/server/chunks/0a3b6_webapp__next-internal_server_app_api_comments_[id]_route_actions_af232ab0.js +3 -0
  128. package/webapp-dist/.next/server/chunks/0a3b6_webapp__next-internal_server_app_api_dependencies_route_actions_e60a141e.js +3 -0
  129. package/webapp-dist/.next/server/chunks/0a3b6_webapp__next-internal_server_app_api_tasks_[id]_comments_route_actions_7664dee6.js +3 -0
  130. package/webapp-dist/.next/server/chunks/457e5_packages_webapp__next-internal_server_app_api_epics_[id]_route_actions_4214a255.js +3 -0
  131. package/webapp-dist/.next/server/chunks/457e5_packages_webapp__next-internal_server_app_api_epics_route_actions_21a25d78.js +3 -0
  132. package/webapp-dist/.next/server/chunks/457e5_packages_webapp__next-internal_server_app_api_events_route_actions_7eb71690.js +3 -0
  133. package/webapp-dist/.next/server/chunks/457e5_packages_webapp__next-internal_server_app_api_project_route_actions_b9749fa9.js +3 -0
  134. package/webapp-dist/.next/server/chunks/457e5_packages_webapp__next-internal_server_app_api_tasks_[id]_route_actions_0a245d38.js +3 -0
  135. package/webapp-dist/.next/server/chunks/457e5_packages_webapp__next-internal_server_app_api_tasks_route_actions_36c9bc86.js +3 -0
  136. package/webapp-dist/.next/server/chunks/[root-of-the-server]__167728e4._.js +3 -0
  137. package/webapp-dist/.next/server/chunks/[root-of-the-server]__288a9fb4._.js +3 -0
  138. package/webapp-dist/.next/server/chunks/[root-of-the-server]__b483bdb2._.js +3 -0
  139. package/webapp-dist/.next/server/chunks/[root-of-the-server]__b9c44791._.js +7 -0
  140. package/webapp-dist/.next/server/chunks/[root-of-the-server]__d195c75a._.js +3 -0
  141. package/webapp-dist/.next/server/chunks/[root-of-the-server]__d5a6bced._.js +3 -0
  142. package/webapp-dist/.next/server/chunks/[root-of-the-server]__dccbb1d9._.js +19 -0
  143. package/webapp-dist/.next/server/chunks/[root-of-the-server]__eb3302c2._.js +3 -0
  144. package/webapp-dist/.next/server/chunks/[root-of-the-server]__f0999659._.js +3 -0
  145. package/webapp-dist/.next/server/chunks/[root-of-the-server]__f91dba61._.js +19 -0
  146. package/webapp-dist/.next/server/chunks/[root-of-the-server]__fa733c09._.js +3 -0
  147. package/webapp-dist/.next/server/chunks/[turbopack]_runtime.js +795 -0
  148. package/webapp-dist/.next/server/chunks/b001a_next_39efd30d._.js +17 -0
  149. package/webapp-dist/.next/server/chunks/ssr/457e5_packages_webapp__next-internal_server_app__global-error_page_actions_316934be.js +3 -0
  150. package/webapp-dist/.next/server/chunks/ssr/457e5_packages_webapp__next-internal_server_app__not-found_page_actions_51c8ae48.js +3 -0
  151. package/webapp-dist/.next/server/chunks/ssr/953a0_trekker_packages_webapp__next-internal_server_app_page_actions_c6362592.js +3 -0
  152. package/webapp-dist/.next/server/chunks/ssr/[root-of-the-server]__282182c1._.js +3 -0
  153. package/webapp-dist/.next/server/chunks/ssr/[root-of-the-server]__3c9630e5._.js +3 -0
  154. package/webapp-dist/.next/server/chunks/ssr/[root-of-the-server]__560e4049._.js +4 -0
  155. package/webapp-dist/.next/server/chunks/ssr/[root-of-the-server]__660feac5._.js +3 -0
  156. package/webapp-dist/.next/server/chunks/ssr/[root-of-the-server]__7a85eec3._.js +10 -0
  157. package/webapp-dist/.next/server/chunks/ssr/[root-of-the-server]__8a9deef1._.js +3 -0
  158. package/webapp-dist/.next/server/chunks/ssr/[root-of-the-server]__958d14fd._.js +3 -0
  159. package/webapp-dist/.next/server/chunks/ssr/[root-of-the-server]__bbfb83b6._.js +3 -0
  160. package/webapp-dist/.next/server/chunks/ssr/[turbopack]_runtime.js +795 -0
  161. package/webapp-dist/.next/server/chunks/ssr/b001a_next_dist_4febb8e2._.js +3 -0
  162. package/webapp-dist/.next/server/chunks/ssr/b001a_next_dist_70accf5e._.js +3 -0
  163. package/webapp-dist/.next/server/chunks/ssr/b001a_next_dist_722d79f4._.js +6 -0
  164. package/webapp-dist/.next/server/chunks/ssr/b001a_next_dist_99636b3e._.js +4 -0
  165. package/webapp-dist/.next/server/chunks/ssr/b001a_next_dist_client_components_10f1741b._.js +3 -0
  166. package/webapp-dist/.next/server/chunks/ssr/b001a_next_dist_client_components_builtin_forbidden_e274141c.js +3 -0
  167. package/webapp-dist/.next/server/chunks/ssr/b001a_next_dist_client_components_builtin_global-error_a5dade91.js +3 -0
  168. package/webapp-dist/.next/server/chunks/ssr/b001a_next_dist_client_components_builtin_unauthorized_348d5f3a.js +3 -0
  169. package/webapp-dist/.next/server/chunks/ssr/b001a_next_dist_esm_build_templates_app-page_441c6a47.js +4 -0
  170. package/webapp-dist/.next/server/chunks/ssr/workspace_trekker_7282b7cb._.js +4 -0
  171. package/webapp-dist/.next/server/chunks/ssr/workspace_trekker_a32cc225._.js +48 -0
  172. package/webapp-dist/.next/server/chunks/ssr/workspace_trekker_d88c7e00._.js +4 -0
  173. package/webapp-dist/.next/server/chunks/ssr/workspace_trekker_packages_webapp_src_68df25c3._.js +3 -0
  174. package/webapp-dist/.next/server/chunks/ssr/workspace_trekker_packages_webapp_src_components_providers_tsx_35c69be9._.js +3 -0
  175. package/webapp-dist/.next/server/functions-config-manifest.json +4 -0
  176. package/webapp-dist/.next/server/middleware-build-manifest.js +20 -0
  177. package/webapp-dist/.next/server/middleware-manifest.json +6 -0
  178. package/webapp-dist/.next/server/next-font-manifest.js +1 -0
  179. package/webapp-dist/.next/server/next-font-manifest.json +6 -0
  180. package/webapp-dist/.next/server/pages/404.html +17 -0
  181. package/webapp-dist/.next/server/pages/500.html +2 -0
  182. package/webapp-dist/.next/server/pages-manifest.json +4 -0
  183. package/webapp-dist/.next/server/server-reference-manifest.js +1 -0
  184. package/webapp-dist/.next/server/server-reference-manifest.json +5 -0
  185. package/webapp-dist/.next/static/chunks/1ac2cd06236076d4.js +46 -0
  186. package/webapp-dist/.next/static/chunks/3036933cb9bf38e3.js +1 -0
  187. package/webapp-dist/.next/static/chunks/5e0be427f68f6080.js +1 -0
  188. package/webapp-dist/.next/static/chunks/6aa9c115948055d1.js +1 -0
  189. package/webapp-dist/.next/static/chunks/a3a48138431e69f2.css +1 -0
  190. package/webapp-dist/.next/static/chunks/a6dad97d9634a72d.js +1 -0
  191. package/webapp-dist/.next/static/chunks/a6dad97d9634a72d.js.map +1 -0
  192. package/webapp-dist/.next/static/chunks/c1589cab6fb15b0d.js +5 -0
  193. package/webapp-dist/.next/static/chunks/de03c42fd52463c2.js +2 -0
  194. package/webapp-dist/.next/static/chunks/f87dc668b9e005e0.js +1 -0
  195. package/webapp-dist/.next/static/chunks/turbopack-d39d36eb8f918d5a.js +4 -0
  196. package/webapp-dist/.next/static/sziMhYzomTi_mBUq2dVcq/_buildManifest.js +11 -0
  197. package/webapp-dist/.next/static/sziMhYzomTi_mBUq2dVcq/_clientMiddlewareManifest.json +1 -0
  198. package/webapp-dist/.next/static/sziMhYzomTi_mBUq2dVcq/_ssgManifest.js +1 -0
  199. package/webapp-dist/server.js +38 -0
package/dist/index.js ADDED
@@ -0,0 +1,2278 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+ var __defProp = Object.defineProperty;
4
+ var __export = (target, all) => {
5
+ for (var name in all)
6
+ __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true,
9
+ configurable: true,
10
+ set: (newValue) => all[name] = () => newValue
11
+ });
12
+ };
13
+
14
+ // src/index.ts
15
+ import { Command as Command11 } from "commander";
16
+
17
+ // src/commands/init.ts
18
+ import { Command } from "commander";
19
+
20
+ // src/db/client.ts
21
+ import { Database } from "bun:sqlite";
22
+ import { drizzle } from "drizzle-orm/bun-sqlite";
23
+
24
+ // src/db/schema.ts
25
+ var exports_schema = {};
26
+ __export(exports_schema, {
27
+ tasksRelations: () => tasksRelations,
28
+ tasks: () => tasks,
29
+ projectsRelations: () => projectsRelations,
30
+ projects: () => projects,
31
+ idCounters: () => idCounters,
32
+ epicsRelations: () => epicsRelations,
33
+ epics: () => epics,
34
+ dependenciesRelations: () => dependenciesRelations,
35
+ dependencies: () => dependencies,
36
+ commentsRelations: () => commentsRelations,
37
+ comments: () => comments
38
+ });
39
+ import { relations } from "drizzle-orm";
40
+
41
+ // ../shared/schema.ts
42
+ import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
43
+ var projects = sqliteTable("projects", {
44
+ id: text("id").primaryKey(),
45
+ name: text("name").notNull().unique(),
46
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
47
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
48
+ });
49
+ var epics = sqliteTable("epics", {
50
+ id: text("id").primaryKey(),
51
+ projectId: text("project_id").notNull(),
52
+ title: text("title").notNull(),
53
+ description: text("description"),
54
+ status: text("status").notNull().default("todo"),
55
+ priority: integer("priority").notNull().default(2),
56
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
57
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
58
+ });
59
+ var tasks = sqliteTable("tasks", {
60
+ id: text("id").primaryKey(),
61
+ projectId: text("project_id").notNull(),
62
+ epicId: text("epic_id"),
63
+ parentTaskId: text("parent_task_id"),
64
+ title: text("title").notNull(),
65
+ description: text("description"),
66
+ priority: integer("priority").notNull().default(2),
67
+ status: text("status").notNull().default("todo"),
68
+ tags: text("tags"),
69
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
70
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
71
+ });
72
+ var comments = sqliteTable("comments", {
73
+ id: text("id").primaryKey(),
74
+ taskId: text("task_id").notNull(),
75
+ author: text("author").notNull(),
76
+ content: text("content").notNull(),
77
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
78
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
79
+ });
80
+ var dependencies = sqliteTable("dependencies", {
81
+ id: text("id").primaryKey(),
82
+ taskId: text("task_id").notNull(),
83
+ dependsOnId: text("depends_on_id").notNull(),
84
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
85
+ });
86
+ var idCounters = sqliteTable("id_counters", {
87
+ entityType: text("entity_type").primaryKey(),
88
+ counter: integer("counter").notNull().default(0)
89
+ });
90
+ // ../shared/types.ts
91
+ var TASK_STATUSES = [
92
+ "todo",
93
+ "in_progress",
94
+ "completed",
95
+ "wont_fix",
96
+ "archived"
97
+ ];
98
+ var EPIC_STATUSES = [
99
+ "todo",
100
+ "in_progress",
101
+ "completed",
102
+ "archived"
103
+ ];
104
+ var PREFIX_MAP = {
105
+ task: "TREK",
106
+ epic: "EPIC",
107
+ comment: "CMT"
108
+ };
109
+ // src/db/schema.ts
110
+ var projectsRelations = relations(projects, ({ many }) => ({
111
+ epics: many(epics),
112
+ tasks: many(tasks)
113
+ }));
114
+ var epicsRelations = relations(epics, ({ one, many }) => ({
115
+ project: one(projects, {
116
+ fields: [epics.projectId],
117
+ references: [projects.id]
118
+ }),
119
+ tasks: many(tasks)
120
+ }));
121
+ var tasksRelations = relations(tasks, ({ one, many }) => ({
122
+ project: one(projects, {
123
+ fields: [tasks.projectId],
124
+ references: [projects.id]
125
+ }),
126
+ epic: one(epics, {
127
+ fields: [tasks.epicId],
128
+ references: [epics.id]
129
+ }),
130
+ parentTask: one(tasks, {
131
+ fields: [tasks.parentTaskId],
132
+ references: [tasks.id],
133
+ relationName: "subtasks"
134
+ }),
135
+ subtasks: many(tasks, { relationName: "subtasks" }),
136
+ comments: many(comments),
137
+ dependsOn: many(dependencies, { relationName: "dependsOn" }),
138
+ blockedBy: many(dependencies, { relationName: "blockedBy" })
139
+ }));
140
+ var commentsRelations = relations(comments, ({ one }) => ({
141
+ task: one(tasks, {
142
+ fields: [comments.taskId],
143
+ references: [tasks.id]
144
+ })
145
+ }));
146
+ var dependenciesRelations = relations(dependencies, ({ one }) => ({
147
+ task: one(tasks, {
148
+ fields: [dependencies.taskId],
149
+ references: [tasks.id],
150
+ relationName: "dependsOn"
151
+ }),
152
+ dependsOn: one(tasks, {
153
+ fields: [dependencies.dependsOnId],
154
+ references: [tasks.id],
155
+ relationName: "blockedBy"
156
+ })
157
+ }));
158
+
159
+ // src/db/client.ts
160
+ import { existsSync, mkdirSync, rmSync } from "fs";
161
+ import { join } from "path";
162
+ var TREKKER_DIR = ".trekker";
163
+ var DB_NAME = "trekker.db";
164
+ function getTrekkerDir(cwd = process.cwd()) {
165
+ return join(cwd, TREKKER_DIR);
166
+ }
167
+ function getDbPath(cwd = process.cwd()) {
168
+ return join(getTrekkerDir(cwd), DB_NAME);
169
+ }
170
+ function isTrekkerInitialized(cwd = process.cwd()) {
171
+ return existsSync(getDbPath(cwd));
172
+ }
173
+ function ensureTrekkerDir(cwd = process.cwd()) {
174
+ const trekkerDir = getTrekkerDir(cwd);
175
+ if (!existsSync(trekkerDir)) {
176
+ mkdirSync(trekkerDir, { recursive: true });
177
+ }
178
+ }
179
+ var dbInstance = null;
180
+ var sqliteInstance = null;
181
+ function getDb(cwd = process.cwd()) {
182
+ if (dbInstance) {
183
+ return dbInstance;
184
+ }
185
+ const dbPath = getDbPath(cwd);
186
+ if (!existsSync(dbPath)) {
187
+ throw new Error("Trekker not initialized. Run 'trekker init' first.");
188
+ }
189
+ sqliteInstance = new Database(dbPath);
190
+ dbInstance = drizzle(sqliteInstance, { schema: exports_schema });
191
+ return dbInstance;
192
+ }
193
+ function createDb(cwd = process.cwd()) {
194
+ ensureTrekkerDir(cwd);
195
+ const dbPath = getDbPath(cwd);
196
+ sqliteInstance = new Database(dbPath);
197
+ dbInstance = drizzle(sqliteInstance, { schema: exports_schema });
198
+ sqliteInstance.exec(`
199
+ CREATE TABLE IF NOT EXISTS projects (
200
+ id TEXT PRIMARY KEY,
201
+ name TEXT NOT NULL UNIQUE,
202
+ created_at INTEGER NOT NULL,
203
+ updated_at INTEGER NOT NULL
204
+ );
205
+
206
+ CREATE TABLE IF NOT EXISTS epics (
207
+ id TEXT PRIMARY KEY,
208
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
209
+ title TEXT NOT NULL,
210
+ description TEXT,
211
+ status TEXT NOT NULL DEFAULT 'todo',
212
+ priority INTEGER NOT NULL DEFAULT 2,
213
+ created_at INTEGER NOT NULL,
214
+ updated_at INTEGER NOT NULL
215
+ );
216
+
217
+ CREATE TABLE IF NOT EXISTS tasks (
218
+ id TEXT PRIMARY KEY,
219
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
220
+ epic_id TEXT REFERENCES epics(id) ON DELETE SET NULL,
221
+ parent_task_id TEXT,
222
+ title TEXT NOT NULL,
223
+ description TEXT,
224
+ priority INTEGER NOT NULL DEFAULT 2,
225
+ status TEXT NOT NULL DEFAULT 'todo',
226
+ tags TEXT,
227
+ created_at INTEGER NOT NULL,
228
+ updated_at INTEGER NOT NULL
229
+ );
230
+
231
+ CREATE TABLE IF NOT EXISTS comments (
232
+ id TEXT PRIMARY KEY,
233
+ task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
234
+ author TEXT NOT NULL,
235
+ content TEXT NOT NULL,
236
+ created_at INTEGER NOT NULL,
237
+ updated_at INTEGER NOT NULL
238
+ );
239
+
240
+ CREATE TABLE IF NOT EXISTS dependencies (
241
+ id TEXT PRIMARY KEY,
242
+ task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
243
+ depends_on_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
244
+ created_at INTEGER NOT NULL
245
+ );
246
+
247
+ CREATE TABLE IF NOT EXISTS id_counters (
248
+ entity_type TEXT PRIMARY KEY,
249
+ counter INTEGER NOT NULL DEFAULT 0
250
+ );
251
+
252
+ -- Initialize counters
253
+ INSERT OR IGNORE INTO id_counters (entity_type, counter) VALUES ('task', 0);
254
+ INSERT OR IGNORE INTO id_counters (entity_type, counter) VALUES ('epic', 0);
255
+ INSERT OR IGNORE INTO id_counters (entity_type, counter) VALUES ('comment', 0);
256
+ `);
257
+ return dbInstance;
258
+ }
259
+ function closeDb() {
260
+ if (sqliteInstance) {
261
+ sqliteInstance.close();
262
+ sqliteInstance = null;
263
+ dbInstance = null;
264
+ }
265
+ }
266
+ function deleteDb(cwd = process.cwd()) {
267
+ closeDb();
268
+ const trekkerDir = getTrekkerDir(cwd);
269
+ if (existsSync(trekkerDir)) {
270
+ rmSync(trekkerDir, { recursive: true, force: true });
271
+ }
272
+ }
273
+
274
+ // src/utils/id-generator.ts
275
+ import { eq, sql } from "drizzle-orm";
276
+ function generateId(entityType) {
277
+ const db = getDb();
278
+ const prefix = PREFIX_MAP[entityType];
279
+ db.update(idCounters).set({ counter: sql`${idCounters.counter} + 1` }).where(eq(idCounters.entityType, entityType)).run();
280
+ const result = db.select({ counter: idCounters.counter }).from(idCounters).where(eq(idCounters.entityType, entityType)).get();
281
+ if (!result) {
282
+ throw new Error(`Counter not found for entity type: ${entityType}`);
283
+ }
284
+ return `${prefix}-${result.counter}`;
285
+ }
286
+ function generateUuid() {
287
+ return crypto.randomUUID();
288
+ }
289
+
290
+ // src/services/project.ts
291
+ import { basename } from "path";
292
+ function initProject(cwd = process.cwd()) {
293
+ if (isTrekkerInitialized(cwd)) {
294
+ throw new Error("Trekker is already initialized in this directory.");
295
+ }
296
+ const db = createDb(cwd);
297
+ const projectName = basename(cwd);
298
+ const now = new Date;
299
+ db.insert(projects).values({
300
+ id: generateUuid(),
301
+ name: projectName,
302
+ createdAt: now,
303
+ updatedAt: now
304
+ }).run();
305
+ }
306
+ function wipeProject(cwd = process.cwd()) {
307
+ if (!isTrekkerInitialized(cwd)) {
308
+ throw new Error("Trekker is not initialized in this directory.");
309
+ }
310
+ deleteDb(cwd);
311
+ }
312
+
313
+ // src/utils/output.ts
314
+ var jsonMode = false;
315
+ function setJsonMode(enabled) {
316
+ jsonMode = enabled;
317
+ }
318
+ function isJsonMode() {
319
+ return jsonMode;
320
+ }
321
+ function output(data) {
322
+ if (jsonMode) {
323
+ console.log(JSON.stringify(data, null, 2));
324
+ } else if (typeof data === "string") {
325
+ console.log(data);
326
+ } else {
327
+ console.log(JSON.stringify(data, null, 2));
328
+ }
329
+ }
330
+ function success(message, data) {
331
+ if (jsonMode) {
332
+ console.log(JSON.stringify({ success: true, message, data }, null, 2));
333
+ } else {
334
+ console.log(`\u2713 ${message}`);
335
+ if (data) {
336
+ output(data);
337
+ }
338
+ }
339
+ }
340
+ function error(message, details) {
341
+ if (jsonMode) {
342
+ console.error(JSON.stringify({ success: false, error: message, details }, null, 2));
343
+ } else {
344
+ console.error(`\u2717 Error: ${message}`);
345
+ if (details) {
346
+ console.error(details);
347
+ }
348
+ }
349
+ }
350
+ function info(message) {
351
+ if (!jsonMode) {
352
+ console.log(message);
353
+ }
354
+ }
355
+ function formatTask(task) {
356
+ const lines = [
357
+ `ID: ${task.id}`,
358
+ `Title: ${task.title}`,
359
+ `Status: ${task.status}`,
360
+ `Priority: ${task.priority}`
361
+ ];
362
+ if (task.description) {
363
+ lines.push(`Description: ${task.description}`);
364
+ }
365
+ if (task.epicId) {
366
+ lines.push(`Epic: ${task.epicId}`);
367
+ }
368
+ if (task.parentTaskId) {
369
+ lines.push(`Parent: ${task.parentTaskId}`);
370
+ }
371
+ if (task.tags) {
372
+ lines.push(`Tags: ${task.tags}`);
373
+ }
374
+ lines.push(`Created: ${task.createdAt.toISOString()}`);
375
+ lines.push(`Updated: ${task.updatedAt.toISOString()}`);
376
+ return lines.join(`
377
+ `);
378
+ }
379
+ function formatEpic(epic) {
380
+ const lines = [
381
+ `ID: ${epic.id}`,
382
+ `Title: ${epic.title}`,
383
+ `Status: ${epic.status}`,
384
+ `Priority: ${epic.priority}`
385
+ ];
386
+ if (epic.description) {
387
+ lines.push(`Description: ${epic.description}`);
388
+ }
389
+ lines.push(`Created: ${epic.createdAt.toISOString()}`);
390
+ lines.push(`Updated: ${epic.updatedAt.toISOString()}`);
391
+ return lines.join(`
392
+ `);
393
+ }
394
+ function formatComment(comment) {
395
+ const lines = [
396
+ `ID: ${comment.id}`,
397
+ `Author: ${comment.author}`,
398
+ `Content: ${comment.content}`,
399
+ `Created: ${comment.createdAt.toISOString()}`
400
+ ];
401
+ return lines.join(`
402
+ `);
403
+ }
404
+ function formatTaskList(tasks2) {
405
+ if (tasks2.length === 0) {
406
+ return "No tasks found.";
407
+ }
408
+ const lines = tasks2.map((task) => {
409
+ const tags = task.tags ? ` [${task.tags}]` : "";
410
+ const parent = task.parentTaskId ? ` (subtask of ${task.parentTaskId})` : "";
411
+ return `${task.id} | ${task.status.padEnd(11)} | P${task.priority} | ${task.title}${tags}${parent}`;
412
+ });
413
+ return lines.join(`
414
+ `);
415
+ }
416
+ function formatEpicList(epics2) {
417
+ if (epics2.length === 0) {
418
+ return "No epics found.";
419
+ }
420
+ const lines = epics2.map((epic) => {
421
+ return `${epic.id} | ${epic.status.padEnd(11)} | P${epic.priority} | ${epic.title}`;
422
+ });
423
+ return lines.join(`
424
+ `);
425
+ }
426
+ function formatCommentList(comments2) {
427
+ if (comments2.length === 0) {
428
+ return "No comments found.";
429
+ }
430
+ return comments2.map((c) => `[${c.id}] ${c.author}: ${c.content}`).join(`
431
+ `);
432
+ }
433
+ function formatDependencyList(dependencies2, direction) {
434
+ if (dependencies2.length === 0) {
435
+ return direction === "depends_on" ? "No dependencies." : "Does not block any tasks.";
436
+ }
437
+ if (direction === "depends_on") {
438
+ return dependencies2.map((d) => ` \u2192 depends on ${d.dependsOnId}`).join(`
439
+ `);
440
+ } else {
441
+ return dependencies2.map((d) => ` \u2192 blocks ${d.taskId}`).join(`
442
+ `);
443
+ }
444
+ }
445
+
446
+ // src/commands/init.ts
447
+ var initCommand = new Command("init").description("Initialize Trekker in the current directory").action(() => {
448
+ try {
449
+ if (isTrekkerInitialized()) {
450
+ error("Trekker is already initialized in this directory.");
451
+ process.exit(1);
452
+ }
453
+ initProject();
454
+ success("Trekker initialized successfully.");
455
+ } catch (err) {
456
+ error(err instanceof Error ? err.message : String(err));
457
+ process.exit(1);
458
+ }
459
+ });
460
+
461
+ // src/commands/wipe.ts
462
+ import { Command as Command2 } from "commander";
463
+ import * as readline from "readline";
464
+ var wipeCommand = new Command2("wipe").description("Delete all Trekker data in the current directory").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
465
+ try {
466
+ if (!isTrekkerInitialized()) {
467
+ error("Trekker is not initialized in this directory.");
468
+ process.exit(1);
469
+ }
470
+ if (!options.yes) {
471
+ const confirmed = await confirm("Are you sure you want to delete all Trekker data? This cannot be undone. (y/N): ");
472
+ if (!confirmed) {
473
+ console.log("Aborted.");
474
+ return;
475
+ }
476
+ }
477
+ wipeProject();
478
+ success("Trekker data deleted successfully.");
479
+ } catch (err) {
480
+ error(err instanceof Error ? err.message : String(err));
481
+ process.exit(1);
482
+ }
483
+ });
484
+ function confirm(prompt) {
485
+ return new Promise((resolve) => {
486
+ const rl = readline.createInterface({
487
+ input: process.stdin,
488
+ output: process.stdout
489
+ });
490
+ rl.question(prompt, (answer) => {
491
+ rl.close();
492
+ resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
493
+ });
494
+ });
495
+ }
496
+
497
+ // src/commands/epic.ts
498
+ import { Command as Command3 } from "commander";
499
+
500
+ // src/services/epic.ts
501
+ import { eq as eq2 } from "drizzle-orm";
502
+ function createEpic(input) {
503
+ const db = getDb();
504
+ const project = db.select().from(projects).get();
505
+ if (!project) {
506
+ throw new Error("Project not found. Run 'trekker init' first.");
507
+ }
508
+ const id = generateId("epic");
509
+ const now = new Date;
510
+ const epic = {
511
+ id,
512
+ projectId: project.id,
513
+ title: input.title,
514
+ description: input.description ?? null,
515
+ status: input.status ?? "todo",
516
+ priority: input.priority ?? 2,
517
+ createdAt: now,
518
+ updatedAt: now
519
+ };
520
+ db.insert(epics).values(epic).run();
521
+ return epic;
522
+ }
523
+ function getEpic(id) {
524
+ const db = getDb();
525
+ const result = db.select().from(epics).where(eq2(epics.id, id)).get();
526
+ return result;
527
+ }
528
+ function listEpics(status) {
529
+ const db = getDb();
530
+ if (status) {
531
+ return db.select().from(epics).where(eq2(epics.status, status)).all();
532
+ }
533
+ return db.select().from(epics).all();
534
+ }
535
+ function updateEpic(id, input) {
536
+ const db = getDb();
537
+ const existing = getEpic(id);
538
+ if (!existing) {
539
+ throw new Error(`Epic not found: ${id}`);
540
+ }
541
+ const updates = {
542
+ updatedAt: new Date
543
+ };
544
+ if (input.title !== undefined)
545
+ updates.title = input.title;
546
+ if (input.description !== undefined)
547
+ updates.description = input.description;
548
+ if (input.status !== undefined)
549
+ updates.status = input.status;
550
+ if (input.priority !== undefined)
551
+ updates.priority = input.priority;
552
+ db.update(epics).set(updates).where(eq2(epics.id, id)).run();
553
+ return getEpic(id);
554
+ }
555
+ function deleteEpic(id) {
556
+ const db = getDb();
557
+ const existing = getEpic(id);
558
+ if (!existing) {
559
+ throw new Error(`Epic not found: ${id}`);
560
+ }
561
+ db.delete(epics).where(eq2(epics.id, id)).run();
562
+ }
563
+ // src/utils/validator.ts
564
+ function isValidTaskStatus(status) {
565
+ return TASK_STATUSES.includes(status);
566
+ }
567
+ function isValidEpicStatus(status) {
568
+ return EPIC_STATUSES.includes(status);
569
+ }
570
+ function isValidPriority(priority) {
571
+ return Number.isInteger(priority) && priority >= 0 && priority <= 5;
572
+ }
573
+ function parseStatus(status, type) {
574
+ if (!status)
575
+ return;
576
+ const normalizedStatus = status.toLowerCase().replace(/-/g, "_");
577
+ if (type === "task") {
578
+ if (!isValidTaskStatus(normalizedStatus)) {
579
+ throw new Error(`Invalid task status: ${status}. Valid values: ${TASK_STATUSES.join(", ")}`);
580
+ }
581
+ return normalizedStatus;
582
+ } else {
583
+ if (!isValidEpicStatus(normalizedStatus)) {
584
+ throw new Error(`Invalid epic status: ${status}. Valid values: ${EPIC_STATUSES.join(", ")}`);
585
+ }
586
+ return normalizedStatus;
587
+ }
588
+ }
589
+ function parsePriority(priority) {
590
+ if (priority === undefined)
591
+ return;
592
+ const num = parseInt(priority, 10);
593
+ if (isNaN(num) || !isValidPriority(num)) {
594
+ throw new Error(`Invalid priority: ${priority}. Must be a number between 0 and 5.`);
595
+ }
596
+ return num;
597
+ }
598
+ function validateRequired(value, fieldName) {
599
+ if (value === undefined || value === null || value === "") {
600
+ throw new Error(`${fieldName} is required`);
601
+ }
602
+ }
603
+
604
+ // src/commands/epic.ts
605
+ var epicCommand = new Command3("epic").description("Manage epics");
606
+ epicCommand.command("create").description("Create a new epic").requiredOption("-t, --title <title>", "Epic title").option("-d, --description <description>", "Epic description").option("-p, --priority <priority>", "Priority (0-5, default: 2)").option("-s, --status <status>", "Status (todo, in_progress, completed, archived)").action((options) => {
607
+ try {
608
+ validateRequired(options.title, "Title");
609
+ const epic = createEpic({
610
+ title: options.title,
611
+ description: options.description,
612
+ priority: parsePriority(options.priority),
613
+ status: parseStatus(options.status, "epic")
614
+ });
615
+ if (isJsonMode()) {
616
+ output(epic);
617
+ } else {
618
+ success(`Epic created: ${epic.id}`);
619
+ console.log(formatEpic(epic));
620
+ }
621
+ } catch (err) {
622
+ error(err instanceof Error ? err.message : String(err));
623
+ process.exit(1);
624
+ }
625
+ });
626
+ epicCommand.command("list").description("List all epics").option("-s, --status <status>", "Filter by status").action((options) => {
627
+ try {
628
+ const status = parseStatus(options.status, "epic");
629
+ const epics2 = listEpics(status);
630
+ if (isJsonMode()) {
631
+ output(epics2);
632
+ } else {
633
+ console.log(formatEpicList(epics2));
634
+ }
635
+ } catch (err) {
636
+ error(err instanceof Error ? err.message : String(err));
637
+ process.exit(1);
638
+ }
639
+ });
640
+ epicCommand.command("show <epic-id>").description("Show epic details").action((epicId) => {
641
+ try {
642
+ const epic = getEpic(epicId);
643
+ if (!epic) {
644
+ error(`Epic not found: ${epicId}`);
645
+ process.exit(1);
646
+ }
647
+ if (isJsonMode()) {
648
+ output(epic);
649
+ } else {
650
+ console.log(formatEpic(epic));
651
+ }
652
+ } catch (err) {
653
+ error(err instanceof Error ? err.message : String(err));
654
+ process.exit(1);
655
+ }
656
+ });
657
+ epicCommand.command("update <epic-id>").description("Update an epic").option("-t, --title <title>", "New title").option("-d, --description <description>", "New description").option("-p, --priority <priority>", "New priority (0-5)").option("-s, --status <status>", "New status").action((epicId, options) => {
658
+ try {
659
+ const epic = updateEpic(epicId, {
660
+ title: options.title,
661
+ description: options.description,
662
+ priority: parsePriority(options.priority),
663
+ status: parseStatus(options.status, "epic")
664
+ });
665
+ if (isJsonMode()) {
666
+ output(epic);
667
+ } else {
668
+ success(`Epic updated: ${epic.id}`);
669
+ console.log(formatEpic(epic));
670
+ }
671
+ } catch (err) {
672
+ error(err instanceof Error ? err.message : String(err));
673
+ process.exit(1);
674
+ }
675
+ });
676
+ epicCommand.command("delete <epic-id>").description("Delete an epic").action((epicId) => {
677
+ try {
678
+ deleteEpic(epicId);
679
+ success(`Epic deleted: ${epicId}`);
680
+ } catch (err) {
681
+ error(err instanceof Error ? err.message : String(err));
682
+ process.exit(1);
683
+ }
684
+ });
685
+
686
+ // src/commands/task.ts
687
+ import { Command as Command4 } from "commander";
688
+
689
+ // src/services/task.ts
690
+ import { eq as eq3, and, isNull } from "drizzle-orm";
691
+ function createTask(input) {
692
+ const db = getDb();
693
+ const project = db.select().from(projects).get();
694
+ if (!project) {
695
+ throw new Error("Project not found. Run 'trekker init' first.");
696
+ }
697
+ if (input.epicId) {
698
+ const epic = db.select().from(epics).where(eq3(epics.id, input.epicId)).get();
699
+ if (!epic) {
700
+ throw new Error(`Epic not found: ${input.epicId}`);
701
+ }
702
+ }
703
+ if (input.parentTaskId) {
704
+ const parent = db.select().from(tasks).where(eq3(tasks.id, input.parentTaskId)).get();
705
+ if (!parent) {
706
+ throw new Error(`Parent task not found: ${input.parentTaskId}`);
707
+ }
708
+ }
709
+ const id = generateId("task");
710
+ const now = new Date;
711
+ const task = {
712
+ id,
713
+ projectId: project.id,
714
+ epicId: input.epicId ?? null,
715
+ parentTaskId: input.parentTaskId ?? null,
716
+ title: input.title,
717
+ description: input.description ?? null,
718
+ priority: input.priority ?? 2,
719
+ status: input.status ?? "todo",
720
+ tags: input.tags ?? null,
721
+ createdAt: now,
722
+ updatedAt: now
723
+ };
724
+ db.insert(tasks).values(task).run();
725
+ return task;
726
+ }
727
+ function getTask(id) {
728
+ const db = getDb();
729
+ const result = db.select().from(tasks).where(eq3(tasks.id, id)).get();
730
+ return result;
731
+ }
732
+ function listTasks(options) {
733
+ const db = getDb();
734
+ const conditions = [];
735
+ if (options?.status) {
736
+ conditions.push(eq3(tasks.status, options.status));
737
+ }
738
+ if (options?.epicId) {
739
+ conditions.push(eq3(tasks.epicId, options.epicId));
740
+ }
741
+ if (options?.parentTaskId === null) {
742
+ conditions.push(isNull(tasks.parentTaskId));
743
+ } else if (options?.parentTaskId) {
744
+ conditions.push(eq3(tasks.parentTaskId, options.parentTaskId));
745
+ }
746
+ if (conditions.length > 0) {
747
+ return db.select().from(tasks).where(and(...conditions)).all();
748
+ }
749
+ return db.select().from(tasks).all();
750
+ }
751
+ function listSubtasks(parentTaskId) {
752
+ const db = getDb();
753
+ return db.select().from(tasks).where(eq3(tasks.parentTaskId, parentTaskId)).all();
754
+ }
755
+ function updateTask(id, input) {
756
+ const db = getDb();
757
+ const existing = getTask(id);
758
+ if (!existing) {
759
+ throw new Error(`Task not found: ${id}`);
760
+ }
761
+ if (input.epicId) {
762
+ const epic = db.select().from(epics).where(eq3(epics.id, input.epicId)).get();
763
+ if (!epic) {
764
+ throw new Error(`Epic not found: ${input.epicId}`);
765
+ }
766
+ }
767
+ const updates = {
768
+ updatedAt: new Date
769
+ };
770
+ if (input.title !== undefined)
771
+ updates.title = input.title;
772
+ if (input.description !== undefined)
773
+ updates.description = input.description;
774
+ if (input.priority !== undefined)
775
+ updates.priority = input.priority;
776
+ if (input.status !== undefined)
777
+ updates.status = input.status;
778
+ if (input.tags !== undefined)
779
+ updates.tags = input.tags;
780
+ if (input.epicId !== undefined)
781
+ updates.epicId = input.epicId;
782
+ db.update(tasks).set(updates).where(eq3(tasks.id, id)).run();
783
+ return getTask(id);
784
+ }
785
+ function deleteTask(id) {
786
+ const db = getDb();
787
+ const existing = getTask(id);
788
+ if (!existing) {
789
+ throw new Error(`Task not found: ${id}`);
790
+ }
791
+ db.delete(tasks).where(eq3(tasks.id, id)).run();
792
+ }
793
+
794
+ // src/commands/task.ts
795
+ var taskCommand = new Command4("task").description("Manage tasks");
796
+ taskCommand.command("create").description("Create a new task").requiredOption("-t, --title <title>", "Task title").option("-d, --description <description>", "Task description").option("-p, --priority <priority>", "Priority (0-5, default: 2)").option("-s, --status <status>", "Status (todo, in_progress, completed, wont_fix, archived)").option("--tags <tags>", "Comma-separated tags").option("-e, --epic <epic-id>", "Epic ID to assign task to").action((options) => {
797
+ try {
798
+ validateRequired(options.title, "Title");
799
+ const task = createTask({
800
+ title: options.title,
801
+ description: options.description,
802
+ priority: parsePriority(options.priority),
803
+ status: parseStatus(options.status, "task"),
804
+ tags: options.tags,
805
+ epicId: options.epic
806
+ });
807
+ if (isJsonMode()) {
808
+ output(task);
809
+ } else {
810
+ success(`Task created: ${task.id}`);
811
+ console.log(formatTask(task));
812
+ }
813
+ } catch (err) {
814
+ error(err instanceof Error ? err.message : String(err));
815
+ process.exit(1);
816
+ }
817
+ });
818
+ taskCommand.command("list").description("List all tasks").option("-s, --status <status>", "Filter by status").option("-e, --epic <epic-id>", "Filter by epic").action((options) => {
819
+ try {
820
+ const status = parseStatus(options.status, "task");
821
+ const tasks2 = listTasks({
822
+ status,
823
+ epicId: options.epic,
824
+ parentTaskId: null
825
+ });
826
+ if (isJsonMode()) {
827
+ output(tasks2);
828
+ } else {
829
+ console.log(formatTaskList(tasks2));
830
+ }
831
+ } catch (err) {
832
+ error(err instanceof Error ? err.message : String(err));
833
+ process.exit(1);
834
+ }
835
+ });
836
+ taskCommand.command("show <task-id>").description("Show task details").action((taskId) => {
837
+ try {
838
+ const task = getTask(taskId);
839
+ if (!task) {
840
+ error(`Task not found: ${taskId}`);
841
+ process.exit(1);
842
+ }
843
+ if (isJsonMode()) {
844
+ output(task);
845
+ } else {
846
+ console.log(formatTask(task));
847
+ }
848
+ } catch (err) {
849
+ error(err instanceof Error ? err.message : String(err));
850
+ process.exit(1);
851
+ }
852
+ });
853
+ taskCommand.command("update <task-id>").description("Update a task").option("-t, --title <title>", "New title").option("-d, --description <description>", "New description").option("-p, --priority <priority>", "New priority (0-5)").option("-s, --status <status>", "New status").option("--tags <tags>", "New tags (comma-separated)").option("-e, --epic <epic-id>", "New epic ID").option("--no-epic", "Remove from epic").action((taskId, options) => {
854
+ try {
855
+ const updateInput = {};
856
+ if (options.title !== undefined)
857
+ updateInput.title = options.title;
858
+ if (options.description !== undefined)
859
+ updateInput.description = options.description;
860
+ if (options.priority !== undefined)
861
+ updateInput.priority = parsePriority(options.priority);
862
+ if (options.status !== undefined) {
863
+ updateInput.status = parseStatus(options.status, "task");
864
+ }
865
+ if (options.tags !== undefined)
866
+ updateInput.tags = options.tags;
867
+ if (options.epic === false) {
868
+ updateInput.epicId = null;
869
+ } else if (options.epic !== undefined) {
870
+ updateInput.epicId = options.epic;
871
+ }
872
+ const task = updateTask(taskId, updateInput);
873
+ if (isJsonMode()) {
874
+ output(task);
875
+ } else {
876
+ success(`Task updated: ${task.id}`);
877
+ console.log(formatTask(task));
878
+ }
879
+ } catch (err) {
880
+ error(err instanceof Error ? err.message : String(err));
881
+ process.exit(1);
882
+ }
883
+ });
884
+ taskCommand.command("delete <task-id>").description("Delete a task").action((taskId) => {
885
+ try {
886
+ deleteTask(taskId);
887
+ success(`Task deleted: ${taskId}`);
888
+ } catch (err) {
889
+ error(err instanceof Error ? err.message : String(err));
890
+ process.exit(1);
891
+ }
892
+ });
893
+
894
+ // src/commands/subtask.ts
895
+ import { Command as Command5 } from "commander";
896
+ var subtaskCommand = new Command5("subtask").description("Manage subtasks");
897
+ subtaskCommand.command("create <parent-task-id>").description("Create a new subtask").requiredOption("-t, --title <title>", "Subtask title").option("-d, --description <description>", "Subtask description").option("-p, --priority <priority>", "Priority (0-5, default: 2)").option("-s, --status <status>", "Status (todo, in_progress, completed, wont_fix, archived)").action((parentTaskId, options) => {
898
+ try {
899
+ validateRequired(options.title, "Title");
900
+ const parent = getTask(parentTaskId);
901
+ if (!parent) {
902
+ error(`Parent task not found: ${parentTaskId}`);
903
+ process.exit(1);
904
+ }
905
+ const subtask = createTask({
906
+ title: options.title,
907
+ description: options.description,
908
+ priority: parsePriority(options.priority),
909
+ status: parseStatus(options.status, "task"),
910
+ parentTaskId,
911
+ epicId: parent.epicId ?? undefined
912
+ });
913
+ if (isJsonMode()) {
914
+ output(subtask);
915
+ } else {
916
+ success(`Subtask created: ${subtask.id}`);
917
+ console.log(formatTask(subtask));
918
+ }
919
+ } catch (err) {
920
+ error(err instanceof Error ? err.message : String(err));
921
+ process.exit(1);
922
+ }
923
+ });
924
+ subtaskCommand.command("list <parent-task-id>").description("List all subtasks of a task").action((parentTaskId) => {
925
+ try {
926
+ const parent = getTask(parentTaskId);
927
+ if (!parent) {
928
+ error(`Parent task not found: ${parentTaskId}`);
929
+ process.exit(1);
930
+ }
931
+ const subtasks = listSubtasks(parentTaskId);
932
+ if (isJsonMode()) {
933
+ output(subtasks);
934
+ } else {
935
+ if (subtasks.length === 0) {
936
+ console.log(`No subtasks for ${parentTaskId}`);
937
+ } else {
938
+ console.log(`Subtasks of ${parentTaskId}:`);
939
+ console.log(formatTaskList(subtasks));
940
+ }
941
+ }
942
+ } catch (err) {
943
+ error(err instanceof Error ? err.message : String(err));
944
+ process.exit(1);
945
+ }
946
+ });
947
+ subtaskCommand.command("update <subtask-id>").description("Update a subtask").option("-t, --title <title>", "New title").option("-d, --description <description>", "New description").option("-p, --priority <priority>", "New priority (0-5)").option("-s, --status <status>", "New status").action((subtaskId, options) => {
948
+ try {
949
+ const subtask = getTask(subtaskId);
950
+ if (!subtask) {
951
+ error(`Subtask not found: ${subtaskId}`);
952
+ process.exit(1);
953
+ }
954
+ if (!subtask.parentTaskId) {
955
+ error(`${subtaskId} is not a subtask. Use 'trekker task update' instead.`);
956
+ process.exit(1);
957
+ }
958
+ const updateInput = {};
959
+ if (options.title !== undefined)
960
+ updateInput.title = options.title;
961
+ if (options.description !== undefined)
962
+ updateInput.description = options.description;
963
+ if (options.priority !== undefined)
964
+ updateInput.priority = parsePriority(options.priority);
965
+ if (options.status !== undefined) {
966
+ updateInput.status = parseStatus(options.status, "task");
967
+ }
968
+ const updated = updateTask(subtaskId, updateInput);
969
+ if (isJsonMode()) {
970
+ output(updated);
971
+ } else {
972
+ success(`Subtask updated: ${updated.id}`);
973
+ console.log(formatTask(updated));
974
+ }
975
+ } catch (err) {
976
+ error(err instanceof Error ? err.message : String(err));
977
+ process.exit(1);
978
+ }
979
+ });
980
+ subtaskCommand.command("delete <subtask-id>").description("Delete a subtask").action((subtaskId) => {
981
+ try {
982
+ const subtask = getTask(subtaskId);
983
+ if (!subtask) {
984
+ error(`Subtask not found: ${subtaskId}`);
985
+ process.exit(1);
986
+ }
987
+ if (!subtask.parentTaskId) {
988
+ error(`${subtaskId} is not a subtask. Use 'trekker task delete' instead.`);
989
+ process.exit(1);
990
+ }
991
+ deleteTask(subtaskId);
992
+ success(`Subtask deleted: ${subtaskId}`);
993
+ } catch (err) {
994
+ error(err instanceof Error ? err.message : String(err));
995
+ process.exit(1);
996
+ }
997
+ });
998
+
999
+ // src/commands/comment.ts
1000
+ import { Command as Command6 } from "commander";
1001
+
1002
+ // src/services/comment.ts
1003
+ import { eq as eq4 } from "drizzle-orm";
1004
+ function createComment(input) {
1005
+ const db = getDb();
1006
+ const task = db.select().from(tasks).where(eq4(tasks.id, input.taskId)).get();
1007
+ if (!task) {
1008
+ throw new Error(`Task not found: ${input.taskId}`);
1009
+ }
1010
+ const id = generateId("comment");
1011
+ const now = new Date;
1012
+ const comment = {
1013
+ id,
1014
+ taskId: input.taskId,
1015
+ author: input.author,
1016
+ content: input.content,
1017
+ createdAt: now,
1018
+ updatedAt: now
1019
+ };
1020
+ db.insert(comments).values(comment).run();
1021
+ return comment;
1022
+ }
1023
+ function getComment(id) {
1024
+ const db = getDb();
1025
+ const result = db.select().from(comments).where(eq4(comments.id, id)).get();
1026
+ return result;
1027
+ }
1028
+ function listComments(taskId) {
1029
+ const db = getDb();
1030
+ const task = db.select().from(tasks).where(eq4(tasks.id, taskId)).get();
1031
+ if (!task) {
1032
+ throw new Error(`Task not found: ${taskId}`);
1033
+ }
1034
+ return db.select().from(comments).where(eq4(comments.taskId, taskId)).all();
1035
+ }
1036
+ function updateComment(id, input) {
1037
+ const db = getDb();
1038
+ const existing = getComment(id);
1039
+ if (!existing) {
1040
+ throw new Error(`Comment not found: ${id}`);
1041
+ }
1042
+ db.update(comments).set({
1043
+ content: input.content,
1044
+ updatedAt: new Date
1045
+ }).where(eq4(comments.id, id)).run();
1046
+ return getComment(id);
1047
+ }
1048
+ function deleteComment(id) {
1049
+ const db = getDb();
1050
+ const existing = getComment(id);
1051
+ if (!existing) {
1052
+ throw new Error(`Comment not found: ${id}`);
1053
+ }
1054
+ db.delete(comments).where(eq4(comments.id, id)).run();
1055
+ }
1056
+
1057
+ // src/commands/comment.ts
1058
+ var commentCommand = new Command6("comment").description("Manage comments");
1059
+ commentCommand.command("add <task-id>").description("Add a comment to a task").requiredOption("-a, --author <author>", "Comment author").requiredOption("-c, --content <content>", "Comment content").action((taskId, options) => {
1060
+ try {
1061
+ validateRequired(options.author, "Author");
1062
+ validateRequired(options.content, "Content");
1063
+ const comment = createComment({
1064
+ taskId,
1065
+ author: options.author,
1066
+ content: options.content
1067
+ });
1068
+ if (isJsonMode()) {
1069
+ output(comment);
1070
+ } else {
1071
+ success(`Comment added: ${comment.id}`);
1072
+ console.log(formatComment(comment));
1073
+ }
1074
+ } catch (err) {
1075
+ error(err instanceof Error ? err.message : String(err));
1076
+ process.exit(1);
1077
+ }
1078
+ });
1079
+ commentCommand.command("list <task-id>").description("List all comments on a task").action((taskId) => {
1080
+ try {
1081
+ const comments2 = listComments(taskId);
1082
+ if (isJsonMode()) {
1083
+ output(comments2);
1084
+ } else {
1085
+ if (comments2.length === 0) {
1086
+ console.log(`No comments on ${taskId}`);
1087
+ } else {
1088
+ console.log(`Comments on ${taskId}:`);
1089
+ console.log(formatCommentList(comments2));
1090
+ }
1091
+ }
1092
+ } catch (err) {
1093
+ error(err instanceof Error ? err.message : String(err));
1094
+ process.exit(1);
1095
+ }
1096
+ });
1097
+ commentCommand.command("update <comment-id>").description("Update a comment").requiredOption("-c, --content <content>", "New comment content").action((commentId, options) => {
1098
+ try {
1099
+ validateRequired(options.content, "Content");
1100
+ const comment = updateComment(commentId, {
1101
+ content: options.content
1102
+ });
1103
+ if (isJsonMode()) {
1104
+ output(comment);
1105
+ } else {
1106
+ success(`Comment updated: ${comment.id}`);
1107
+ console.log(formatComment(comment));
1108
+ }
1109
+ } catch (err) {
1110
+ error(err instanceof Error ? err.message : String(err));
1111
+ process.exit(1);
1112
+ }
1113
+ });
1114
+ commentCommand.command("delete <comment-id>").description("Delete a comment").action((commentId) => {
1115
+ try {
1116
+ deleteComment(commentId);
1117
+ success(`Comment deleted: ${commentId}`);
1118
+ } catch (err) {
1119
+ error(err instanceof Error ? err.message : String(err));
1120
+ process.exit(1);
1121
+ }
1122
+ });
1123
+
1124
+ // src/commands/dep.ts
1125
+ import { Command as Command7 } from "commander";
1126
+
1127
+ // src/services/dependency.ts
1128
+ import { eq as eq5 } from "drizzle-orm";
1129
+ function addDependency(taskId, dependsOnId) {
1130
+ const db = getDb();
1131
+ const task = db.select().from(tasks).where(eq5(tasks.id, taskId)).get();
1132
+ if (!task) {
1133
+ throw new Error(`Task not found: ${taskId}`);
1134
+ }
1135
+ const dependsOnTask = db.select().from(tasks).where(eq5(tasks.id, dependsOnId)).get();
1136
+ if (!dependsOnTask) {
1137
+ throw new Error(`Task not found: ${dependsOnId}`);
1138
+ }
1139
+ if (taskId === dependsOnId) {
1140
+ throw new Error("A task cannot depend on itself.");
1141
+ }
1142
+ const existing = db.select().from(dependencies).where(eq5(dependencies.taskId, taskId)).all().find((d) => d.dependsOnId === dependsOnId);
1143
+ if (existing) {
1144
+ throw new Error(`Dependency already exists: ${taskId} \u2192 ${dependsOnId}`);
1145
+ }
1146
+ if (wouldCreateCycle(taskId, dependsOnId)) {
1147
+ throw new Error(`Adding this dependency would create a cycle. ${dependsOnId} already depends on ${taskId} (directly or transitively).`);
1148
+ }
1149
+ const id = generateUuid();
1150
+ const now = new Date;
1151
+ const dependency = {
1152
+ id,
1153
+ taskId,
1154
+ dependsOnId,
1155
+ createdAt: now
1156
+ };
1157
+ db.insert(dependencies).values(dependency).run();
1158
+ return dependency;
1159
+ }
1160
+ function removeDependency(taskId, dependsOnId) {
1161
+ const db = getDb();
1162
+ const existing = db.select().from(dependencies).where(eq5(dependencies.taskId, taskId)).all().find((d) => d.dependsOnId === dependsOnId);
1163
+ if (!existing) {
1164
+ throw new Error(`Dependency not found: ${taskId} \u2192 ${dependsOnId}`);
1165
+ }
1166
+ db.delete(dependencies).where(eq5(dependencies.id, existing.id)).run();
1167
+ }
1168
+ function getDependencies(taskId) {
1169
+ const db = getDb();
1170
+ const dependsOn = db.select({
1171
+ taskId: dependencies.taskId,
1172
+ dependsOnId: dependencies.dependsOnId
1173
+ }).from(dependencies).where(eq5(dependencies.taskId, taskId)).all();
1174
+ const blocks = db.select({
1175
+ taskId: dependencies.taskId,
1176
+ dependsOnId: dependencies.dependsOnId
1177
+ }).from(dependencies).where(eq5(dependencies.dependsOnId, taskId)).all();
1178
+ return { dependsOn, blocks };
1179
+ }
1180
+ function wouldCreateCycle(taskId, dependsOnId) {
1181
+ const db = getDb();
1182
+ const visited = new Set;
1183
+ const stack = [dependsOnId];
1184
+ while (stack.length > 0) {
1185
+ const current = stack.pop();
1186
+ if (current === taskId) {
1187
+ return true;
1188
+ }
1189
+ if (visited.has(current)) {
1190
+ continue;
1191
+ }
1192
+ visited.add(current);
1193
+ const deps = db.select({ dependsOnId: dependencies.dependsOnId }).from(dependencies).where(eq5(dependencies.taskId, current)).all();
1194
+ for (const dep of deps) {
1195
+ if (!visited.has(dep.dependsOnId)) {
1196
+ stack.push(dep.dependsOnId);
1197
+ }
1198
+ }
1199
+ }
1200
+ return false;
1201
+ }
1202
+
1203
+ // src/commands/dep.ts
1204
+ var depCommand = new Command7("dep").description("Manage task dependencies");
1205
+ depCommand.command("add <task-id> <depends-on-id>").description("Add a dependency (task-id depends on depends-on-id)").action((taskId, dependsOnId) => {
1206
+ try {
1207
+ const dependency = addDependency(taskId, dependsOnId);
1208
+ if (isJsonMode()) {
1209
+ output(dependency);
1210
+ } else {
1211
+ success(`Dependency added: ${taskId} \u2192 depends on ${dependsOnId}`);
1212
+ }
1213
+ } catch (err) {
1214
+ error(err instanceof Error ? err.message : String(err));
1215
+ process.exit(1);
1216
+ }
1217
+ });
1218
+ depCommand.command("remove <task-id> <depends-on-id>").description("Remove a dependency").action((taskId, dependsOnId) => {
1219
+ try {
1220
+ removeDependency(taskId, dependsOnId);
1221
+ success(`Dependency removed: ${taskId} \u2192 ${dependsOnId}`);
1222
+ } catch (err) {
1223
+ error(err instanceof Error ? err.message : String(err));
1224
+ process.exit(1);
1225
+ }
1226
+ });
1227
+ depCommand.command("list <task-id>").description("List dependencies for a task").action((taskId) => {
1228
+ try {
1229
+ const { dependsOn, blocks } = getDependencies(taskId);
1230
+ if (isJsonMode()) {
1231
+ output({ taskId, dependsOn, blocks });
1232
+ } else {
1233
+ console.log(`Dependencies for ${taskId}:`);
1234
+ console.log(`
1235
+ Depends on:`);
1236
+ console.log(formatDependencyList(dependsOn, "depends_on"));
1237
+ console.log(`
1238
+ Blocks:`);
1239
+ console.log(formatDependencyList(blocks, "blocks"));
1240
+ }
1241
+ } catch (err) {
1242
+ error(err instanceof Error ? err.message : String(err));
1243
+ process.exit(1);
1244
+ }
1245
+ });
1246
+
1247
+ // src/commands/quickstart.ts
1248
+ import { Command as Command8 } from "commander";
1249
+ var QUICKSTART_TEXT = `# Trekker - AI Agent Quickstart Guide
1250
+
1251
+ Trekker is a CLI-based issue tracker designed for coding agents. It stores all data in a local SQLite database at \`.trekker/trekker.db\` in your project root.
1252
+
1253
+ ## Why Use Trekker?
1254
+
1255
+ As an AI agent, you should use Trekker to:
1256
+ - **Track your work** across multiple sessions and context windows
1257
+ - **Break down complex tasks** into manageable, atomic pieces
1258
+ - **Document decisions** and progress for future reference
1259
+ - **Manage dependencies** between tasks to ensure correct execution order
1260
+ - **Offload context** - store your reasoning, findings, and state externally so you can recover after context resets
1261
+ - **Persist memory** - comments survive context window limits and session boundaries
1262
+
1263
+ ## Best Practices for AI Agents
1264
+
1265
+ ### Creating Epics
1266
+ - Create one epic per **feature or major goal**
1267
+ - Use clear, descriptive titles that explain the outcome (e.g., "User Authentication System" not "Auth")
1268
+ - Write descriptions that capture the **why** and **scope** of the work
1269
+ - Example: \`trekker epic create -t "REST API for User Management" -d "Build CRUD endpoints for users with JWT auth, input validation, and rate limiting"\`
1270
+
1271
+ ### Creating Atomic Tasks
1272
+ - Each task should be **completable in one focused session**
1273
+ - Tasks should have a **single, clear objective**
1274
+ - If a task feels too big, break it into subtasks
1275
+ - Use action verbs: "Implement", "Add", "Fix", "Refactor", "Update"
1276
+ - Bad: \`"Work on authentication"\`
1277
+ - Good: \`"Implement JWT token generation endpoint"\`
1278
+
1279
+ ### Writing Good Descriptions
1280
+ - Explain **what** needs to be done and **how** to verify it's complete
1281
+ - Include relevant technical details (endpoints, file paths, function names)
1282
+ - Mention acceptance criteria when applicable
1283
+ - Example: \`-d "Create POST /api/auth/login that accepts {email, password}, validates credentials against DB, returns JWT token. Should return 401 for invalid credentials."\`
1284
+
1285
+ ### Using Tags Effectively
1286
+ - Use tags to categorize work: \`--tags "api,auth,security"\`
1287
+ - Common tag categories: component (\`api\`, \`ui\`, \`db\`), type (\`bug\`, \`feature\`, \`refactor\`), area (\`auth\`, \`payments\`)
1288
+
1289
+ ### Managing Dependencies
1290
+ - Always define dependencies when task order matters
1291
+ - A task should not start until its dependencies are complete
1292
+ - Use \`trekker dep list <task-id>\` to check what's blocking a task
1293
+
1294
+ ### Adding Comments (Critical for Context Management)
1295
+
1296
+ Comments are your **external memory**. Use them extensively to:
1297
+
1298
+ **Save Your Thought Process:**
1299
+ - Document your reasoning and analysis as you work
1300
+ - Record hypotheses before investigating them
1301
+ - Note alternatives you considered and why you chose/rejected them
1302
+
1303
+ **Offload Context:**
1304
+ - When your context window is filling up, dump your current state into comments
1305
+ - Record what you've tried, what worked, what didn't
1306
+ - Save partial progress so you can resume after a context reset
1307
+
1308
+ **Preserve Investigation Results:**
1309
+ - Store findings from code exploration
1310
+ - Document file locations and relevant code snippets
1311
+ - Record error messages and stack traces you're debugging
1312
+
1313
+ **Track Decision History:**
1314
+ - Log architectural decisions with rationale
1315
+ - Document trade-offs you evaluated
1316
+ - Record blockers and how you resolved them
1317
+
1318
+ **Examples:**
1319
+ \`\`\`bash
1320
+ # Starting a task - record your initial analysis
1321
+ trekker comment add TREK-1 -a "agent" -c "Initial analysis: Need to modify auth.ts (line 45-80) and add new endpoint in routes/api.ts. Dependencies: bcrypt, jsonwebtoken already installed."
1322
+
1323
+ # During investigation - save what you found
1324
+ trekker comment add TREK-1 -a "agent" -c "Found existing validation in utils/validate.ts:23. Can reuse validateEmail() and validatePassword(). Token generation should follow pattern in auth/jwt.ts."
1325
+
1326
+ # Recording a decision
1327
+ trekker comment add TREK-1 -a "agent" -c "Decision: Using bcrypt over argon2 for password hashing. Rationale: better library support, existing team familiarity, sufficient security for this use case."
1328
+
1329
+ # Saving progress before context reset
1330
+ trekker comment add TREK-1 -a "agent" -c "Progress checkpoint: Implemented login endpoint (auth.ts:45-120). TODO: Add rate limiting, write tests. Blocked by: Need to clarify password reset flow with user."
1331
+
1332
+ # After hitting an issue
1333
+ trekker comment add TREK-1 -a "agent" -c "Issue: JWT verification failing. Tried: 1) Checked secret key - correct, 2) Verified token format - valid, 3) Found issue - clock skew on server. Solution: Added 30s leeway to verification."
1334
+ \`\`\`
1335
+
1336
+ ---
1337
+
1338
+ ## Initialization
1339
+
1340
+ Before using Trekker, initialize it in your project directory:
1341
+
1342
+ \`\`\`bash
1343
+ trekker init # Creates .trekker/ directory with database
1344
+ \`\`\`
1345
+
1346
+ To remove all Trekker data:
1347
+
1348
+ \`\`\`bash
1349
+ trekker wipe # Prompts for confirmation
1350
+ trekker wipe -y # Skip confirmation
1351
+ \`\`\`
1352
+
1353
+ ## Global Options
1354
+
1355
+ | Option | Description |
1356
+ |-----------|--------------------------------------------|
1357
+ | \`--json\` | Output in JSON format (recommended for agents) |
1358
+ | \`--help\` | Show help for any command |
1359
+
1360
+ **Example:**
1361
+ \`\`\`bash
1362
+ trekker --json task list # Returns tasks as JSON array
1363
+ \`\`\`
1364
+
1365
+ ---
1366
+
1367
+ ## Epics
1368
+
1369
+ > High-level features or milestones
1370
+
1371
+ ### Create Epic
1372
+
1373
+ \`\`\`bash
1374
+ trekker epic create -t <title> [-d <description>] [-p <0-5>] [-s <status>]
1375
+ \`\`\`
1376
+
1377
+ | Option | Required | Description |
1378
+ |--------|----------|-------------|
1379
+ | \`-t, --title\` | Yes | Epic title |
1380
+ | \`-d, --description\` | No | Detailed description |
1381
+ | \`-p, --priority\` | No | 0=critical, 1=high, 2=medium (default), 3=low, 4=backlog, 5=someday |
1382
+ | \`-s, --status\` | No | todo (default), in_progress, completed, archived |
1383
+
1384
+ **Example:**
1385
+ \`\`\`bash
1386
+ trekker epic create -t "User Authentication" -d "Implement OAuth2 login" -p 1
1387
+ \`\`\`
1388
+
1389
+ ### List Epics
1390
+
1391
+ \`\`\`bash
1392
+ trekker epic list [--status <status>]
1393
+ \`\`\`
1394
+
1395
+ ### Show Epic
1396
+
1397
+ \`\`\`bash
1398
+ trekker epic show <epic-id>
1399
+ \`\`\`
1400
+
1401
+ ### Update Epic
1402
+
1403
+ \`\`\`bash
1404
+ trekker epic update <epic-id> [-t <title>] [-d <desc>] [-p <priority>] [-s <status>]
1405
+ \`\`\`
1406
+
1407
+ ### Delete Epic
1408
+
1409
+ \`\`\`bash
1410
+ trekker epic delete <epic-id>
1411
+ \`\`\`
1412
+
1413
+ ---
1414
+
1415
+ ## Tasks
1416
+
1417
+ > Work items that can be assigned to epics
1418
+
1419
+ ### Create Task
1420
+
1421
+ \`\`\`bash
1422
+ trekker task create -t <title> [-d <description>] [-p <0-5>] [-s <status>] [--tags <tags>] [-e <epic-id>]
1423
+ \`\`\`
1424
+
1425
+ | Option | Required | Description |
1426
+ |--------|----------|-------------|
1427
+ | \`-t, --title\` | Yes | Task title |
1428
+ | \`-d, --description\` | No | Detailed description |
1429
+ | \`-p, --priority\` | No | 0-5, default: 2 |
1430
+ | \`-s, --status\` | No | todo (default), in_progress, completed, wont_fix, archived |
1431
+ | \`--tags\` | No | Comma-separated tags, e.g., "api,auth,backend" |
1432
+ | \`-e, --epic\` | No | Epic ID to assign task to |
1433
+
1434
+ **Example:**
1435
+ \`\`\`bash
1436
+ trekker task create -t "Implement login API" -d "POST /api/login endpoint" -e EPIC-1 --tags "api,auth"
1437
+ \`\`\`
1438
+
1439
+ ### List Tasks
1440
+
1441
+ \`\`\`bash
1442
+ trekker task list [--status <status>] [--epic <epic-id>]
1443
+ \`\`\`
1444
+
1445
+ **Examples:**
1446
+ \`\`\`bash
1447
+ trekker task list # All top-level tasks
1448
+ trekker task list --status todo # Filter by status
1449
+ trekker task list --epic EPIC-1 # Filter by epic
1450
+ \`\`\`
1451
+
1452
+ ### Show Task
1453
+
1454
+ \`\`\`bash
1455
+ trekker task show <task-id>
1456
+ trekker --json task show TREK-1 # Get full task details as JSON
1457
+ \`\`\`
1458
+
1459
+ ### Update Task
1460
+
1461
+ \`\`\`bash
1462
+ trekker task update <task-id> [-t <title>] [-d <desc>] [-p <priority>] [-s <status>] [--tags <tags>] [-e <epic-id>] [--no-epic]
1463
+ \`\`\`
1464
+
1465
+ **Examples:**
1466
+ \`\`\`bash
1467
+ trekker task update TREK-1 -s in_progress
1468
+ trekker task update TREK-1 --no-epic # Remove from epic
1469
+ \`\`\`
1470
+
1471
+ ### Delete Task
1472
+
1473
+ \`\`\`bash
1474
+ trekker task delete <task-id>
1475
+ \`\`\`
1476
+
1477
+ ---
1478
+
1479
+ ## Subtasks
1480
+
1481
+ > Child tasks that belong to a parent task. They inherit the epic from their parent.
1482
+
1483
+ ### Create Subtask
1484
+
1485
+ \`\`\`bash
1486
+ trekker subtask create <parent-task-id> -t <title> [-d <description>] [-p <0-5>] [-s <status>]
1487
+ \`\`\`
1488
+
1489
+ **Example:**
1490
+ \`\`\`bash
1491
+ trekker subtask create TREK-1 -t "Add input validation"
1492
+ \`\`\`
1493
+
1494
+ ### List Subtasks
1495
+
1496
+ \`\`\`bash
1497
+ trekker subtask list <parent-task-id>
1498
+ \`\`\`
1499
+
1500
+ ### Update Subtask
1501
+
1502
+ \`\`\`bash
1503
+ trekker subtask update <subtask-id> [-t <title>] [-d <desc>] [-p <priority>] [-s <status>]
1504
+ \`\`\`
1505
+
1506
+ ### Delete Subtask
1507
+
1508
+ \`\`\`bash
1509
+ trekker subtask delete <subtask-id>
1510
+ \`\`\`
1511
+
1512
+ ---
1513
+
1514
+ ## Comments
1515
+
1516
+ > Your external memory - use extensively to preserve context and reasoning
1517
+
1518
+ Comments are **critical for AI agents**. They persist beyond your context window and session boundaries. Use them to:
1519
+ - Store your analysis and reasoning
1520
+ - Save investigation results
1521
+ - Record decisions with rationale
1522
+ - Checkpoint progress before context resets
1523
+ - Document blockers and solutions
1524
+
1525
+ ### Add Comment
1526
+
1527
+ \`\`\`bash
1528
+ trekker comment add <task-id> -a <author> -c <content>
1529
+ \`\`\`
1530
+
1531
+ | Option | Required | Description |
1532
+ |--------|----------|-------------|
1533
+ | \`-a, --author\` | Yes | Comment author name (use "agent" for AI) |
1534
+ | \`-c, --content\` | Yes | Comment text (can be multi-line) |
1535
+
1536
+ **Examples:**
1537
+ \`\`\`bash
1538
+ # Record analysis
1539
+ trekker comment add TREK-1 -a "agent" -c "Analyzed codebase: auth logic in src/auth/, uses JWT stored in httpOnly cookies"
1540
+
1541
+ # Save progress checkpoint
1542
+ trekker comment add TREK-1 -a "agent" -c "Checkpoint: Completed steps 1-3. Next: implement validation. Files modified: auth.ts, routes.ts"
1543
+
1544
+ # Document a blocker
1545
+ trekker comment add TREK-1 -a "agent" -c "BLOCKED: Need clarification on password requirements. Asked user, waiting for response."
1546
+ \`\`\`
1547
+
1548
+ ### List Comments
1549
+
1550
+ \`\`\`bash
1551
+ trekker comment list <task-id>
1552
+ trekker --json comment list <task-id> # Get as JSON for parsing
1553
+ \`\`\`
1554
+
1555
+ **Pro tip:** Always read comments when resuming work on a task - they contain your previous context!
1556
+
1557
+ ### Update Comment
1558
+
1559
+ \`\`\`bash
1560
+ trekker comment update <comment-id> -c <new-content>
1561
+ \`\`\`
1562
+
1563
+ ### Delete Comment
1564
+
1565
+ \`\`\`bash
1566
+ trekker comment delete <comment-id>
1567
+ \`\`\`
1568
+
1569
+ ---
1570
+
1571
+ ## Dependencies
1572
+
1573
+ > Task relationships - which tasks must be completed before others can start.
1574
+ > Trekker automatically detects and prevents circular dependencies.
1575
+
1576
+ ### Add Dependency
1577
+
1578
+ \`\`\`bash
1579
+ trekker dep add <task-id> <depends-on-id>
1580
+ \`\`\`
1581
+
1582
+ This means:
1583
+ - \`<task-id>\` depends on \`<depends-on-id>\`
1584
+ - \`<task-id>\` cannot start until \`<depends-on-id>\` is done
1585
+
1586
+ **Example:**
1587
+ \`\`\`bash
1588
+ trekker dep add TREK-2 TREK-1 # TREK-2 depends on TREK-1
1589
+ \`\`\`
1590
+
1591
+ ### Remove Dependency
1592
+
1593
+ \`\`\`bash
1594
+ trekker dep remove <task-id> <depends-on-id>
1595
+ \`\`\`
1596
+
1597
+ ### List Dependencies
1598
+
1599
+ \`\`\`bash
1600
+ trekker dep list <task-id>
1601
+ \`\`\`
1602
+
1603
+ Shows both:
1604
+ - What this task depends on (blockers)
1605
+ - What tasks this task blocks
1606
+
1607
+ ---
1608
+
1609
+ ## Web Interface
1610
+
1611
+ Trekker includes a web interface for visual task management.
1612
+
1613
+ ### Start the Web Interface
1614
+
1615
+ \`\`\`bash
1616
+ trekker serve # Start on port 3000
1617
+ trekker serve -p 8080 # Start on custom port
1618
+ \`\`\`
1619
+
1620
+ The web interface provides:
1621
+ - Kanban board with tasks grouped by status (TODO, In Progress, Completed)
1622
+ - Epic filter to focus on specific features
1623
+ - Task details including dependencies, subtasks, and tags
1624
+ - Auto-refresh every 5 seconds to reflect CLI changes
1625
+
1626
+ ---
1627
+
1628
+ ## Reference
1629
+
1630
+ ### ID Formats
1631
+
1632
+ | Type | Format | Example |
1633
+ |------|--------|---------|
1634
+ | Epic | \`EPIC-n\` | EPIC-1, EPIC-2 |
1635
+ | Task/Subtask | \`TREK-n\` | TREK-1, TREK-42 |
1636
+ | Comment | \`CMT-n\` | CMT-1, CMT-5 |
1637
+
1638
+ IDs are auto-generated and sequential within each type.
1639
+
1640
+ ### Task Status Values
1641
+
1642
+ | Status | Description |
1643
+ |--------|-------------|
1644
+ | \`todo\` | Not started (default) |
1645
+ | \`in_progress\` | Currently being worked on |
1646
+ | \`completed\` | Finished successfully |
1647
+ | \`wont_fix\` | Decided not to implement |
1648
+ | \`archived\` | No longer relevant |
1649
+
1650
+ ### Epic Status Values
1651
+
1652
+ | Status | Description |
1653
+ |--------|-------------|
1654
+ | \`todo\` | Not started (default) |
1655
+ | \`in_progress\` | Work has begun |
1656
+ | \`completed\` | All tasks done |
1657
+ | \`archived\` | No longer relevant |
1658
+
1659
+ ### Priority Scale
1660
+
1661
+ | Value | Meaning |
1662
+ |-------|---------|
1663
+ | 0 | Critical (drop everything) |
1664
+ | 1 | High (do soon) |
1665
+ | 2 | Medium (default) |
1666
+ | 3 | Low (when time permits) |
1667
+ | 4 | Backlog (future consideration) |
1668
+ | 5 | Someday (nice to have) |
1669
+
1670
+ ---
1671
+
1672
+ ## Recommended Workflow for AI Agents
1673
+
1674
+ 1. **Initialize** (once per project):
1675
+ \`\`\`bash
1676
+ trekker init
1677
+ \`\`\`
1678
+
1679
+ 2. **Check existing state** (every session start):
1680
+ \`\`\`bash
1681
+ trekker --json task list --status in_progress # See what's active
1682
+ trekker --json comment list TREK-1 # Read your previous context
1683
+ \`\`\`
1684
+
1685
+ 3. **Create epic** for the feature you're working on:
1686
+ \`\`\`bash
1687
+ trekker epic create -t "Feature Name" -d "Description"
1688
+ \`\`\`
1689
+
1690
+ 4. **Create tasks** for each piece of work:
1691
+ \`\`\`bash
1692
+ trekker task create -t "Task name" -e EPIC-1
1693
+ \`\`\`
1694
+
1695
+ 5. **Add dependencies** if tasks have ordering requirements:
1696
+ \`\`\`bash
1697
+ trekker dep add TREK-2 TREK-1
1698
+ \`\`\`
1699
+
1700
+ 6. **Document your initial analysis** before starting work:
1701
+ \`\`\`bash
1702
+ trekker comment add TREK-1 -a "agent" -c "Analysis: Need to modify X, Y, Z. Approach: ..."
1703
+ \`\`\`
1704
+
1705
+ 7. **Update status** as you work:
1706
+ \`\`\`bash
1707
+ trekker task update TREK-1 -s in_progress
1708
+ \`\`\`
1709
+
1710
+ 8. **Add comments frequently** - this is your external memory:
1711
+ \`\`\`bash
1712
+ # After investigating
1713
+ trekker comment add TREK-1 -a "agent" -c "Found: auth logic in src/auth.ts:45-80"
1714
+
1715
+ # After making a decision
1716
+ trekker comment add TREK-1 -a "agent" -c "Decision: Using approach X because Y"
1717
+
1718
+ # Before context might reset
1719
+ trekker comment add TREK-1 -a "agent" -c "Checkpoint: Completed A, B. Next: C, D"
1720
+ \`\`\`
1721
+
1722
+ 9. **Mark complete** when done:
1723
+ \`\`\`bash
1724
+ trekker task update TREK-1 -s completed
1725
+ trekker comment add TREK-1 -a "agent" -c "Completed. Summary: Implemented X in files A, B, C."
1726
+ \`\`\`
1727
+
1728
+ 10. **Use JSON output** for parsing:
1729
+ \`\`\`bash
1730
+ trekker --json task list
1731
+ trekker --json task show TREK-1
1732
+ \`\`\`
1733
+
1734
+ ---
1735
+
1736
+ ## Context Management Strategies
1737
+
1738
+ AI agents have limited context windows. Use Trekker to extend your effective memory:
1739
+
1740
+ ### Starting a New Session
1741
+
1742
+ Always begin by reading your previous state:
1743
+ \`\`\`bash
1744
+ # What was I working on?
1745
+ trekker --json task list --status in_progress
1746
+
1747
+ # What did I learn/decide?
1748
+ trekker --json comment list TREK-1
1749
+ \`\`\`
1750
+
1751
+ ### During Long Tasks
1752
+
1753
+ Periodically checkpoint your progress:
1754
+ \`\`\`bash
1755
+ trekker comment add TREK-1 -a "agent" -c "Progress: Steps 1-3 done. Current state: X. Next: Y. Blockers: Z."
1756
+ \`\`\`
1757
+
1758
+ ### Before Context Window Fills Up
1759
+
1760
+ When you notice context getting large, dump your current mental state:
1761
+ \`\`\`bash
1762
+ trekker comment add TREK-1 -a "agent" -c "Context dump:
1763
+ - Working on: implementing login validation
1764
+ - Files involved: auth.ts (modified lines 45-80), routes.ts (new endpoint at line 120)
1765
+ - Current approach: using existing validateEmail() from utils
1766
+ - Remaining work: add rate limiting, write tests
1767
+ - Open questions: unclear if we need refresh tokens"
1768
+ \`\`\`
1769
+
1770
+ ### After Solving a Problem
1771
+
1772
+ Document the solution so future-you doesn't repeat the investigation:
1773
+ \`\`\`bash
1774
+ trekker comment add TREK-1 -a "agent" -c "Solved: JWT verification failing. Root cause: clock skew. Fix: added 30s leeway in verify(). See auth.ts:67."
1775
+ \`\`\`
1776
+
1777
+ ### When Blocked
1778
+
1779
+ Record what you're waiting for:
1780
+ \`\`\`bash
1781
+ trekker comment add TREK-1 -a "agent" -c "BLOCKED: Need user input on password complexity requirements. Asked in conversation. Current assumption: min 8 chars, 1 number."
1782
+ \`\`\`
1783
+
1784
+ ---
1785
+
1786
+ ## Common Scenarios
1787
+
1788
+ ### Start a new feature
1789
+
1790
+ \`\`\`bash
1791
+ trekker epic create -t "API Rate Limiting" -d "Implement rate limiting for all endpoints" -p 1
1792
+ trekker task create -t "Design rate limit algorithm" -e EPIC-1
1793
+ trekker task create -t "Implement Redis counter" -e EPIC-1
1794
+ trekker task create -t "Add middleware" -e EPIC-1
1795
+ trekker dep add TREK-3 TREK-2 # Middleware depends on Redis counter
1796
+ trekker dep add TREK-2 TREK-1 # Redis counter depends on design
1797
+ \`\`\`
1798
+
1799
+ ### Check what's ready to work on
1800
+
1801
+ \`\`\`bash
1802
+ trekker --json task list --status todo
1803
+ \`\`\`
1804
+
1805
+ ### Get all details about a task
1806
+
1807
+ \`\`\`bash
1808
+ trekker --json task show TREK-1
1809
+ \`\`\`
1810
+
1811
+ ### Log progress
1812
+
1813
+ \`\`\`bash
1814
+ trekker task update TREK-1 -s in_progress
1815
+ trekker comment add TREK-1 -a "agent" -c "Chose token bucket algorithm"
1816
+ trekker task update TREK-1 -s completed
1817
+ \`\`\`
1818
+
1819
+ ### Break down a complex task
1820
+
1821
+ \`\`\`bash
1822
+ trekker subtask create TREK-2 -t "Set up Redis connection"
1823
+ trekker subtask create TREK-2 -t "Implement increment logic"
1824
+ trekker subtask create TREK-2 -t "Add TTL handling"
1825
+ \`\`\`
1826
+
1827
+ ### Resume work after context reset
1828
+
1829
+ \`\`\`bash
1830
+ # 1. Find what you were working on
1831
+ trekker --json task list --status in_progress
1832
+
1833
+ # 2. Read your previous comments to restore context
1834
+ trekker --json comment list TREK-1
1835
+
1836
+ # 3. Read task details for full picture
1837
+ trekker --json task show TREK-1
1838
+
1839
+ # 4. Continue work with restored context
1840
+ \`\`\`
1841
+
1842
+ ### Save context before stopping
1843
+
1844
+ \`\`\`bash
1845
+ # Dump everything you know before session ends
1846
+ trekker comment add TREK-1 -a "agent" -c "Session end checkpoint:
1847
+ - Completed: login endpoint, validation
1848
+ - In progress: rate limiting (50% done, see middleware.ts:30)
1849
+ - Files modified: auth.ts, routes.ts, middleware.ts
1850
+ - Next steps: finish rate limiter, add tests
1851
+ - Notes: user prefers 100 req/min limit"
1852
+ \`\`\`
1853
+ `;
1854
+ var quickstartCommand = new Command8("quickstart").description("Show comprehensive guide for AI agents").action(() => {
1855
+ console.log(QUICKSTART_TEXT);
1856
+ });
1857
+
1858
+ // src/commands/serve.ts
1859
+ import { Command as Command9 } from "commander";
1860
+ import { spawn, spawnSync } from "child_process";
1861
+ import { resolve, dirname } from "path";
1862
+ import { existsSync as existsSync2 } from "fs";
1863
+ function findWebappDir() {
1864
+ const scriptPath = import.meta.url.replace("file://", "");
1865
+ const scriptDir = dirname(scriptPath);
1866
+ const cliRoot = scriptDir.includes("/src/") ? dirname(dirname(dirname(scriptPath))) : dirname(dirname(scriptPath));
1867
+ const bundledWebapp = resolve(cliRoot, "webapp-dist");
1868
+ if (existsSync2(bundledWebapp)) {
1869
+ return { path: bundledWebapp, isBundled: true };
1870
+ }
1871
+ const packagesDir = dirname(cliRoot);
1872
+ const webappDir = resolve(packagesDir, "webapp");
1873
+ if (existsSync2(webappDir)) {
1874
+ return { path: webappDir, isBundled: false };
1875
+ }
1876
+ return null;
1877
+ }
1878
+ var serveCommand = new Command9("serve").description("Start the Trekker web interface").option("-p, --port <port>", "Port to run on", "3000").option("--dev", "Run in development mode").action(async (options) => {
1879
+ try {
1880
+ if (!isTrekkerInitialized()) {
1881
+ error("Trekker is not initialized. Run 'trekker init' first.");
1882
+ process.exit(1);
1883
+ }
1884
+ const dbPath = getDbPath();
1885
+ const port = options.port;
1886
+ const webapp = findWebappDir();
1887
+ if (!webapp) {
1888
+ error("Webapp not found. Please reinstall Trekker.");
1889
+ process.exit(1);
1890
+ }
1891
+ const { path: webappDir, isBundled } = webapp;
1892
+ const env = {
1893
+ ...process.env,
1894
+ TREKKER_DB_PATH: dbPath,
1895
+ PORT: port
1896
+ };
1897
+ if (isBundled) {
1898
+ success(`Starting Trekker web interface on http://localhost:${port}`);
1899
+ console.log(`Press Ctrl+C to stop
1900
+ `);
1901
+ const server2 = spawn("bun", ["run", "server.js"], {
1902
+ cwd: webappDir,
1903
+ stdio: "inherit",
1904
+ env
1905
+ });
1906
+ setupSignalHandlers(server2);
1907
+ return;
1908
+ }
1909
+ const nodeModulesPath = resolve(webappDir, "node_modules");
1910
+ if (!existsSync2(nodeModulesPath)) {
1911
+ console.log("Installing webapp dependencies...");
1912
+ const result = spawnSync("bun", ["install"], {
1913
+ cwd: webappDir,
1914
+ stdio: "inherit"
1915
+ });
1916
+ if (result.status !== 0) {
1917
+ error("Failed to install dependencies");
1918
+ process.exit(1);
1919
+ }
1920
+ }
1921
+ if (options.dev) {
1922
+ success(`Starting Trekker web interface (dev) on http://localhost:${port}`);
1923
+ console.log(`Press Ctrl+C to stop
1924
+ `);
1925
+ const dev = spawn("bun", ["run", "dev", "--", "-p", port], {
1926
+ cwd: webappDir,
1927
+ stdio: "inherit",
1928
+ env
1929
+ });
1930
+ setupSignalHandlers(dev);
1931
+ return;
1932
+ }
1933
+ const standalonePath = resolve(webappDir, ".next", "standalone");
1934
+ const buildMarker = resolve(webappDir, ".next", "BUILD_ID");
1935
+ if (!existsSync2(standalonePath) || !existsSync2(buildMarker)) {
1936
+ console.log("Building webapp...");
1937
+ const result = spawnSync("bun", ["run", "build"], {
1938
+ cwd: webappDir,
1939
+ stdio: "inherit",
1940
+ env
1941
+ });
1942
+ if (result.status !== 0) {
1943
+ error("Failed to build webapp");
1944
+ process.exit(1);
1945
+ }
1946
+ }
1947
+ const staticSrc = resolve(webappDir, ".next", "static");
1948
+ const staticDest = resolve(standalonePath, ".next", "static");
1949
+ if (existsSync2(staticSrc) && !existsSync2(staticDest)) {
1950
+ spawnSync("cp", ["-r", staticSrc, resolve(standalonePath, ".next")], {
1951
+ stdio: "inherit"
1952
+ });
1953
+ }
1954
+ const publicSrc = resolve(webappDir, "public");
1955
+ const publicDest = resolve(standalonePath, "public");
1956
+ if (existsSync2(publicSrc) && !existsSync2(publicDest)) {
1957
+ spawnSync("cp", ["-r", publicSrc, standalonePath], {
1958
+ stdio: "inherit"
1959
+ });
1960
+ }
1961
+ success(`Starting Trekker web interface on http://localhost:${port}`);
1962
+ console.log(`Press Ctrl+C to stop
1963
+ `);
1964
+ const server = spawn("bun", ["run", "server.js"], {
1965
+ cwd: standalonePath,
1966
+ stdio: "inherit",
1967
+ env
1968
+ });
1969
+ setupSignalHandlers(server);
1970
+ } catch (err) {
1971
+ error(err instanceof Error ? err.message : String(err));
1972
+ process.exit(1);
1973
+ }
1974
+ });
1975
+ function setupSignalHandlers(child) {
1976
+ child.on("error", (err) => {
1977
+ error(`Failed to start webapp: ${err.message}`);
1978
+ process.exit(1);
1979
+ });
1980
+ process.on("SIGINT", () => {
1981
+ child.kill("SIGINT");
1982
+ process.exit(0);
1983
+ });
1984
+ process.on("SIGTERM", () => {
1985
+ child.kill("SIGTERM");
1986
+ process.exit(0);
1987
+ });
1988
+ }
1989
+
1990
+ // src/commands/seed.ts
1991
+ import { Command as Command10 } from "commander";
1992
+ var SAMPLE_EPICS = [
1993
+ {
1994
+ title: "User Authentication",
1995
+ description: "Implement user authentication and authorization system",
1996
+ priority: 0,
1997
+ status: "in_progress"
1998
+ },
1999
+ {
2000
+ title: "Dashboard",
2001
+ description: "Build the main dashboard with analytics and metrics",
2002
+ priority: 1,
2003
+ status: "todo"
2004
+ },
2005
+ {
2006
+ title: "API Development",
2007
+ description: "Design and implement RESTful API endpoints",
2008
+ priority: 1,
2009
+ status: "in_progress"
2010
+ },
2011
+ {
2012
+ title: "Testing & QA",
2013
+ description: "Set up testing infrastructure and write tests",
2014
+ priority: 2,
2015
+ status: "todo"
2016
+ }
2017
+ ];
2018
+ var SAMPLE_TASKS = [
2019
+ {
2020
+ epicIndex: 0,
2021
+ title: "Set up OAuth 2.0 provider",
2022
+ description: "Configure OAuth 2.0 with Google and GitHub providers",
2023
+ priority: 0,
2024
+ status: "completed",
2025
+ tags: "backend,security"
2026
+ },
2027
+ {
2028
+ epicIndex: 0,
2029
+ title: "Implement JWT token handling",
2030
+ description: "Create JWT generation, validation, and refresh logic",
2031
+ priority: 1,
2032
+ status: "in_progress",
2033
+ tags: "backend,security"
2034
+ },
2035
+ {
2036
+ epicIndex: 0,
2037
+ title: "Build login page",
2038
+ description: "Create responsive login page with social login buttons",
2039
+ priority: 1,
2040
+ status: "todo",
2041
+ tags: "frontend,ui"
2042
+ },
2043
+ {
2044
+ epicIndex: 0,
2045
+ title: "Add password reset flow",
2046
+ description: "Implement forgot password and reset password functionality",
2047
+ priority: 2,
2048
+ status: "todo",
2049
+ tags: "backend,frontend"
2050
+ },
2051
+ {
2052
+ epicIndex: 1,
2053
+ title: "Design dashboard layout",
2054
+ description: "Create wireframes and mockups for the main dashboard",
2055
+ priority: 1,
2056
+ status: "completed",
2057
+ tags: "design,ui"
2058
+ },
2059
+ {
2060
+ epicIndex: 1,
2061
+ title: "Implement chart components",
2062
+ description: "Build reusable chart components using Chart.js",
2063
+ priority: 2,
2064
+ status: "in_progress",
2065
+ tags: "frontend,ui"
2066
+ },
2067
+ {
2068
+ epicIndex: 1,
2069
+ title: "Add real-time data updates",
2070
+ description: "Implement WebSocket connection for live dashboard updates",
2071
+ priority: 2,
2072
+ status: "todo",
2073
+ tags: "frontend,backend"
2074
+ },
2075
+ {
2076
+ epicIndex: 2,
2077
+ title: "Define API schema",
2078
+ description: "Document API endpoints using OpenAPI specification",
2079
+ priority: 1,
2080
+ status: "completed",
2081
+ tags: "backend,docs"
2082
+ },
2083
+ {
2084
+ epicIndex: 2,
2085
+ title: "Implement user endpoints",
2086
+ description: "Create CRUD endpoints for user management",
2087
+ priority: 1,
2088
+ status: "completed",
2089
+ tags: "backend"
2090
+ },
2091
+ {
2092
+ epicIndex: 2,
2093
+ title: "Add rate limiting",
2094
+ description: "Implement rate limiting middleware for API protection",
2095
+ priority: 2,
2096
+ status: "in_progress",
2097
+ tags: "backend,security"
2098
+ },
2099
+ {
2100
+ epicIndex: 2,
2101
+ title: "Set up API versioning",
2102
+ description: "Implement v1/v2 API versioning strategy",
2103
+ priority: 3,
2104
+ status: "todo",
2105
+ tags: "backend"
2106
+ },
2107
+ {
2108
+ epicIndex: 3,
2109
+ title: "Set up Jest testing framework",
2110
+ description: "Configure Jest with TypeScript support",
2111
+ priority: 1,
2112
+ status: "completed",
2113
+ tags: "testing,devops"
2114
+ },
2115
+ {
2116
+ epicIndex: 3,
2117
+ title: "Write unit tests for auth module",
2118
+ description: "Create comprehensive unit tests for authentication logic",
2119
+ priority: 2,
2120
+ status: "todo",
2121
+ tags: "testing"
2122
+ },
2123
+ {
2124
+ epicIndex: 3,
2125
+ title: "Set up E2E testing with Playwright",
2126
+ description: "Configure Playwright for end-to-end testing",
2127
+ priority: 3,
2128
+ status: "todo",
2129
+ tags: "testing,devops"
2130
+ },
2131
+ {
2132
+ epicIndex: null,
2133
+ title: "Update README documentation",
2134
+ description: "Add installation instructions and usage examples",
2135
+ priority: 3,
2136
+ status: "todo",
2137
+ tags: "docs"
2138
+ },
2139
+ {
2140
+ epicIndex: null,
2141
+ title: "Configure CI/CD pipeline",
2142
+ description: "Set up GitHub Actions for automated testing and deployment",
2143
+ priority: 2,
2144
+ status: "in_progress",
2145
+ tags: "devops"
2146
+ }
2147
+ ];
2148
+ var SAMPLE_SUBTASKS = [
2149
+ {
2150
+ parentIndex: 1,
2151
+ title: "Implement access token generation",
2152
+ status: "completed",
2153
+ priority: 1
2154
+ },
2155
+ {
2156
+ parentIndex: 1,
2157
+ title: "Implement refresh token logic",
2158
+ status: "in_progress",
2159
+ priority: 1
2160
+ },
2161
+ {
2162
+ parentIndex: 1,
2163
+ title: "Add token blacklisting",
2164
+ status: "todo",
2165
+ priority: 2
2166
+ },
2167
+ {
2168
+ parentIndex: 5,
2169
+ title: "Create bar chart component",
2170
+ status: "completed",
2171
+ priority: 2
2172
+ },
2173
+ {
2174
+ parentIndex: 5,
2175
+ title: "Create line chart component",
2176
+ status: "in_progress",
2177
+ priority: 2
2178
+ },
2179
+ {
2180
+ parentIndex: 5,
2181
+ title: "Create pie chart component",
2182
+ status: "todo",
2183
+ priority: 3
2184
+ }
2185
+ ];
2186
+ var SAMPLE_DEPENDENCIES = [
2187
+ [2, 1],
2188
+ [3, 1],
2189
+ [6, 5],
2190
+ [6, 4],
2191
+ [9, 8],
2192
+ [12, 11],
2193
+ [13, 11]
2194
+ ];
2195
+ var seedCommand = new Command10("seed").description("Seed the database with sample data (development only)").option("--force", "Skip confirmation prompt").action((options) => {
2196
+ try {
2197
+ if (!isTrekkerInitialized()) {
2198
+ error("Trekker is not initialized. Run 'trekker init' first.");
2199
+ process.exit(1);
2200
+ }
2201
+ if (!options.force) {
2202
+ info("This will create sample epics, tasks, and dependencies.");
2203
+ info(`Use --force to skip this confirmation.
2204
+ `);
2205
+ }
2206
+ const epicIds = [];
2207
+ const taskIds = [];
2208
+ info("Creating epics...");
2209
+ for (const epicData of SAMPLE_EPICS) {
2210
+ const epic = createEpic({
2211
+ title: epicData.title,
2212
+ description: epicData.description,
2213
+ priority: epicData.priority,
2214
+ status: epicData.status
2215
+ });
2216
+ epicIds.push(epic.id);
2217
+ info(` Created ${epic.id}: ${epic.title}`);
2218
+ }
2219
+ info(`
2220
+ Creating tasks...`);
2221
+ for (const taskData of SAMPLE_TASKS) {
2222
+ const task = createTask({
2223
+ title: taskData.title,
2224
+ description: taskData.description,
2225
+ priority: taskData.priority,
2226
+ status: taskData.status,
2227
+ tags: taskData.tags,
2228
+ epicId: taskData.epicIndex !== null ? epicIds[taskData.epicIndex] : undefined
2229
+ });
2230
+ taskIds.push(task.id);
2231
+ info(` Created ${task.id}: ${task.title}`);
2232
+ }
2233
+ info(`
2234
+ Creating subtasks...`);
2235
+ for (const subtaskData of SAMPLE_SUBTASKS) {
2236
+ const subtask = createTask({
2237
+ title: subtaskData.title,
2238
+ priority: subtaskData.priority,
2239
+ status: subtaskData.status,
2240
+ parentTaskId: taskIds[subtaskData.parentIndex]
2241
+ });
2242
+ info(` Created ${subtask.id}: ${subtask.title} (subtask of ${taskIds[subtaskData.parentIndex]})`);
2243
+ }
2244
+ info(`
2245
+ Creating dependencies...`);
2246
+ for (const [taskIndex, dependsOnIndex] of SAMPLE_DEPENDENCIES) {
2247
+ const taskId = taskIds[taskIndex];
2248
+ const dependsOnId = taskIds[dependsOnIndex];
2249
+ addDependency(taskId, dependsOnId);
2250
+ info(` ${taskId} depends on ${dependsOnId}`);
2251
+ }
2252
+ success(`
2253
+ Seed complete! Created ${epicIds.length} epics, ${taskIds.length} tasks, ${SAMPLE_SUBTASKS.length} subtasks, and ${SAMPLE_DEPENDENCIES.length} dependencies.`);
2254
+ } catch (err) {
2255
+ error(err instanceof Error ? err.message : String(err));
2256
+ process.exit(1);
2257
+ }
2258
+ });
2259
+
2260
+ // src/index.ts
2261
+ var program = new Command11;
2262
+ program.name("trekker").description("CLI-based issue tracker for coding agents").version("0.1.0").option("--json", "Output in JSON format").hook("preAction", (thisCommand) => {
2263
+ const opts = thisCommand.opts();
2264
+ if (opts.json) {
2265
+ setJsonMode(true);
2266
+ }
2267
+ });
2268
+ program.addCommand(initCommand);
2269
+ program.addCommand(wipeCommand);
2270
+ program.addCommand(epicCommand);
2271
+ program.addCommand(taskCommand);
2272
+ program.addCommand(subtaskCommand);
2273
+ program.addCommand(commentCommand);
2274
+ program.addCommand(depCommand);
2275
+ program.addCommand(quickstartCommand);
2276
+ program.addCommand(serveCommand);
2277
+ program.addCommand(seedCommand);
2278
+ program.parse();