@nickmeriano/task 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +77 -9
  2. package/dist/cli.js +290 -19
  3. package/dist/cli.js.map +1 -1
  4. package/dist/file-store.d.ts +113 -0
  5. package/dist/file-store.d.ts.map +1 -0
  6. package/dist/file-store.js +604 -0
  7. package/dist/file-store.js.map +1 -0
  8. package/dist/index.d.ts +6 -4
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +3 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/server.d.ts.map +1 -1
  13. package/dist/server.js +30 -7
  14. package/dist/server.js.map +1 -1
  15. package/dist/store.d.ts +69 -16
  16. package/dist/store.d.ts.map +1 -1
  17. package/dist/store.js +169 -39
  18. package/dist/store.js.map +1 -1
  19. package/dist/store.test.d.ts +12 -0
  20. package/dist/store.test.d.ts.map +1 -0
  21. package/dist/store.test.js +252 -0
  22. package/dist/store.test.js.map +1 -0
  23. package/dist/ticket-doc.d.ts +57 -0
  24. package/dist/ticket-doc.d.ts.map +1 -0
  25. package/dist/ticket-doc.js +197 -0
  26. package/dist/ticket-doc.js.map +1 -0
  27. package/dist/types.d.ts +35 -3
  28. package/dist/types.d.ts.map +1 -1
  29. package/dist/types.js.map +1 -1
  30. package/package.json +4 -4
  31. package/skill/SKILL.md +40 -9
  32. package/src/cli.ts +304 -22
  33. package/src/file-store.ts +693 -0
  34. package/src/index.ts +30 -4
  35. package/src/server.ts +31 -11
  36. package/src/store.test.ts +305 -0
  37. package/src/store.ts +210 -49
  38. package/src/ticket-doc.ts +226 -0
  39. package/src/types.ts +35 -3
  40. package/ui/dist/assets/index-CXW8uT5f.css +1 -0
  41. package/ui/dist/assets/{index-Dm3ToURf.js → index-oJzomUDL.js} +67 -67
  42. package/ui/dist/index.html +2 -2
  43. package/ui/dist/assets/index-DXFbw9bM.css +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAA;AACtG,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AACtF,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,SAAS,EACT,WAAW,EACX,YAAY,EACZ,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,aAAa,EACb,KAAK,QAAQ,EACb,KAAK,KAAK,GACX,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,WAAW,EACX,SAAS,EACT,WAAW,EACX,WAAW,EACX,YAAY,EACZ,SAAS,GACV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,WAAW,EACX,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AACtF,cAAc,YAAY,CAAA"}
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  // Programmatic access to the same store the CLI and `task serve` use — for
2
2
  // scripts that want to read or write .task/ without shelling out.
3
- export { TaskStore, findRoot, findBoards, initProject, derivePrefix } from "./store.js";
3
+ export { TaskStore, boardConfig, derivePrefix, findBoards, findBoardsByPrefix, findRoot, findScopeRoot, } from "./store.js";
4
+ export { ARCHIVE_DIR, FileStore, TICKETS_DIR, initProject, migrateBoard, openBoard, } from "./file-store.js";
5
+ export { parseTicket, serializeTicket, parseComment, serializeComment, } from "./ticket-doc.js";
4
6
  export { createTaskServer } from "./server.js";
5
7
  export { resolveAuthor, ANONYMOUS } from "./author.js";
6
8
  export * from "./types.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,kEAAkE;AAClE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAiB,MAAM,YAAY,CAAA;AACtG,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAkC,MAAM,aAAa,CAAA;AACtF,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,kEAAkE;AAClE,OAAO,EACL,SAAS,EACT,WAAW,EACX,YAAY,EACZ,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,aAAa,GAGd,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,WAAW,EACX,SAAS,EACT,WAAW,EACX,WAAW,EACX,YAAY,EACZ,SAAS,GACV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,WAAW,EACX,eAAe,EACf,YAAY,EACZ,gBAAgB,GAGjB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAkC,MAAM,aAAa,CAAA;AACtF,cAAc,YAAY,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAA;AAsDhG;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAqP1D"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAA;AAuEhG;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAwP1D"}
