@trail-pm/cli 0.1.5 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib.d.ts ADDED
@@ -0,0 +1,233 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Walks upward from `startDir` looking for a Trail project root: a directory
5
+ * that contains `.trail/config.json`.
6
+ *
7
+ * @returns The **project root** directory (the parent of the `.trail` folder),
8
+ * or `null` if none is found within the walk limit. This is not the path to
9
+ * `.trail` itself — use {@link trailPaths} for `.trail`-relative paths.
10
+ */
11
+ declare function findTrailRoot(startDir: string): string | null;
12
+ interface TrailPaths {
13
+ root: string;
14
+ trailDir: string;
15
+ tasksDir: string;
16
+ configPath: string;
17
+ snapshotPath: string;
18
+ gitignorePath: string;
19
+ }
20
+ /** Resolved paths under a Trail project root (the directory that contains `.trail`). */
21
+ declare function trailPaths(root: string): TrailPaths;
22
+
23
+ declare const TaskSchema: z.ZodObject<{
24
+ id: z.ZodString;
25
+ title: z.ZodString;
26
+ description: z.ZodOptional<z.ZodString>;
27
+ status: z.ZodEnum<["draft", "todo", "in_progress", "in_review", "done", "cancelled"]>;
28
+ priority: z.ZodOptional<z.ZodEnum<["p0", "p1", "p2", "p3"]>>;
29
+ type: z.ZodEnum<["feature", "bug", "chore", "epic"]>;
30
+ assignee: z.ZodOptional<z.ZodString>;
31
+ milestone: z.ZodOptional<z.ZodString>;
32
+ branch: z.ZodOptional<z.ZodString>;
33
+ labels: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
34
+ parent: z.ZodOptional<z.ZodNullable<z.ZodString>>;
35
+ depends_on: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
36
+ blocks: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
37
+ due_date: z.ZodOptional<z.ZodString>;
38
+ start_date: z.ZodOptional<z.ZodString>;
39
+ estimate: z.ZodOptional<z.ZodEnum<["xs", "sm", "md", "lg", "xl"]>>;
40
+ github: z.ZodOptional<z.ZodNullable<z.ZodObject<{
41
+ issue_number: z.ZodNumber;
42
+ synced_at: z.ZodString;
43
+ url: z.ZodString;
44
+ }, "strip", z.ZodTypeAny, {
45
+ issue_number: number;
46
+ synced_at: string;
47
+ url: string;
48
+ }, {
49
+ issue_number: number;
50
+ synced_at: string;
51
+ url: string;
52
+ }>>>;
53
+ refs: z.ZodDefault<z.ZodArray<z.ZodObject<{
54
+ type: z.ZodString;
55
+ path: z.ZodString;
56
+ }, "strict", z.ZodTypeAny, {
57
+ path: string;
58
+ type: string;
59
+ }, {
60
+ path: string;
61
+ type: string;
62
+ }>, "many">>;
63
+ ai: z.ZodOptional<z.ZodObject<{
64
+ summary: z.ZodOptional<z.ZodString>;
65
+ acceptance_criteria: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
66
+ implementation_context: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
67
+ test_strategy: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
68
+ constraints: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
69
+ }, "strict", z.ZodTypeAny, {
70
+ summary?: string | undefined;
71
+ acceptance_criteria?: string[] | undefined;
72
+ implementation_context?: string[] | undefined;
73
+ test_strategy?: string[] | undefined;
74
+ constraints?: string[] | undefined;
75
+ }, {
76
+ summary?: string | undefined;
77
+ acceptance_criteria?: string[] | undefined;
78
+ implementation_context?: string[] | undefined;
79
+ test_strategy?: string[] | undefined;
80
+ constraints?: string[] | undefined;
81
+ }>>;
82
+ created_at: z.ZodString;
83
+ updated_at: z.ZodString;
84
+ }, "strict", z.ZodTypeAny, {
85
+ status: "draft" | "todo" | "in_progress" | "in_review" | "done" | "cancelled";
86
+ type: "feature" | "bug" | "chore" | "epic";
87
+ id: string;
88
+ title: string;
89
+ labels: string[];
90
+ depends_on: string[];
91
+ blocks: string[];
92
+ refs: {
93
+ path: string;
94
+ type: string;
95
+ }[];
96
+ created_at: string;
97
+ updated_at: string;
98
+ description?: string | undefined;
99
+ priority?: "p0" | "p1" | "p2" | "p3" | undefined;
100
+ assignee?: string | undefined;
101
+ milestone?: string | undefined;
102
+ branch?: string | undefined;
103
+ parent?: string | null | undefined;
104
+ due_date?: string | undefined;
105
+ start_date?: string | undefined;
106
+ estimate?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
107
+ github?: {
108
+ issue_number: number;
109
+ synced_at: string;
110
+ url: string;
111
+ } | null | undefined;
112
+ ai?: {
113
+ summary?: string | undefined;
114
+ acceptance_criteria?: string[] | undefined;
115
+ implementation_context?: string[] | undefined;
116
+ test_strategy?: string[] | undefined;
117
+ constraints?: string[] | undefined;
118
+ } | undefined;
119
+ }, {
120
+ status: "draft" | "todo" | "in_progress" | "in_review" | "done" | "cancelled";
121
+ type: "feature" | "bug" | "chore" | "epic";
122
+ id: string;
123
+ title: string;
124
+ created_at: string;
125
+ updated_at: string;
126
+ description?: string | undefined;
127
+ priority?: "p0" | "p1" | "p2" | "p3" | undefined;
128
+ assignee?: string | undefined;
129
+ milestone?: string | undefined;
130
+ branch?: string | undefined;
131
+ labels?: string[] | undefined;
132
+ parent?: string | null | undefined;
133
+ depends_on?: string[] | undefined;
134
+ blocks?: string[] | undefined;
135
+ due_date?: string | undefined;
136
+ start_date?: string | undefined;
137
+ estimate?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
138
+ github?: {
139
+ issue_number: number;
140
+ synced_at: string;
141
+ url: string;
142
+ } | null | undefined;
143
+ refs?: {
144
+ path: string;
145
+ type: string;
146
+ }[] | undefined;
147
+ ai?: {
148
+ summary?: string | undefined;
149
+ acceptance_criteria?: string[] | undefined;
150
+ implementation_context?: string[] | undefined;
151
+ test_strategy?: string[] | undefined;
152
+ constraints?: string[] | undefined;
153
+ } | undefined;
154
+ }>;
155
+ type Task = z.infer<typeof TaskSchema>;
156
+
157
+ declare function writeTaskFile(filePath: string, task: Task): void;
158
+ /**
159
+ * Loads all task JSON files from `tasksDir`. Returns an empty array if the directory is missing.
160
+ * Stops on the first file that fails to parse or validate.
161
+ */
162
+ declare function loadAllTasks(tasksDir: string): Task[];
163
+ /**
164
+ * Resolves the task file for `id`: prefers `${id}.json` when it exists and its `id` matches;
165
+ * otherwise scans `*.json` for a task whose `id` field equals `id`.
166
+ */
167
+ declare function findTaskFileById(tasksDir: string, id: string): {
168
+ filePath: string;
169
+ task: Task;
170
+ } | null;
171
+
172
+ /** Recompiles `.trail/snapshot.json` from all task files. */
173
+ declare function rebuildSnapshot(paths: TrailPaths, now?: Date): void;
174
+
175
+ /** Stable draft task id prefix + random suffix (e.g. `draft-a1b2c3d4`). */
176
+ declare function generateDraftId(): string;
177
+
178
+ declare const TrailConfigSchema: z.ZodObject<{
179
+ github: z.ZodObject<{
180
+ owner: z.ZodString;
181
+ repo: z.ZodString;
182
+ }, "strict", z.ZodTypeAny, {
183
+ owner: string;
184
+ repo: string;
185
+ }, {
186
+ owner: string;
187
+ repo: string;
188
+ }>;
189
+ sync: z.ZodObject<{
190
+ preset: z.ZodEnum<["collaborative", "solo", "offline"]>;
191
+ auto_sync_on_command: z.ZodBoolean;
192
+ ui_poll_interval_seconds: z.ZodNumber;
193
+ ui_idle_backoff: z.ZodBoolean;
194
+ }, "strict", z.ZodTypeAny, {
195
+ preset: "collaborative" | "solo" | "offline";
196
+ auto_sync_on_command: boolean;
197
+ ui_poll_interval_seconds: number;
198
+ ui_idle_backoff: boolean;
199
+ }, {
200
+ preset: "collaborative" | "solo" | "offline";
201
+ auto_sync_on_command: boolean;
202
+ ui_poll_interval_seconds: number;
203
+ ui_idle_backoff: boolean;
204
+ }>;
205
+ /** Last successful full sync; useful for future `trail status` and similar. */
206
+ last_full_sync_at: z.ZodOptional<z.ZodString>;
207
+ }, "strict", z.ZodTypeAny, {
208
+ github: {
209
+ owner: string;
210
+ repo: string;
211
+ };
212
+ sync: {
213
+ preset: "collaborative" | "solo" | "offline";
214
+ auto_sync_on_command: boolean;
215
+ ui_poll_interval_seconds: number;
216
+ ui_idle_backoff: boolean;
217
+ };
218
+ last_full_sync_at?: string | undefined;
219
+ }, {
220
+ github: {
221
+ owner: string;
222
+ repo: string;
223
+ };
224
+ sync: {
225
+ preset: "collaborative" | "solo" | "offline";
226
+ auto_sync_on_command: boolean;
227
+ ui_poll_interval_seconds: number;
228
+ ui_idle_backoff: boolean;
229
+ };
230
+ last_full_sync_at?: string | undefined;
231
+ }>;
232
+
233
+ export { type Task, TaskSchema, TrailConfigSchema, type TrailPaths, findTaskFileById, findTrailRoot, generateDraftId, loadAllTasks, rebuildSnapshot, trailPaths, writeTaskFile };
package/dist/lib.js ADDED
@@ -0,0 +1,314 @@
1
+ // src/core/paths.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ var MAX_TRAIL_ROOT_WALK = 20;
5
+ function findTrailRoot(startDir) {
6
+ let dir = path.resolve(startDir);
7
+ for (let i = 0; i < MAX_TRAIL_ROOT_WALK; i++) {
8
+ const configPath = path.join(dir, ".trail", "config.json");
9
+ if (fs.existsSync(configPath)) {
10
+ return dir;
11
+ }
12
+ const parent = path.dirname(dir);
13
+ if (parent === dir) {
14
+ break;
15
+ }
16
+ dir = parent;
17
+ }
18
+ return null;
19
+ }
20
+ function trailPaths(root) {
21
+ const trailDir = path.join(root, ".trail");
22
+ return {
23
+ root,
24
+ trailDir,
25
+ tasksDir: path.join(trailDir, "tasks"),
26
+ configPath: path.join(trailDir, "config.json"),
27
+ snapshotPath: path.join(trailDir, "snapshot.json"),
28
+ gitignorePath: path.join(trailDir, ".gitignore")
29
+ };
30
+ }
31
+
32
+ // src/core/task-store.ts
33
+ import fs2 from "fs";
34
+ import path2 from "path";
35
+
36
+ // src/schemas/task.ts
37
+ import { z } from "zod";
38
+ var TaskStatusSchema = z.enum([
39
+ "draft",
40
+ "todo",
41
+ "in_progress",
42
+ "in_review",
43
+ "done",
44
+ "cancelled"
45
+ ]);
46
+ var isoDateStringSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Expected ISO date string (YYYY-MM-DD)");
47
+ var TaskGitHubSchema = z.object({
48
+ issue_number: z.number().int(),
49
+ synced_at: z.string().datetime({ offset: true }),
50
+ url: z.string().url()
51
+ }).nullable();
52
+ var TaskAiSchema = z.object({
53
+ summary: z.string().optional(),
54
+ acceptance_criteria: z.array(z.string()).optional(),
55
+ implementation_context: z.array(z.string()).optional(),
56
+ test_strategy: z.array(z.string()).optional(),
57
+ constraints: z.array(z.string()).optional()
58
+ }).strict().optional();
59
+ var TaskSchema = z.object({
60
+ id: z.string(),
61
+ title: z.string(),
62
+ description: z.string().optional(),
63
+ status: TaskStatusSchema,
64
+ priority: z.enum(["p0", "p1", "p2", "p3"]).optional(),
65
+ type: z.enum(["feature", "bug", "chore", "epic"]),
66
+ assignee: z.string().optional(),
67
+ milestone: z.string().optional(),
68
+ branch: z.string().optional(),
69
+ labels: z.array(z.string()).default([]),
70
+ parent: z.string().nullable().optional(),
71
+ depends_on: z.array(z.string()).default([]),
72
+ blocks: z.array(z.string()).default([]),
73
+ due_date: isoDateStringSchema.optional(),
74
+ start_date: isoDateStringSchema.optional(),
75
+ estimate: z.enum(["xs", "sm", "md", "lg", "xl"]).optional(),
76
+ github: TaskGitHubSchema.optional(),
77
+ refs: z.array(
78
+ z.object({
79
+ type: z.string(),
80
+ path: z.string()
81
+ }).strict()
82
+ ).default([]),
83
+ ai: TaskAiSchema,
84
+ created_at: z.string().datetime({ offset: true }),
85
+ updated_at: z.string().datetime({ offset: true })
86
+ }).strict();
87
+
88
+ // src/core/task-store.ts
89
+ function toValidationError(zodError, context) {
90
+ const issues = zodError.issues.map(
91
+ (i) => `${i.path.length ? i.path.join(".") : "(root)"}: ${i.message}`
92
+ );
93
+ return {
94
+ code: "VALIDATION_FAILED",
95
+ message: context ? `Task validation failed (${context})` : "Task validation failed",
96
+ details: zodError.message,
97
+ issues
98
+ };
99
+ }
100
+ function throwValidationFailed(err) {
101
+ const e = new Error(`[VALIDATION_FAILED] ${err.message}`);
102
+ e.name = "TrailError";
103
+ e.trailError = err;
104
+ throw e;
105
+ }
106
+ function listTaskFiles(tasksDir) {
107
+ const names = fs2.readdirSync(tasksDir);
108
+ return names.filter(
109
+ (n) => n.endsWith(".json") && n !== "snapshot.json"
110
+ ).sort((a, b) => a.localeCompare(b));
111
+ }
112
+ function readTaskFile(filePath) {
113
+ let raw;
114
+ try {
115
+ raw = JSON.parse(fs2.readFileSync(filePath, "utf8"));
116
+ } catch (e) {
117
+ if (e instanceof SyntaxError) {
118
+ throwValidationFailed({
119
+ code: "VALIDATION_FAILED",
120
+ message: "Invalid JSON in task file",
121
+ details: filePath
122
+ });
123
+ }
124
+ throw e;
125
+ }
126
+ const parsed = TaskSchema.safeParse(raw);
127
+ if (!parsed.success) {
128
+ throwValidationFailed(toValidationError(parsed.error, filePath));
129
+ }
130
+ return parsed.data;
131
+ }
132
+ function writeTaskFile(filePath, task) {
133
+ const parsed = TaskSchema.safeParse(task);
134
+ if (!parsed.success) {
135
+ throwValidationFailed(toValidationError(parsed.error, filePath));
136
+ }
137
+ const dir = path2.dirname(filePath);
138
+ fs2.mkdirSync(dir, { recursive: true });
139
+ const body = `${JSON.stringify(parsed.data, null, 2)}
140
+ `;
141
+ fs2.writeFileSync(filePath, body, "utf8");
142
+ }
143
+ function loadAllTasks(tasksDir) {
144
+ if (!fs2.existsSync(tasksDir)) {
145
+ return [];
146
+ }
147
+ const files = listTaskFiles(tasksDir);
148
+ return files.map((name) => readTaskFile(path2.join(tasksDir, name)));
149
+ }
150
+ function findTaskFileById(tasksDir, id) {
151
+ if (!fs2.existsSync(tasksDir)) {
152
+ return null;
153
+ }
154
+ const direct = path2.join(tasksDir, `${id}.json`);
155
+ if (fs2.existsSync(direct)) {
156
+ const task = readTaskFile(direct);
157
+ if (task.id === id) {
158
+ return { filePath: direct, task };
159
+ }
160
+ }
161
+ for (const name of listTaskFiles(tasksDir)) {
162
+ const filePath = path2.join(tasksDir, name);
163
+ const task = readTaskFile(filePath);
164
+ if (task.id === id) {
165
+ return { filePath, task };
166
+ }
167
+ }
168
+ return null;
169
+ }
170
+
171
+ // src/core/compile-snapshot.ts
172
+ import fs3 from "fs";
173
+ import path3 from "path";
174
+
175
+ // src/schemas/snapshot.ts
176
+ import { z as z2 } from "zod";
177
+ var SnapshotSchema = z2.object({
178
+ generated_at: z2.string().datetime({ offset: true }),
179
+ tasks: z2.array(TaskSchema),
180
+ warnings: z2.array(
181
+ z2.object({
182
+ code: z2.string(),
183
+ message: z2.string(),
184
+ taskId: z2.string().optional()
185
+ }).strict()
186
+ )
187
+ }).strict();
188
+
189
+ // src/core/compile-snapshot.ts
190
+ var UNKNOWN_DEPENDENCY = "UNKNOWN_DEPENDENCY";
191
+ var DEPENDENCY_CYCLE = "DEPENDENCY_CYCLE";
192
+ function detectCycles(taskIds, deps) {
193
+ const cycles = [];
194
+ const visited = /* @__PURE__ */ new Set();
195
+ const visiting = /* @__PURE__ */ new Set();
196
+ const stack = [];
197
+ function recordCycle(fromIndex) {
198
+ cycles.push(stack.slice(fromIndex));
199
+ }
200
+ function dfs(u) {
201
+ visiting.add(u);
202
+ stack.push(u);
203
+ for (const v of deps.get(u) ?? []) {
204
+ if (!taskIds.has(v)) {
205
+ continue;
206
+ }
207
+ if (visiting.has(v)) {
208
+ const i = stack.indexOf(v);
209
+ if (i !== -1) {
210
+ recordCycle(i);
211
+ }
212
+ continue;
213
+ }
214
+ if (!visited.has(v)) {
215
+ dfs(v);
216
+ }
217
+ }
218
+ stack.pop();
219
+ visiting.delete(u);
220
+ visited.add(u);
221
+ }
222
+ for (const id of taskIds) {
223
+ if (!visited.has(id)) {
224
+ dfs(id);
225
+ }
226
+ }
227
+ return cycles;
228
+ }
229
+ function formatCycle(nodes) {
230
+ return nodes.join(" \u2192 ");
231
+ }
232
+ function compileSnapshot(tasks, now) {
233
+ const generatedAt = (now ?? /* @__PURE__ */ new Date()).toISOString();
234
+ const taskList = [...tasks];
235
+ const taskIds = new Set(taskList.map((t) => t.id));
236
+ const deps = /* @__PURE__ */ new Map();
237
+ for (const t of taskList) {
238
+ deps.set(t.id, t.depends_on ?? []);
239
+ }
240
+ const warnings = [];
241
+ for (const t of taskList) {
242
+ for (const depId of t.depends_on ?? []) {
243
+ if (!taskIds.has(depId)) {
244
+ warnings.push({
245
+ code: UNKNOWN_DEPENDENCY,
246
+ message: `Task "${t.id}" depends on unknown task id "${depId}"`,
247
+ taskId: t.id
248
+ });
249
+ }
250
+ }
251
+ }
252
+ for (const cycle of detectCycles(taskIds, deps)) {
253
+ warnings.push({
254
+ code: DEPENDENCY_CYCLE,
255
+ message: `Dependency cycle: ${formatCycle(cycle)}`,
256
+ taskId: cycle[0]
257
+ });
258
+ }
259
+ return {
260
+ generated_at: generatedAt,
261
+ tasks: taskList,
262
+ warnings
263
+ };
264
+ }
265
+ function writeSnapshot(snapshotPath, snapshot) {
266
+ const parsed = SnapshotSchema.parse(snapshot);
267
+ const dir = path3.dirname(snapshotPath);
268
+ fs3.mkdirSync(dir, { recursive: true });
269
+ const body = `${JSON.stringify(parsed, null, 2)}
270
+ `;
271
+ fs3.writeFileSync(snapshotPath, body, "utf8");
272
+ }
273
+
274
+ // src/core/rebuild-snapshot.ts
275
+ function rebuildSnapshot(paths, now = /* @__PURE__ */ new Date()) {
276
+ const tasks = loadAllTasks(paths.tasksDir);
277
+ const snapshot = compileSnapshot(tasks, now);
278
+ writeSnapshot(paths.snapshotPath, snapshot);
279
+ }
280
+
281
+ // src/core/draft-id.ts
282
+ import { randomBytes } from "crypto";
283
+ function generateDraftId() {
284
+ return `draft-${randomBytes(4).toString("hex")}`;
285
+ }
286
+
287
+ // src/schemas/config.ts
288
+ import { z as z3 } from "zod";
289
+ var TrailConfigSchema = z3.object({
290
+ github: z3.object({
291
+ owner: z3.string(),
292
+ repo: z3.string()
293
+ }).strict(),
294
+ sync: z3.object({
295
+ preset: z3.enum(["collaborative", "solo", "offline"]),
296
+ auto_sync_on_command: z3.boolean(),
297
+ ui_poll_interval_seconds: z3.number(),
298
+ ui_idle_backoff: z3.boolean()
299
+ }).strict(),
300
+ /** Last successful full sync; useful for future `trail status` and similar. */
301
+ last_full_sync_at: z3.string().datetime({ offset: true }).optional()
302
+ }).strict();
303
+ export {
304
+ TaskSchema,
305
+ TrailConfigSchema,
306
+ findTaskFileById,
307
+ findTrailRoot,
308
+ generateDraftId,
309
+ loadAllTasks,
310
+ rebuildSnapshot,
311
+ trailPaths,
312
+ writeTaskFile
313
+ };
314
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/paths.ts","../src/core/task-store.ts","../src/schemas/task.ts","../src/core/compile-snapshot.ts","../src/schemas/snapshot.ts","../src/core/rebuild-snapshot.ts","../src/core/draft-id.ts","../src/schemas/config.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\n\nconst MAX_TRAIL_ROOT_WALK = 20;\n\n/**\n * Walks upward from `startDir` looking for a Trail project root: a directory\n * that contains `.trail/config.json`.\n *\n * @returns The **project root** directory (the parent of the `.trail` folder),\n * or `null` if none is found within the walk limit. This is not the path to\n * `.trail` itself — use {@link trailPaths} for `.trail`-relative paths.\n */\nexport function findTrailRoot(startDir: string): string | null {\n let dir = path.resolve(startDir);\n for (let i = 0; i < MAX_TRAIL_ROOT_WALK; i++) {\n const configPath = path.join(dir, \".trail\", \"config.json\");\n if (fs.existsSync(configPath)) {\n return dir;\n }\n const parent = path.dirname(dir);\n if (parent === dir) {\n break;\n }\n dir = parent;\n }\n return null;\n}\n\nexport interface TrailPaths {\n root: string;\n trailDir: string;\n tasksDir: string;\n configPath: string;\n snapshotPath: string;\n gitignorePath: string;\n}\n\n/** Resolved paths under a Trail project root (the directory that contains `.trail`). */\nexport function trailPaths(root: string): TrailPaths {\n const trailDir = path.join(root, \".trail\");\n return {\n root,\n trailDir,\n tasksDir: path.join(trailDir, \"tasks\"),\n configPath: path.join(trailDir, \"config.json\"),\n snapshotPath: path.join(trailDir, \"snapshot.json\"),\n gitignorePath: path.join(trailDir, \".gitignore\"),\n };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\n\nimport type { TrailError } from \"./errors.js\";\nimport { TaskSchema, type Task } from \"../schemas/task.js\";\n\n/** Thrown by task-store when validation fails; inspect `.trailError` for `VALIDATION_FAILED`. */\nexport type TaskStoreError = Error & { trailError: TrailError };\n\nexport function toValidationError(\n zodError: z.ZodError,\n context?: string,\n): Extract<TrailError, { code: \"VALIDATION_FAILED\" }> {\n const issues = zodError.issues.map(\n (i) => `${i.path.length ? i.path.join(\".\") : \"(root)\"}: ${i.message}`,\n );\n return {\n code: \"VALIDATION_FAILED\",\n message: context\n ? `Task validation failed (${context})`\n : \"Task validation failed\",\n details: zodError.message,\n issues,\n };\n}\n\nfunction throwValidationFailed(\n err: Extract<TrailError, { code: \"VALIDATION_FAILED\" }>,\n): never {\n const e = new Error(`[VALIDATION_FAILED] ${err.message}`) as TaskStoreError;\n e.name = \"TrailError\";\n e.trailError = err;\n throw e;\n}\n\nexport function isTaskStoreValidationError(\n e: unknown,\n): e is TaskStoreError & { trailError: Extract<TrailError, { code: \"VALIDATION_FAILED\" }> } {\n return (\n e instanceof Error &&\n \"trailError\" in e &&\n typeof (e as TaskStoreError).trailError === \"object\" &&\n (e as TaskStoreError).trailError !== null &&\n \"code\" in (e as TaskStoreError).trailError &&\n (e as TaskStoreError).trailError.code === \"VALIDATION_FAILED\"\n );\n}\n\n/**\n * Lists `*.json` basenames under `tasksDir`, excluding `snapshot.json`, sorted lexicographically.\n */\nexport function listTaskFiles(tasksDir: string): string[] {\n const names = fs.readdirSync(tasksDir);\n return names\n .filter(\n (n) => n.endsWith(\".json\") && n !== \"snapshot.json\",\n )\n .sort((a, b) => a.localeCompare(b));\n}\n\nexport function readTaskFile(filePath: string): Task {\n let raw: unknown;\n try {\n raw = JSON.parse(fs.readFileSync(filePath, \"utf8\"));\n } catch (e) {\n if (e instanceof SyntaxError) {\n throwValidationFailed({\n code: \"VALIDATION_FAILED\",\n message: \"Invalid JSON in task file\",\n details: filePath,\n });\n }\n throw e;\n }\n\n const parsed = TaskSchema.safeParse(raw);\n if (!parsed.success) {\n throwValidationFailed(toValidationError(parsed.error, filePath));\n }\n return parsed.data;\n}\n\nexport function writeTaskFile(filePath: string, task: Task): void {\n const parsed = TaskSchema.safeParse(task);\n if (!parsed.success) {\n throwValidationFailed(toValidationError(parsed.error, filePath));\n }\n const dir = path.dirname(filePath);\n fs.mkdirSync(dir, { recursive: true });\n const body = `${JSON.stringify(parsed.data, null, 2)}\\n`;\n fs.writeFileSync(filePath, body, \"utf8\");\n}\n\n/**\n * Loads all task JSON files from `tasksDir`. Returns an empty array if the directory is missing.\n * Stops on the first file that fails to parse or validate.\n */\nexport function loadAllTasks(tasksDir: string): Task[] {\n if (!fs.existsSync(tasksDir)) {\n return [];\n }\n const files = listTaskFiles(tasksDir);\n return files.map((name) => readTaskFile(path.join(tasksDir, name)));\n}\n\n/**\n * Resolves the task file for `id`: prefers `${id}.json` when it exists and its `id` matches;\n * otherwise scans `*.json` for a task whose `id` field equals `id`.\n */\nexport function findTaskFileById(\n tasksDir: string,\n id: string,\n): { filePath: string; task: Task } | null {\n if (!fs.existsSync(tasksDir)) {\n return null;\n }\n const direct = path.join(tasksDir, `${id}.json`);\n if (fs.existsSync(direct)) {\n const task = readTaskFile(direct);\n if (task.id === id) {\n return { filePath: direct, task };\n }\n }\n for (const name of listTaskFiles(tasksDir)) {\n const filePath = path.join(tasksDir, name);\n const task = readTaskFile(filePath);\n if (task.id === id) {\n return { filePath, task };\n }\n }\n return null;\n}\n","import { z } from \"zod\";\n\nexport const TaskStatusSchema = z.enum([\n \"draft\",\n \"todo\",\n \"in_progress\",\n \"in_review\",\n \"done\",\n \"cancelled\",\n]);\n\nexport type TaskStatus = z.infer<typeof TaskStatusSchema>;\n\n/** YYYY-MM-DD (ISO 8601 calendar date). */\nconst isoDateStringSchema = z\n .string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"Expected ISO date string (YYYY-MM-DD)\");\n\n/**\n * GitHub issue link metadata. `null` means the task is not linked to an issue (e.g. local draft).\n */\nconst TaskGitHubSchema = z\n .object({\n issue_number: z.number().int(),\n synced_at: z.string().datetime({ offset: true }),\n url: z.string().url(),\n })\n .nullable();\n\nconst TaskAiSchema = z\n .object({\n summary: z.string().optional(),\n acceptance_criteria: z.array(z.string()).optional(),\n implementation_context: z.array(z.string()).optional(),\n test_strategy: z.array(z.string()).optional(),\n constraints: z.array(z.string()).optional(),\n })\n .strict()\n .optional();\n\nexport const TaskSchema = z\n .object({\n id: z.string(),\n title: z.string(),\n description: z.string().optional(),\n status: TaskStatusSchema,\n priority: z.enum([\"p0\", \"p1\", \"p2\", \"p3\"]).optional(),\n type: z.enum([\"feature\", \"bug\", \"chore\", \"epic\"]),\n assignee: z.string().optional(),\n milestone: z.string().optional(),\n branch: z.string().optional(),\n labels: z.array(z.string()).default([]),\n parent: z.string().nullable().optional(),\n depends_on: z.array(z.string()).default([]),\n blocks: z.array(z.string()).default([]),\n due_date: isoDateStringSchema.optional(),\n start_date: isoDateStringSchema.optional(),\n estimate: z.enum([\"xs\", \"sm\", \"md\", \"lg\", \"xl\"]).optional(),\n github: TaskGitHubSchema.optional(),\n refs: z\n .array(\n z\n .object({\n type: z.string(),\n path: z.string(),\n })\n .strict(),\n )\n .default([]),\n ai: TaskAiSchema,\n created_at: z.string().datetime({ offset: true }),\n updated_at: z.string().datetime({ offset: true }),\n })\n .strict();\n\nexport type Task = z.infer<typeof TaskSchema>;\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport type { Task } from \"../schemas/task.js\";\nimport { SnapshotSchema, type Snapshot } from \"../schemas/snapshot.js\";\n\nconst UNKNOWN_DEPENDENCY = \"UNKNOWN_DEPENDENCY\";\n\n/** Warning code when `depends_on` forms a directed cycle. */\nexport const DEPENDENCY_CYCLE = \"DEPENDENCY_CYCLE\";\n\n/**\n * Finds directed cycles in the dependency graph: edge `u → v` when task `u` lists `v` in `depends_on`.\n * Only vertices in `taskIds` participate; edges to ids outside `taskIds` are ignored here (handled as warnings in `compileSnapshot`).\n */\nexport function detectCycles(\n taskIds: Set<string>,\n deps: Map<string, string[]>,\n): string[][] {\n const cycles: string[][] = [];\n /** Finished nodes (BLACK). */\n const visited = new Set<string>();\n /** Nodes on the current DFS path (GRAY). */\n const visiting = new Set<string>();\n const stack: string[] = [];\n\n function recordCycle(fromIndex: number): void {\n cycles.push(stack.slice(fromIndex));\n }\n\n function dfs(u: string): void {\n visiting.add(u);\n stack.push(u);\n\n for (const v of deps.get(u) ?? []) {\n if (!taskIds.has(v)) {\n continue;\n }\n if (visiting.has(v)) {\n const i = stack.indexOf(v);\n if (i !== -1) {\n recordCycle(i);\n }\n continue;\n }\n if (!visited.has(v)) {\n dfs(v);\n }\n }\n\n stack.pop();\n visiting.delete(u);\n visited.add(u);\n }\n\n for (const id of taskIds) {\n if (!visited.has(id)) {\n dfs(id);\n }\n }\n\n return cycles;\n}\n\nfunction formatCycle(nodes: string[]): string {\n return nodes.join(\" → \");\n}\n\n/**\n * Builds a snapshot from tasks, with warnings for unknown dependency ids and dependency cycles.\n */\nexport function compileSnapshot(tasks: Task[], now?: Date): Snapshot {\n const generatedAt = (now ?? new Date()).toISOString();\n const taskList = [...tasks];\n const taskIds = new Set(taskList.map((t) => t.id));\n const deps = new Map<string, string[]>();\n for (const t of taskList) {\n deps.set(t.id, t.depends_on ?? []);\n }\n\n const warnings: Snapshot[\"warnings\"] = [];\n\n for (const t of taskList) {\n for (const depId of t.depends_on ?? []) {\n if (!taskIds.has(depId)) {\n warnings.push({\n code: UNKNOWN_DEPENDENCY,\n message: `Task \"${t.id}\" depends on unknown task id \"${depId}\"`,\n taskId: t.id,\n });\n }\n }\n }\n\n for (const cycle of detectCycles(taskIds, deps)) {\n warnings.push({\n code: DEPENDENCY_CYCLE,\n message: `Dependency cycle: ${formatCycle(cycle)}`,\n taskId: cycle[0],\n });\n }\n\n return {\n generated_at: generatedAt,\n tasks: taskList,\n warnings,\n };\n}\n\nexport function writeSnapshot(snapshotPath: string, snapshot: Snapshot): void {\n const parsed = SnapshotSchema.parse(snapshot);\n const dir = path.dirname(snapshotPath);\n fs.mkdirSync(dir, { recursive: true });\n const body = `${JSON.stringify(parsed, null, 2)}\\n`;\n fs.writeFileSync(snapshotPath, body, \"utf8\");\n}\n","import { z } from \"zod\";\n\nimport { TaskSchema } from \"./task.js\";\n\nexport const SnapshotSchema = z\n .object({\n generated_at: z.string().datetime({ offset: true }),\n tasks: z.array(TaskSchema),\n warnings: z.array(\n z\n .object({\n code: z.string(),\n message: z.string(),\n taskId: z.string().optional(),\n })\n .strict(),\n ),\n })\n .strict();\n\nexport type Snapshot = z.infer<typeof SnapshotSchema>;\n","import { compileSnapshot, writeSnapshot } from \"./compile-snapshot.js\";\nimport { loadAllTasks } from \"./task-store.js\";\nimport type { TrailPaths } from \"./paths.js\";\n\n/** Recompiles `.trail/snapshot.json` from all task files. */\nexport function rebuildSnapshot(paths: TrailPaths, now = new Date()): void {\n const tasks = loadAllTasks(paths.tasksDir);\n const snapshot = compileSnapshot(tasks, now);\n writeSnapshot(paths.snapshotPath, snapshot);\n}\n","import { randomBytes } from \"node:crypto\";\n\n/** Stable draft task id prefix + random suffix (e.g. `draft-a1b2c3d4`). */\nexport function generateDraftId(): string {\n return `draft-${randomBytes(4).toString(\"hex\")}`;\n}\n","import { z } from \"zod\";\n\nexport const TrailConfigSchema = z\n .object({\n github: z\n .object({\n owner: z.string(),\n repo: z.string(),\n })\n .strict(),\n sync: z\n .object({\n preset: z.enum([\"collaborative\", \"solo\", \"offline\"]),\n auto_sync_on_command: z.boolean(),\n ui_poll_interval_seconds: z.number(),\n ui_idle_backoff: z.boolean(),\n })\n .strict(),\n /** Last successful full sync; useful for future `trail status` and similar. */\n last_full_sync_at: z.string().datetime({ offset: true }).optional(),\n })\n .strict();\n\nexport type TrailConfig = z.infer<typeof TrailConfigSchema>;\n"],"mappings":"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","names":["fs","path","fs","path","fs","path","z","z","path","fs","z"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trail-pm/cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.9",
4
4
  "description": "GitHub-native AI project management CLI",
5
5
  "type": "module",
6
6
  "files": [
@@ -16,6 +16,16 @@
16
16
  },
17
17
  "main": "./dist/index.js",
18
18
  "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js"
23
+ },
24
+ "./lib": {
25
+ "types": "./dist/lib.d.ts",
26
+ "import": "./dist/lib.js"
27
+ }
28
+ },
19
29
  "scripts": {
20
30
  "prepublishOnly": "npm run build",
21
31
  "build": "tsup",
@@ -23,7 +33,9 @@
23
33
  "test": "vitest run",
24
34
  "test:watch": "vitest",
25
35
  "typecheck": "tsc --noEmit",
26
- "lint": "tsc --noEmit"
36
+ "lint": "tsc --noEmit",
37
+ "ui:dev": "npm --prefix ../ui run dev:all",
38
+ "ui:server": "npm --prefix ../ui run server"
27
39
  },
28
40
  "dependencies": {
29
41
  "@modelcontextprotocol/sdk": "^1.29.0",