package/dist/server.js CHANGED
@@ -3,7 +3,8 @@ import { watch, existsSync, readFileSync, statSync } from "node:fs";
3
3
  import { extname, join, normalize } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { resolveAuthor } from "./author.js";
6
- import { findBoards, TaskStore } from "./store.js";
6
+ import { openBoard } from "./file-store.js";
7
+ import { findBoards } from "./store.js";
7
8
  import { STATUSES, isStatus } from "./types.js";
8
9
  /** The prebuilt SPA, shipped inside the package next to dist/. */
9
10
  const UI_DIR = fileURLToPath(new URL("../ui/dist", import.meta.url));
@@ -50,10 +51,29 @@ function parsePatch(body) {
50
51
  }
51
52
  if (typeof body.needsHuman === "boolean")
52
53
  patch.needsHuman = body.needsHuman;
54
+ if (Array.isArray(body.blocks))
55
+ patch.blocks = body.blocks.map(taskNumber);
56
+ if (Array.isArray(body.blockedBy))
57
+ patch.blockedBy = body.blockedBy.map(taskNumber);
58
+ if (Array.isArray(body.prs)) {
59
+ patch.prs = body.prs.map((pr) => {
60
+ const url = String(pr).trim();
61
+ // Anything the UI would render as a clickable link has to be a link.
62
+ if (!/^https?:\/\//.test(url))
63
+ throw new Error(`not a PR url: ${url}`);
64
+ return url;
65
+ });
66
+ }
53
67
  if (typeof body.position === "number")
54
68
  patch.position = body.position;
55
69
  return patch;
56
70
  }
71
+ function taskNumber(value) {
72
+ const n = Number(value);
73
+ if (!Number.isInteger(n) || n <= 0)
74
+ throw new Error(`invalid task number: ${String(value)}`);
75
+ return n;
76
+ }
57
77
  /**
58
78
  * `task serve` — one plain node:http server for the static UI, the JSON API,
59
79
  * and an SSE stream that pings whenever anything writes to a `.task/` (the UI
@@ -91,9 +111,12 @@ export function createTaskServer(serveRoot) {
91
111
  };
92
112
  const boards = new Map();
93
113
  let ordered = [];
94
- const openBoard = (ref) => {
95
- const store = new TaskStore(ref.root);
96
- const watcher = watch(store.taskDir, () => noteChange(ref.id));
114
+ const attachBoard = (ref) => {
115
+ const store = openBoard(ref.root);
116
+ // Recursive: text-canonical state is a tree (tickets/<n>/comments/…), and
117
+ // a write anywhere in it is a board change. Node supports this on Linux,
118
+ // macOS and Windows for the versions this package requires.
119
+ const watcher = watch(store.taskDir, { recursive: true }, () => noteChange(ref.id));
97
120
  // A deleted board dir can make fs.watch emit; the next rescan cleans up.
98
121
  watcher.on("error", () => { });
99
122
  boards.set(ref.id, { store, watcher });
@@ -111,7 +134,7 @@ export function createTaskServer(serveRoot) {
111
134
  }
112
135
  for (const ref of found)
113
136
  if (!boards.has(ref.id))
114
- openBoard(ref);
137
+ attachBoard(ref);
115
138
  ordered = found.map((ref) => ref.id);
116
139
  return found;
117
140
  };
@@ -209,11 +232,11 @@ export function createTaskServer(serveRoot) {
209
232
  .catch((error) => json(res, 400, { error: error.message }));
210
233
  return;
211
234
  }
212
- const taskMatch = /^\/api\/tasks\/([^/]+)(\/comments(?:\/(\d+))?)?$/.exec(path);
235
+ const taskMatch = /^\/api\/tasks\/([^/]+)(\/comments(?:\/([^/]+))?)?$/.exec(path);
213
236
  if (taskMatch) {
214
237
  const number = store.parseId(decodeURIComponent(taskMatch[1]));
215
238
  if (taskMatch[3] && req.method === "DELETE") {
216
- const commentId = Number(taskMatch[3]);
239
+ const commentId = decodeURIComponent(taskMatch[3]);
217
240
  const existing = store.comments(number).find((c) => c.id === commentId);
218
241
  if (!existing) {
219
242
  json(res, 404, { error: `no such comment: ${commentId}` });
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/dist/store.d.ts CHANGED
@@ -1,7 +1,37 @@
1
- import type { Comment, ProjectConfig, Task, TaskFilter, TaskInput, TaskPatch } from "./types.js";
1
+ import type { Comment, ProjectConfig, Task, TaskFilter, TaskInput, TaskPatch } from "./types.ts";
2
2
  export declare const TASK_DIR = ".task";
3
3
  export declare const DB_FILE = "tasks.db";
4
4
  export declare const CONFIG_FILE = "config.json";
5
+ /** Spacing between adjacent board positions — leaves room to drop between. */
6
+ export declare const POSITION_GAP = 1024;
7
+ /**
8
+ * What a board's persistence layer looks like, whichever representation backs
9
+ * it. Two implementations: `FileStore` (text files in `.task/tickets/`, the
10
+ * canonical format) and the legacy `TaskStore` (a committed SQLite database),
11
+ * which survives so un-migrated boards keep working. `openBoard` picks.
12
+ */
13
+ export interface Store {
14
+ readonly root: string;
15
+ readonly taskDir: string;
16
+ readonly config: ProjectConfig;
17
+ close(): void;
18
+ displayId(number: number): string;
19
+ parseId(ref: string): number;
20
+ list(filter?: TaskFilter): Task[];
21
+ get(number: number): Task | null;
22
+ create(input: TaskInput): Task;
23
+ update(number: number, patch: TaskPatch): Task;
24
+ link(number: number, relation: "blocks" | "blocked_by", target: number): Task;
25
+ unlink(number: number, relation: "blocks" | "blocked_by", target: number): Task;
26
+ delete(number: number): void;
27
+ /** Move a done/canceled ticket to `.task/archive/`, out of the board's hot path. */
28
+ archive(number: number): Task;
29
+ unarchive(number: number): Task;
30
+ comments(number: number): Comment[];
31
+ addComment(number: number, body: string, author?: string): Comment;
32
+ deleteComment(number: number, commentId: string): Comment;
33
+ commentCounts(): Map<number, number>;
34
+ }
5
35
  /**
6
36
  * Walk up from `from` looking for a `.task/config.json`, the way git finds its
7
37
  * `.git`. Returns the directory that *contains* `.task`, or null.
@@ -13,6 +43,22 @@ export interface BoardRef {
13
43
  /** Absolute directory containing `.task/`. */
14
44
  root: string;
15
45
  }
46
+ /**
47
+ * The widest board scope `from` belongs to: the *outermost* ancestor holding a
48
+ * `.task/` (a monorepo's root board), or `from` itself when no ancestor has
49
+ * one. Where `findRoot` answers "which board am I on", this answers "which
50
+ * repo of boards am I in" — the anchor for anything cross-board: prefix
51
+ * routing and `task boards`.
52
+ */
53
+ export declare function findScopeRoot(from: string): string;
54
+ /** A board's config, read without opening a store. Throws on a broken file. */
55
+ export declare function boardConfig(root: string): ProjectConfig;
56
+ /**
57
+ * Every board in scope whose prefix is `prefix` (case-insensitive). Normally
58
+ * zero or one — two boards sharing a prefix is a repo mistake this surfaces
59
+ * rather than resolves. Boards with unreadable configs can't match.
60
+ */
61
+ export declare function findBoardsByPrefix(scopeRoot: string, prefix: string): BoardRef[];
16
62
  /**
17
63
  * The multi-board complement of `findRoot`: walk *down* from `serveRoot`
18
64
  * collecting every directory that holds a `.task/config.json`, so one
@@ -21,14 +67,15 @@ export interface BoardRef {
21
67
  * dependency/build dirs and symlinks are skipped; unreadable dirs are ignored.
22
68
  */
23
69
  export declare function findBoards(serveRoot: string, maxDepth?: number): BoardRef[];
24
- /** Derive an id prefix from a project name: "phone agent" → "PHONE". */
70
+ /** Derive an id prefix from a project name: "phone agent" → "PHO". */
25
71
  export declare function derivePrefix(name: string): string;
26
72
  /**
27
- * The whole persistence layer: one SQLite database inside `.task/`, opened
73
+ * The legacy persistence layer: one SQLite database inside `.task/`, opened
28
74
  * synchronously via node:sqlite (built into Node ≥22.13 — zero dependencies,
29
- * nothing to compile, safe for `npx`).
75
+ * nothing to compile, safe for `npx`). Boards created before the text format
76
+ * still run on this until `task migrate` moves them over.
30
77
  */
31
- export declare class TaskStore {
78
+ export declare class TaskStore implements Store {
32
79
  readonly root: string;
33
80
  readonly taskDir: string;
34
81
  readonly config: ProjectConfig;
@@ -39,25 +86,31 @@ export declare class TaskStore {
39
86
  /** Accepts "PHONE-12", "phone-12" or "12". */
40
87
  parseId(ref: string): number;
41
88
  private toTask;
89
+ /** The other end of every link where `column` is this task. */
90
+ private linkedNumbers;
42
91
  private toComment;
43
92
  list(filter?: TaskFilter): Task[];
44
93
  get(number: number): Task | null;
45
94
  create(input: TaskInput): Task;
46
95
  update(number: number, patch: TaskPatch): Task;
96
+ /**
97
+ * Make the link table agree with `targets` for one side of one task —
98
+ * `blocker_id` when setting what `number` blocks, `blocked_id` when setting
99
+ * what blocks it. The other task's view is the same row read from the other
100
+ * end, so there is no second write to keep consistent. Every task touched
101
+ * (both ends of every added or removed link) gets its `updated_at` bumped.
102
+ */
103
+ private reconcileLinks;
104
+ /** `task link A --blocks B` and friends — additive, unlike the patch form. */
105
+ link(number: number, relation: "blocks" | "blocked_by", target: number): Task;
106
+ unlink(number: number, relation: "blocks" | "blocked_by", target: number): Task;
47
107
  delete(number: number): void;
108
+ /** The archive is a text-format feature — a directory move, not a table. */
109
+ archive(_number: number): Task;
110
+ unarchive(_number: number): Task;
48
111
  comments(number: number): Comment[];
49
112
  addComment(number: number, body: string, author?: string): Comment;
50
- deleteComment(number: number, commentId: number): Comment;
113
+ deleteComment(number: number, commentId: string): Comment;
51
114
  commentCounts(): Map<number, number>;
52
115
  }
53
- export interface InitOptions {
54
- name: string;
55
- prefix?: string;
56
- }
57
- /**
58
- * Create `.task/` in `root`: config, an empty database, and a .gitignore for
59
- * SQLite's transient sidecar files (the database itself is meant to be
60
- * committed — that's the point).
61
- */
62
- export declare function initProject(root: string, options: InitOptions): TaskStore;
63
116
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,OAAO,EACP,aAAa,EAEb,IAAI,EACJ,UAAU,EACV,SAAS,EACT,SAAS,EACV,MAAM,YAAY,CAAA;AAEnB,eAAO,MAAM,QAAQ,UAAU,CAAA;AAC/B,eAAO,MAAM,OAAO,aAAa,CAAA;AACjC,eAAO,MAAM,WAAW,gBAAgB,CAAA;AAKxC;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQpD;AAED,MAAM,WAAW,QAAQ;IACvB,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAA;IACV,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAA;CACb;AAKD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,QAAQ,EAAE,CA4BtE;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD;AA2BD;;;;GAIG;AACH,qBAAa,SAAS;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;IAC9B,OAAO,CAAC,EAAE,CAAc;gBAEZ,IAAI,EAAE,MAAM;IAcxB,KAAK,IAAI,IAAI;IAIb,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIjC,8CAA8C;IAC9C,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAM5B,OAAO,CAAC,MAAM;IAgBd,OAAO,CAAC,SAAS;IAUjB,IAAI,CAAC,MAAM,GAAE,UAAe,GAAG,IAAI,EAAE;IAyBrC,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAOhC,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IA0B9B,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI;IAoC9C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK5B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE;IAOnC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,OAAO;IAW9D,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IASzD,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;CAMrC;AAgFD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,SAAS,CAiBzE"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
package/dist/store.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { DatabaseSync } from "node:sqlite";
2
- import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
3
3
  import { dirname, join, relative, sep } from "node:path";
4
4
  export const TASK_DIR = ".task";
5
5
  export const DB_FILE = "tasks.db";
6
6
  export const CONFIG_FILE = "config.json";
7
7
  /** Spacing between adjacent board positions — leaves room to drop between. */
8
- const POSITION_GAP = 1024;
8
+ export const POSITION_GAP = 1024;
9
9
  /**
10
10
  * Walk up from `from` looking for a `.task/config.json`, the way git finds its
11
11
  * `.git`. Returns the directory that *contains* `.task`, or null.
@@ -21,6 +21,46 @@ export function findRoot(from) {
21
21
  dir = parent;
22
22
  }
23
23
  }
24
+ /**
25
+ * The widest board scope `from` belongs to: the *outermost* ancestor holding a
26
+ * `.task/` (a monorepo's root board), or `from` itself when no ancestor has
27
+ * one. Where `findRoot` answers "which board am I on", this answers "which
28
+ * repo of boards am I in" — the anchor for anything cross-board: prefix
29
+ * routing and `task boards`.
30
+ */
31
+ export function findScopeRoot(from) {
32
+ let dir = from;
33
+ let top = null;
34
+ for (;;) {
35
+ if (existsSync(join(dir, TASK_DIR, CONFIG_FILE)))
36
+ top = dir;
37
+ const parent = dirname(dir);
38
+ if (parent === dir)
39
+ break;
40
+ dir = parent;
41
+ }
42
+ return top ?? from;
43
+ }
44
+ /** A board's config, read without opening a store. Throws on a broken file. */
45
+ export function boardConfig(root) {
46
+ return JSON.parse(readFileSync(join(root, TASK_DIR, CONFIG_FILE), "utf8"));
47
+ }
48
+ /**
49
+ * Every board in scope whose prefix is `prefix` (case-insensitive). Normally
50
+ * zero or one — two boards sharing a prefix is a repo mistake this surfaces
51
+ * rather than resolves. Boards with unreadable configs can't match.
52
+ */
53
+ export function findBoardsByPrefix(scopeRoot, prefix) {
54
+ const wanted = prefix.toUpperCase();
55
+ return findBoards(scopeRoot).filter((ref) => {
56
+ try {
57
+ return boardConfig(ref.root).prefix.toUpperCase() === wanted;
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ });
63
+ }
24
64
  /** Directories that never contain a board worth serving. */
25
65
  const SKIP_DIRS = new Set(["node_modules", "dist", "build", "out", "coverage", "target"]);
26
66
  /**
@@ -62,18 +102,19 @@ export function findBoards(serveRoot, maxDepth = 6) {
62
102
  boards.sort((a, b) => (a.id === "." ? -1 : b.id === "." ? 1 : a.id < b.id ? -1 : 1));
63
103
  return boards;
64
104
  }
65
- /** Derive an id prefix from a project name: "phone agent" → "PHONE". */
105
+ /** Derive an id prefix from a project name: "phone agent" → "PHO". */
66
106
  export function derivePrefix(name) {
67
107
  const word = name.toUpperCase().replace(/[^A-Z0-9]+/g, " ").trim().split(" ")[0];
68
- return (word || "TASK").slice(0, 10);
108
+ return (word || "TAS").slice(0, 3);
69
109
  }
70
110
  function now() {
71
111
  return new Date().toISOString();
72
112
  }
73
113
  /**
74
- * The whole persistence layer: one SQLite database inside `.task/`, opened
114
+ * The legacy persistence layer: one SQLite database inside `.task/`, opened
75
115
  * synchronously via node:sqlite (built into Node ≥22.13 — zero dependencies,
76
- * nothing to compile, safe for `npx`).
116
+ * nothing to compile, safe for `npx`). Boards created before the text format
117
+ * still run on this until `task migrate` moves them over.
77
118
  */
78
119
  export class TaskStore {
79
120
  root;
@@ -114,14 +155,25 @@ export class TaskStore {
114
155
  tags: JSON.parse(row.tags),
115
156
  milestone: row.milestone,
116
157
  needsHuman: row.needs_human !== 0,
158
+ blocks: this.linkedNumbers("blocker_id", row.id),
159
+ blockedBy: this.linkedNumbers("blocked_id", row.id),
160
+ prs: JSON.parse(row.prs),
117
161
  position: row.position,
118
162
  createdAt: row.created_at,
119
163
  updatedAt: row.updated_at,
120
164
  };
121
165
  }
166
+ /** The other end of every link where `column` is this task. */
167
+ linkedNumbers(column, number) {
168
+ const other = column === "blocker_id" ? "blocked_id" : "blocker_id";
169
+ const rows = this.db
170
+ .prepare(`SELECT ${other} AS n FROM task_links WHERE ${column} = ? ORDER BY ${other}`)
171
+ .all(number);
172
+ return rows.map((r) => r.n);
173
+ }
122
174
  toComment(row) {
123
175
  return {
124
- id: row.id,
176
+ id: String(row.id),
125
177
  taskId: this.displayId(row.task_id),
126
178
  author: row.author,
127
179
  body: row.body,
@@ -129,6 +181,9 @@ export class TaskStore {
129
181
  };
130
182
  }
131
183
  list(filter = {}) {
184
+ if (filter.archived) {
185
+ throw new Error("archiving needs a text-format board — run `task migrate` first");
186
+ }
132
187
  const where = [];
133
188
  const params = [];
134
189
  if (filter.statuses?.length) {
@@ -164,15 +219,29 @@ export class TaskStore {
164
219
  .get(status);
165
220
  const timestamp = now();
166
221
  const result = this.db
167
- .prepare(`INSERT INTO tasks (title, description, status, tags, milestone, needs_human, position, created_at, updated_at)
168
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
169
- .run(input.title, input.description ?? "", status, JSON.stringify(input.tags ?? []), input.milestone ?? null, input.needsHuman ? 1 : 0, (max.max ?? 0) + POSITION_GAP, timestamp, timestamp);
170
- return this.get(Number(result.lastInsertRowid));
222
+ .prepare(`INSERT INTO tasks (title, description, status, tags, milestone, needs_human, prs, position, created_at, updated_at)
223
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
224
+ .run(input.title, input.description ?? "", status, JSON.stringify(input.tags ?? []), input.milestone ?? null, input.needsHuman ? 1 : 0, JSON.stringify(input.prs ?? []), (max.max ?? 0) + POSITION_GAP, timestamp, timestamp);
225
+ const number = Number(result.lastInsertRowid);
226
+ if (input.blocks !== undefined)
227
+ this.reconcileLinks("blocker_id", number, input.blocks);
228
+ if (input.blockedBy !== undefined)
229
+ this.reconcileLinks("blocked_id", number, input.blockedBy);
230
+ return this.get(number);
171
231
  }
172
232
  update(number, patch) {
173
233
  const existing = this.get(number);
174
234
  if (!existing)
175
235
  throw new Error(`no such task: ${this.displayId(number)}`);
236
+ // Reconciled outside the UPDATE — links live in their own table. Done
237
+ // first so a bad target rejects the whole patch before anything writes.
238
+ let linksChanged = false;
239
+ if (patch.blocks !== undefined) {
240
+ linksChanged = this.reconcileLinks("blocker_id", number, patch.blocks);
241
+ }
242
+ if (patch.blockedBy !== undefined) {
243
+ linksChanged = this.reconcileLinks("blocked_id", number, patch.blockedBy) || linksChanged;
244
+ }
176
245
  const sets = [];
177
246
  const params = [];
178
247
  const set = (column, value) => {
@@ -189,6 +258,8 @@ export class TaskStore {
189
258
  set("milestone", patch.milestone);
190
259
  if (patch.needsHuman !== undefined)
191
260
  set("needs_human", patch.needsHuman ? 1 : 0);
261
+ if (patch.prs !== undefined)
262
+ set("prs", JSON.stringify(patch.prs));
192
263
  if (patch.status !== undefined) {
193
264
  set("status", patch.status);
194
265
  if (patch.position === undefined && patch.status !== existing.status) {
@@ -202,11 +273,70 @@ export class TaskStore {
202
273
  }
203
274
  if (patch.position !== undefined)
204
275
  set("position", patch.position);
205
- if (sets.length === 0)
276
+ if (sets.length === 0 && !linksChanged)
206
277
  return existing;
207
- set("updated_at", now());
208
- params.push(number);
209
- this.db.prepare(`UPDATE tasks SET ${sets.join(", ")} WHERE id = ?`).run(...params);
278
+ if (sets.length > 0) {
279
+ set("updated_at", now());
280
+ params.push(number);
281
+ this.db.prepare(`UPDATE tasks SET ${sets.join(", ")} WHERE id = ?`).run(...params);
282
+ }
283
+ return this.get(number);
284
+ }
285
+ /**
286
+ * Make the link table agree with `targets` for one side of one task —
287
+ * `blocker_id` when setting what `number` blocks, `blocked_id` when setting
288
+ * what blocks it. The other task's view is the same row read from the other
289
+ * end, so there is no second write to keep consistent. Every task touched
290
+ * (both ends of every added or removed link) gets its `updated_at` bumped.
291
+ */
292
+ reconcileLinks(column, number, targets) {
293
+ const other = column === "blocker_id" ? "blocked_id" : "blocker_id";
294
+ const wanted = [...new Set(targets)];
295
+ for (const target of wanted) {
296
+ if (target === number) {
297
+ throw new Error(`a task can't block itself: ${this.displayId(number)}`);
298
+ }
299
+ if (!this.db.prepare("SELECT id FROM tasks WHERE id = ?").get(target)) {
300
+ throw new Error(`no such task: ${this.displayId(target)}`);
301
+ }
302
+ }
303
+ const current = new Set(this.linkedNumbers(column, number));
304
+ const removed = [...current].filter((n) => !wanted.includes(n));
305
+ const added = wanted.filter((n) => !current.has(n));
306
+ for (const n of removed) {
307
+ this.db
308
+ .prepare(`DELETE FROM task_links WHERE ${column} = ? AND ${other} = ?`)
309
+ .run(number, n);
310
+ }
311
+ for (const n of added) {
312
+ this.db
313
+ .prepare(`INSERT OR IGNORE INTO task_links (${column}, ${other}) VALUES (?, ?)`)
314
+ .run(number, n);
315
+ }
316
+ const touched = [...removed, ...added];
317
+ if (touched.length > 0) {
318
+ const timestamp = now();
319
+ const bump = this.db.prepare("UPDATE tasks SET updated_at = ? WHERE id = ?");
320
+ for (const n of [...touched, number])
321
+ bump.run(timestamp, n);
322
+ }
323
+ return touched.length > 0;
324
+ }
325
+ /** `task link A --blocks B` and friends — additive, unlike the patch form. */
326
+ link(number, relation, target) {
327
+ if (!this.get(number))
328
+ throw new Error(`no such task: ${this.displayId(number)}`);
329
+ const column = relation === "blocks" ? "blocker_id" : "blocked_id";
330
+ const current = this.linkedNumbers(column, number);
331
+ this.reconcileLinks(column, number, [...current, target]);
332
+ return this.get(number);
333
+ }
334
+ unlink(number, relation, target) {
335
+ if (!this.get(number))
336
+ throw new Error(`no such task: ${this.displayId(number)}`);
337
+ const column = relation === "blocks" ? "blocker_id" : "blocked_id";
338
+ const current = this.linkedNumbers(column, number);
339
+ this.reconcileLinks(column, number, current.filter((n) => n !== target));
210
340
  return this.get(number);
211
341
  }
212
342
  delete(number) {
@@ -214,6 +344,13 @@ export class TaskStore {
214
344
  if (result.changes === 0)
215
345
  throw new Error(`no such task: ${this.displayId(number)}`);
216
346
  }
347
+ /** The archive is a text-format feature — a directory move, not a table. */
348
+ archive(_number) {
349
+ throw new Error("archiving needs a text-format board — run `task migrate` first");
350
+ }
351
+ unarchive(_number) {
352
+ throw new Error("archiving needs a text-format board — run `task migrate` first");
353
+ }
217
354
  comments(number) {
218
355
  const rows = this.db
219
356
  .prepare("SELECT * FROM comments WHERE task_id = ? ORDER BY id")
@@ -232,12 +369,15 @@ export class TaskStore {
232
369
  return this.toComment(row);
233
370
  }
234
371
  deleteComment(number, commentId) {
235
- const row = this.db
236
- .prepare("SELECT * FROM comments WHERE id = ? AND task_id = ?")
237
- .get(commentId, number);
372
+ const rowid = Number(commentId);
373
+ const row = (Number.isInteger(rowid)
374
+ ? this.db
375
+ .prepare("SELECT * FROM comments WHERE id = ? AND task_id = ?")
376
+ .get(rowid, number)
377
+ : undefined);
238
378
  if (!row)
239
379
  throw new Error(`no such comment on ${this.displayId(number)}: ${commentId}`);
240
- this.db.prepare("DELETE FROM comments WHERE id = ?").run(commentId);
380
+ this.db.prepare("DELETE FROM comments WHERE id = ?").run(rowid);
241
381
  return this.toComment(row);
242
382
  }
243
383
  commentCounts() {
@@ -301,6 +441,16 @@ const MIGRATIONS = [
301
441
  ALTER TABLE tasks ADD COLUMN needs_human INTEGER NOT NULL DEFAULT 0;
302
442
  ALTER TABLE tasks DROP COLUMN priority;
303
443
  ALTER TABLE tasks DROP COLUMN assignee;`,
444
+ // v3 — dependencies and pull requests. One direction of "blocks" is the
445
+ // whole relation: (blocker, blocked) read from the blocked side is
446
+ // "blocked by", so the mirror is a query, not a second row. PRs are a JSON
447
+ // list of URLs, same shape as tags.
448
+ `CREATE TABLE task_links (
449
+ blocker_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
450
+ blocked_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
451
+ PRIMARY KEY (blocker_id, blocked_id)
452
+ );
453
+ ALTER TABLE tasks ADD COLUMN prs TEXT NOT NULL DEFAULT '[]';`,
304
454
  ];
305
455
  /**
306
456
  * Bring `db` up to the newest schema. DDL and `PRAGMA user_version` are both
@@ -323,24 +473,4 @@ function migrate(db) {
323
473
  throw error;
324
474
  }
325
475
  }
326
- /**
327
- * Create `.task/` in `root`: config, an empty database, and a .gitignore for
328
- * SQLite's transient sidecar files (the database itself is meant to be
329
- * committed — that's the point).
330
- */
331
- export function initProject(root, options) {
332
- const taskDir = join(root, TASK_DIR);
333
- if (existsSync(join(taskDir, CONFIG_FILE))) {
334
- throw new Error(`already initialized: ${join(taskDir, CONFIG_FILE)} exists`);
335
- }
336
- mkdirSync(taskDir, { recursive: true });
337
- const config = {
338
- name: options.name,
339
- prefix: options.prefix ?? derivePrefix(options.name),
340
- version: 1,
341
- };
342
- writeFileSync(join(taskDir, CONFIG_FILE), `${JSON.stringify(config, null, 2)}\n`);
343
- writeFileSync(join(taskDir, ".gitignore"), "# SQLite transients — tasks.db itself is committed.\n*.db-journal\n*.db-wal\n*.db-shm\n");
344
- return new TaskStore(root);
345
- }
346
476
  //# sourceMappingURL=store.js.map