@nickmeriano/task 0.7.1 → 0.9.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 (128) hide show
  1. package/README.md +73 -25
  2. package/dist/asks.test.d.ts +17 -0
  3. package/dist/asks.test.d.ts.map +1 -0
  4. package/dist/asks.test.js +278 -0
  5. package/dist/asks.test.js.map +1 -0
  6. package/dist/check.d.ts +43 -0
  7. package/dist/check.d.ts.map +1 -0
  8. package/dist/check.js +403 -0
  9. package/dist/check.js.map +1 -0
  10. package/dist/check.test.d.ts +9 -0
  11. package/dist/check.test.d.ts.map +1 -0
  12. package/dist/check.test.js +248 -0
  13. package/dist/check.test.js.map +1 -0
  14. package/dist/claim-io.d.ts +73 -0
  15. package/dist/claim-io.d.ts.map +1 -0
  16. package/dist/claim-io.js +344 -0
  17. package/dist/claim-io.js.map +1 -0
  18. package/dist/claim.d.ts +61 -9
  19. package/dist/claim.d.ts.map +1 -1
  20. package/dist/claim.js +197 -67
  21. package/dist/claim.js.map +1 -1
  22. package/dist/claim.test.d.ts +2 -2
  23. package/dist/claim.test.js +235 -64
  24. package/dist/claim.test.js.map +1 -1
  25. package/dist/cli.js +724 -136
  26. package/dist/cli.js.map +1 -1
  27. package/dist/file-store.d.ts +110 -38
  28. package/dist/file-store.d.ts.map +1 -1
  29. package/dist/file-store.js +514 -238
  30. package/dist/file-store.js.map +1 -1
  31. package/dist/git-serve.d.ts +183 -0
  32. package/dist/git-serve.d.ts.map +1 -0
  33. package/dist/git-serve.js +503 -0
  34. package/dist/git-serve.js.map +1 -0
  35. package/dist/git-serve.test.d.ts +16 -0
  36. package/dist/git-serve.test.d.ts.map +1 -0
  37. package/dist/git-serve.test.js +183 -0
  38. package/dist/git-serve.test.js.map +1 -0
  39. package/dist/git.d.ts +65 -0
  40. package/dist/git.d.ts.map +1 -0
  41. package/dist/git.js +114 -0
  42. package/dist/git.js.map +1 -0
  43. package/dist/id.d.ts +39 -0
  44. package/dist/id.d.ts.map +1 -0
  45. package/dist/id.js +67 -0
  46. package/dist/id.js.map +1 -0
  47. package/dist/inbox.d.ts +41 -0
  48. package/dist/inbox.d.ts.map +1 -0
  49. package/dist/inbox.js +56 -0
  50. package/dist/inbox.js.map +1 -0
  51. package/dist/index.d.ts +5 -3
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +5 -3
  54. package/dist/index.js.map +1 -1
  55. package/dist/overview.d.ts +52 -0
  56. package/dist/overview.d.ts.map +1 -0
  57. package/dist/overview.js +61 -0
  58. package/dist/overview.js.map +1 -0
  59. package/dist/overview.test.d.ts +8 -0
  60. package/dist/overview.test.d.ts.map +1 -0
  61. package/dist/overview.test.js +48 -0
  62. package/dist/overview.test.js.map +1 -0
  63. package/dist/promote.test.d.ts +15 -0
  64. package/dist/promote.test.d.ts.map +1 -0
  65. package/dist/promote.test.js +104 -0
  66. package/dist/promote.test.js.map +1 -0
  67. package/dist/publish.d.ts +2 -17
  68. package/dist/publish.d.ts.map +1 -1
  69. package/dist/publish.js +4 -49
  70. package/dist/publish.js.map +1 -1
  71. package/dist/search.d.ts +34 -0
  72. package/dist/search.d.ts.map +1 -0
  73. package/dist/search.js +79 -0
  74. package/dist/search.js.map +1 -0
  75. package/dist/search.test.d.ts +2 -0
  76. package/dist/search.test.d.ts.map +1 -0
  77. package/dist/search.test.js +53 -0
  78. package/dist/search.test.js.map +1 -0
  79. package/dist/server.d.ts.map +1 -1
  80. package/dist/server.js +228 -23
  81. package/dist/server.js.map +1 -1
  82. package/dist/store.d.ts +43 -63
  83. package/dist/store.d.ts.map +1 -1
  84. package/dist/store.js +0 -368
  85. package/dist/store.js.map +1 -1
  86. package/dist/store.test.d.ts +1 -2
  87. package/dist/store.test.d.ts.map +1 -1
  88. package/dist/store.test.js +148 -106
  89. package/dist/store.test.js.map +1 -1
  90. package/dist/ticket-doc.d.ts +74 -5
  91. package/dist/ticket-doc.d.ts.map +1 -1
  92. package/dist/ticket-doc.js +229 -15
  93. package/dist/ticket-doc.js.map +1 -1
  94. package/dist/types.d.ts +115 -28
  95. package/dist/types.d.ts.map +1 -1
  96. package/dist/types.js.map +1 -1
  97. package/package.json +1 -1
  98. package/skill/SKILL.md +153 -40
  99. package/src/asks.test.ts +355 -0
  100. package/src/check.test.ts +328 -0
  101. package/src/check.ts +497 -0
  102. package/src/claim-io.ts +401 -0
  103. package/src/claim.test.ts +301 -71
  104. package/src/claim.ts +238 -81
  105. package/src/cli.ts +740 -131
  106. package/src/file-store.ts +572 -254
  107. package/src/git-serve.test.ts +240 -0
  108. package/src/git-serve.ts +595 -0
  109. package/src/git.ts +141 -0
  110. package/src/id.ts +68 -0
  111. package/src/inbox.ts +77 -0
  112. package/src/index.ts +4 -2
  113. package/src/overview.test.ts +52 -0
  114. package/src/overview.ts +105 -0
  115. package/src/promote.test.ts +143 -0
  116. package/src/publish.ts +6 -53
  117. package/src/search.test.ts +64 -0
  118. package/src/search.ts +105 -0
  119. package/src/server.ts +232 -21
  120. package/src/store.test.ts +166 -116
  121. package/src/store.ts +46 -444
  122. package/src/ticket-doc.ts +284 -21
  123. package/src/types.ts +120 -28
  124. package/ui/dist/assets/index-BjsorZOU.js +229 -0
  125. package/ui/dist/assets/index-CoKCUYic.css +1 -0
  126. package/ui/dist/index.html +2 -2
  127. package/ui/dist/assets/index-COunM-QN.css +0 -1
  128. package/ui/dist/assets/index-D4homvrQ.js +0 -229
package/README.md CHANGED
@@ -40,16 +40,23 @@ nothing reads — which is exactly what happened the first time this tried.
40
40
  ## Use
41
41
 
42
42
  ```bash
43
- task add "Wire up webhook retries" --tags api --milestone launch
43
+ task add "Wire up webhook retries" --tags api --goal launch
44
44
  task list # open tasks, board order
45
- task list --needs-human # what's blocked on a person
46
- task start 1 # in_progress
47
- task done 1 # done
45
+ task ask 1 "Mint the API key" # file what a person owes the ticket
46
+ task resolve 1 1 # …and check it off once it's done
47
+ task inbox # every open ask on in-progress work, repo-wide
48
+ task search "webhook" # find tickets by what they say — titles,
49
+ # descriptions, comments and asks, with snippets
50
+ task move 1 in_progress # status changes all go through move; done is
51
+ # refused while the ticket has open asks
52
+ task promote 1 # backlog → todo, the human "build this" call;
53
+ # blocked tickets promote with the hold reported
48
54
  task link 2 --blocked-by 1 # dependency, visible from both tasks
49
55
  task update 1 --pr https://github.com/you/repo/pull/42
50
56
  task comment 1 "shipped in #42" --author claude
51
57
  task boards # every board in the repo, with prefixes
52
58
  task archive --all # move finished tickets to .task/archive/
59
+ task check # lint the board files; --fix repairs the mechanical part
53
60
  task serve # opens the kanban + table UI, live
54
61
  task publish # same board, at a URL you can open on a phone
55
62
  ```
@@ -66,24 +73,26 @@ task claim --release TAS-21 # abandon a claim cleanly
66
73
  ```
67
74
 
68
75
  - **The claim is the work branch.** `task claim TAS-21` branches
69
- `task/claim/tas-21` off origin's default branch, flips the ticket to
76
+ `task/claim/tas-x7k4m` off origin's default branch, flips the ticket to
70
77
  `in_progress` as the branch's first commit, and pushes. The branch existing
71
78
  on origin *is* the claim — nothing side-band to clean up, because the branch
72
79
  was needed anyway and dies at merge.
73
80
  - **The namespace is yours.** `task/claim/` is only the default —
74
- `"claimPrefix"` in `.task/config.json` moves the whole namespace, and it
75
- lives in the committed config on purpose: every worker and every clone must
76
- agree on what "claimed" looks like, or there is no lock. If your workers are
77
- Claude Code cloud sessions, set `"claimPrefix": "claude/task/"` — that
78
- runtime can push `claude/`-prefixed branches without extra ceremony. Pick
79
- the value before the first claim; renaming later strands in-flight claims.
81
+ `claims.branchPrefix` in `.task/config.json` moves the whole namespace, and
82
+ it lives in the committed config on purpose: every worker and every clone
83
+ must agree on what "claimed" looks like, or there is no lock. If your
84
+ workers are Claude Code cloud sessions, set
85
+ `"claims": { "branchPrefix": "claude/task/" }` that runtime can push
86
+ `claude/`-prefixed branches without extra ceremony. Pick the value before
87
+ the first claim; renaming later strands in-flight claims.
80
88
  - **Atomic by construction.** The push only succeeds if the branch doesn't
81
89
  exist yet (a compare-and-swap on the ref), so two concurrent claimers of the
82
90
  same ticket get exactly one winner. Exit codes are the contract: `0` claimed,
83
91
  `1` already claimed (pick the next ticket), `2` not claimable — not `todo`,
84
- blocked, `--needs-human`, or a dirty working tree.
92
+ blocked, or a dirty working tree. Open asks don't gate a claim: an agent
93
+ can work the code while a person owes the ticket something.
85
94
  - **The lifecycle rides the branch.** Claim = `in_progress`; before the PR is
86
- marked ready, `task done` + `task update --pr` on the branch; the merge lands
95
+ marked ready, `task move <id> done` + `task update --pr` on the branch; the merge lands
87
96
  code and `done` together, and the branch auto-deletes. Between claim and
88
97
  merge the default branch still says `todo` — the branch is the truth about
89
98
  in-flight work, and `git ls-remote origin 'task/claim/*'` (or your
@@ -91,9 +100,40 @@ task claim --release TAS-21 # abandon a claim cleanly
91
100
  - **Claim before you work — humans too.** The same verb covers manual work:
92
101
  run `task claim <id>` before starting a ticket yourself and any scheduled
93
102
  agent will skip it. `task list --claimable` shows `todo` tickets in position
94
- order minus blocked, needs-human, and already-claimed — the top entry is
95
- what an autonomous worker takes next, which makes column order your priority
96
- queue.
103
+ order minus blocked and already-claimed — the top entry is what an
104
+ autonomous worker takes next, which makes column order your priority queue.
105
+
106
+ ## Git, from the board
107
+
108
+ Board edits — a drag, a checkbox, a new ticket — are plain writes into your
109
+ working tree; nothing commits behind your back. `task serve` shows you that
110
+ truth and gives it verbs: the header grows a branch chip with the current
111
+ branch, a dirty-count badge, and ahead/behind, cards carry an "uncommitted
112
+ edits" dot, and the chip's panel commits, switches branches, and opens PRs.
113
+
114
+ - **Commits are board-scoped.** "Commit board changes" runs a pathspec-scoped
115
+ commit of each board's `.task/` directory — your half-finished code stays
116
+ dirty and stays out. Messages default to `chore(board): <ticket ids>`.
117
+ - **Context decides where the commit goes.** On a feature or claim branch it
118
+ lands right there — ticket edits usually belong to that branch's PR. On the
119
+ default branch the flow is a fresh board branch plus a PR, so board edits
120
+ never land on main from a click.
121
+ - **PRs: files remember, git informs.** Opening a PR uses `gh` when it's on
122
+ your PATH and falls back to GitHub's compare page when it isn't. A created
123
+ PR's URL is written into the `prs:` frontmatter of every ticket the branch
124
+ touches — the file stays canonical — and, with `gh`, ticket chips gain
125
+ display-only draft/open/merged state resolved live from the branch.
126
+ - **Branch switching is a real checkout** — distinct from the hosted board's
127
+ `?ref=` preview — and refuses while tracked files outside `.task/` are
128
+ dirty, so a click in a board can't carry your code somewhere else.
129
+ - **Dragging a claimed ticket out of In Progress releases the claim.** That's
130
+ `task claim --release` wearing a drop: a confirm explains that the claim
131
+ branch and its commits go away, and the move happens only if the branch
132
+ deletion succeeds.
133
+ - **It disappears when it can't work.** No git, no `origin`, the hosted board,
134
+ the static snapshot: no git surface at all, no errors. Writes are guarded by
135
+ a same-origin check, so a webpage in the same browser can't aim POSTs at
136
+ your board.
97
137
 
98
138
  ## From anywhere
99
139
 
@@ -164,9 +204,12 @@ jobs:
164
204
  else await github.rest.issues.createComment({ ...context.repo, issue_number: context.issue.number, body })
165
205
  ```
166
206
 
167
- - Ids are `PREFIX-12` or just `12`; the prefix is the first three letters of
207
+ - Ids are `PREFIX-x7k4m` or just `x7k4m` a random 5-character key minted
208
+ at `task add`, so two branches that have never seen each other can never
209
+ mint the same id; any unique prefix of a key resolves git-style
210
+ (`task show x7`). The board prefix is the first three letters of
168
211
  the project name ("phone" → `PHO-1`), or whatever `task init --prefix` says.
169
- - Ids route by prefix: a bare `12` means the nearest board, while `TAS-12`
212
+ - Ids route by prefix: a bare `x7k4m` means the nearest board, while `TAS-x7k4m`
170
213
  reaches the TAS board from anywhere in the monorepo. An unknown or ambiguous
171
214
  prefix fails loudly instead of guessing. `task boards` lists every board —
172
215
  prefix, name, path, open count — with a `*` on the one commands target from
@@ -178,15 +221,20 @@ jobs:
178
221
  reserved forever. `task archive --all` sweeps everything finished;
179
222
  `task unarchive <id>` puts one back.
180
223
  - Statuses: `backlog` `todo` `in_progress` `done` `canceled`.
181
- - A task carries tags, at most one milestone, and a `--needs-human` flag for
182
- work an agent can't finish alone. `--tag a,b` matches either tag.
224
+ - A task carries tags, at most one goal, and **asks** checklist items
225
+ a person owes it (`task ask`), each one file under `tickets/<key>/asks/`.
226
+ Open asks derive the amber needs-human badge, feed `task inbox` (the
227
+ repo-wide "what do I owe NOW" view — in-progress work only, and a ticket
228
+ claimed on a branch counts, its asks read from the branch), and gate
229
+ `done`: a ticket finishes when nobody owes it anything. `--tag a,b`
230
+ matches either tag.
183
231
  - `task link A --blocked-by B` marks a dependency. It's one relation seen from
184
232
  both ends — B's page says it blocks A — and the board badges A as blocked
185
233
  until B is done or canceled.
186
234
  - `--pr <url>` attaches a pull request to a task (`--prs` replaces the list);
187
235
  attached PRs show in the task's rail and as a count on its card. The elegant
188
236
  loop is an agent convention, not a webhook: put the id in the PR title
189
- (`[TAS-6] …`) and run `task update TAS-6 --pr <url>` when opening the PR —
237
+ (`[TAS-x7k4m] …`) and run `task update TAS-x7k4m --pr <url>` when opening the PR —
190
238
  the shipped skill tells agents to do exactly that.
191
239
  - Every task has **Copy link** — the icon next to its title, or right-click /
192
240
  long-press any card or row — so handing a ticket to an agent is one paste.
@@ -205,8 +253,9 @@ jobs:
205
253
  in the header. Run it inside a package and you get just that board. Every
206
254
  other command stays scoped to the nearest `.task/`.
207
255
  - Boards from before 0.6 stored their state as a committed SQLite database;
208
- those keep working as-is, and `task migrate` moves one onto text files
209
- (the database stays on disk as an ignored backup).
256
+ run `task migrate` once on `@nickmeriano/task@0.6` to move one onto text
257
+ files (the database stays on disk as an ignored backup) — newer versions
258
+ read only the text format.
210
259
 
211
260
  ## How it's built
212
261
 
@@ -214,8 +263,7 @@ jobs:
214
263
  block — reviewable in a PR, mergeable by git, editable by hand. Comments are
215
264
  one file each (append-only merges cleanly), and the `blocks`/`blocked-by`
216
265
  relation is stored on one side only, so its two views can't disagree.
217
- Legacy boards read through Node's built-in `node:sqlite` (Node ≥ 22.13) —
218
- nothing to compile, so `npx` starts in about a second.
266
+ Nothing to compile, so `npx` starts in about a second.
219
267
  - **Realtime is a file watch.** `task serve` is one `node:http` process: the
220
268
  prebuilt UI, a JSON API, and a server-sent-events stream that pings whenever
221
269
  anything writes to `.task/` — this UI, another terminal, an agent mid-run.
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Asks (TAS-38): the checklist a person owes a ticket, and everything derived
3
+ * from it.
4
+ *
5
+ * 1. An ask is one file under tickets/<key>/asks/, comment-shaped; `needsHuman`
6
+ * is derived from open asks, never stored.
7
+ * 2. Done is gated: open asks refuse the move, resolving clears it, canceled
8
+ * voids without ceremony. A finished ticket can't start owing again —
9
+ * addAsk/reopen are refused on done/canceled.
10
+ * 3. Ordinals are creation-order positions — stable across resolution, the
11
+ * handle `task resolve <id> <n>` takes.
12
+ * 4. `task inbox` answers "what do I owe NOW": open asks on effectively
13
+ * in-progress tickets — file status, or a live claim branch, whose ask
14
+ * files are read from the branch itself.
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=asks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asks.test.d.ts","sourceRoot":"","sources":["../src/asks.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Asks (TAS-38): the checklist a person owes a ticket, and everything derived
3
+ * from it.
4
+ *
5
+ * 1. An ask is one file under tickets/<key>/asks/, comment-shaped; `needsHuman`
6
+ * is derived from open asks, never stored.
7
+ * 2. Done is gated: open asks refuse the move, resolving clears it, canceled
8
+ * voids without ceremony. A finished ticket can't start owing again —
9
+ * addAsk/reopen are refused on done/canceled.
10
+ * 3. Ordinals are creation-order positions — stable across resolution, the
11
+ * handle `task resolve <id> <n>` takes.
12
+ * 4. `task inbox` answers "what do I owe NOW": open asks on effectively
13
+ * in-progress tickets — file status, or a live claim branch, whose ask
14
+ * files are read from the branch itself.
15
+ */
16
+ import assert from "node:assert/strict";
17
+ import { test } from "node:test";
18
+ import { execFile, execFileSync } from "node:child_process";
19
+ import { existsSync, mkdtempSync, readFileSync, readdirSync, rmSync } from "node:fs";
20
+ import { tmpdir } from "node:os";
21
+ import { join } from "node:path";
22
+ import { fileURLToPath } from "node:url";
23
+ import { initProject } from "./file-store.js";
24
+ const CLI = fileURLToPath(new URL("./cli.ts", import.meta.url));
25
+ function tempDir() {
26
+ const dir = mkdtempSync(join(tmpdir(), "task-asks-test-"));
27
+ process.on("exit", () => rmSync(dir, { recursive: true, force: true }));
28
+ return dir;
29
+ }
30
+ function cli(cwd, ...args) {
31
+ return new Promise((resolve) => {
32
+ execFile(process.execPath, ["--experimental-strip-types", CLI, ...args], { cwd }, (error, stdout, stderr) => {
33
+ resolve({ code: error ? (error.code ?? 1) : 0, stdout, stderr });
34
+ });
35
+ });
36
+ }
37
+ // ── The store-level contract ─────────────────────────────────────────────────
38
+ test("an ask is a file; needsHuman derives from it and resolution round-trips", () => {
39
+ const dir = tempDir();
40
+ const store = initProject(dir, { name: "ask board", prefix: "ASK" });
41
+ const task = store.create({ title: "Wire the webhook", status: "in_progress" });
42
+ assert.equal(store.get(task.key).needsHuman, false);
43
+ const ask = store.addAsk(task.key, "Mint the API token and add it to secrets", "claude");
44
+ assert.equal(ask.ordinal, 1);
45
+ assert.equal(ask.resolvedAt, null);
46
+ // One file, comment-shaped, under asks/ — mergeable by construction.
47
+ const dirPath = join(dir, ".task", "tickets", task.key, "asks");
48
+ const files = readdirSync(dirPath);
49
+ assert.equal(files.length, 1);
50
+ const text = readFileSync(join(dirPath, files[0]), "utf8");
51
+ assert.match(text, /^---\nauthor: "claude"\ncreated: /);
52
+ assert.match(text, /Mint the API token/);
53
+ const withAsk = store.get(task.key);
54
+ assert.equal(withAsk.needsHuman, true);
55
+ assert.equal(withAsk.asks.length, 1);
56
+ const resolved = store.resolveAsk(task.key, "1", "nick");
57
+ assert.equal(resolved.resolvedBy, "nick");
58
+ assert.notEqual(resolved.resolvedAt, null);
59
+ assert.equal(store.get(task.key).needsHuman, false);
60
+ assert.match(readFileSync(join(dirPath, files[0]), "utf8"), /resolved_by: "nick"/);
61
+ const reopened = store.reopenAsk(task.key, resolved.id);
62
+ assert.equal(reopened.resolvedAt, null);
63
+ assert.equal(store.get(task.key).needsHuman, true);
64
+ store.close();
65
+ });
66
+ test("ordinals are creation order and stay put as asks resolve", () => {
67
+ const dir = tempDir();
68
+ const store = initProject(dir, { name: "ask board", prefix: "ASK" });
69
+ const task = store.create({ title: "Ship it", status: "in_progress" });
70
+ store.addAsk(task.key, "First owed thing", "claude");
71
+ store.addAsk(task.key, "Second owed thing", "claude");
72
+ store.resolveAsk(task.key, "1", "nick");
73
+ const asks = store.asks(task.key);
74
+ assert.deepEqual(asks.map((a) => a.ordinal), [1, 2]);
75
+ assert.equal(asks[0].resolvedAt !== null, true);
76
+ assert.equal(asks[1].text, "Second owed thing");
77
+ // The needs-human filter matches the derived flag.
78
+ assert.deepEqual(store.list({ needsHuman: true }).map((t) => t.key), [task.key]);
79
+ store.close();
80
+ });
81
+ test("done is gated on zero open asks; canceled voids them", () => {
82
+ const dir = tempDir();
83
+ const store = initProject(dir, { name: "ask board", prefix: "ASK" });
84
+ const task = store.create({ title: "Gated", status: "in_progress" });
85
+ store.addAsk(task.key, "Approve the cutover window", "claude");
86
+ assert.throws(() => store.update(task.key, { status: "done" }), /1 open ask.*done means nobody owes anything/s);
87
+ // Canceling is allowed with the asks still open — a dead ticket's asks die
88
+ // with it — and once canceled, no new debt can accrue.
89
+ store.update(task.key, { status: "canceled" });
90
+ assert.throws(() => store.addAsk(task.key, "Too late", "claude"), /is canceled/);
91
+ store.update(task.key, { status: "in_progress" });
92
+ store.resolveAsk(task.key, "1", "nick");
93
+ const done = store.update(task.key, { status: "done" });
94
+ assert.equal(done.status, "done");
95
+ // A finished ticket can't quietly start owing things again.
96
+ assert.throws(() => store.addAsk(task.key, "One more thing", "claude"), /is done/);
97
+ assert.throws(() => store.reopenAsk(task.key, "1"), /reopening an ask/);
98
+ store.close();
99
+ });
100
+ // ── The CLI surface ──────────────────────────────────────────────────────────
101
+ test("task ask / resolve / show: the full loop, exit codes and ordinals", async () => {
102
+ const dir = tempDir();
103
+ initProject(dir, { name: "cli board", prefix: "CLI" }).close();
104
+ const created = await cli(dir, "add", "Needs a person", "--status", "in_progress", "--json");
105
+ const id = JSON.parse(created.stdout).task.id;
106
+ const asked = await cli(dir, "ask", id, "Run setup.sh once the token exists", "--author", "claude");
107
+ assert.equal(asked.code, 0, asked.stderr);
108
+ assert.ok(asked.stdout.includes(`asked on ${id} [1]`), asked.stdout);
109
+ const shown = await cli(dir, "show", id, "--json");
110
+ const { task } = JSON.parse(shown.stdout);
111
+ assert.equal(task.needsHuman, true);
112
+ assert.equal(task.asks[0].author, "claude");
113
+ // Done refuses while the ask is open — the gate speaks CLI too.
114
+ const blocked = await cli(dir, "move", id, "done");
115
+ assert.equal(blocked.code, 1);
116
+ assert.match(blocked.stderr, /open ask/);
117
+ const resolved = await cli(dir, "resolve", id, "1", "--comment", "done, it's in 1Password", "--author", "nick");
118
+ assert.equal(resolved.code, 0, resolved.stderr);
119
+ assert.ok(resolved.stdout.includes(`resolved ${id} [1]`), resolved.stdout);
120
+ assert.match(resolved.stdout, /last open ask/);
121
+ // The note landed as an attributed comment naming the ask.
122
+ const detail = await cli(dir, "show", id, "--json");
123
+ const { comments } = JSON.parse(detail.stdout);
124
+ assert.equal(comments.length, 1);
125
+ assert.equal(comments[0].author, "nick");
126
+ assert.match(comments[0].body, /Resolved ask \[1\].*1Password/);
127
+ assert.equal((await cli(dir, "move", id, "done")).code, 0);
128
+ assert.equal((await cli(dir, "resolve", id, "9")).code, 1);
129
+ });
130
+ test("task add --ask files asks at creation, commas and all", async () => {
131
+ const dir = tempDir();
132
+ initProject(dir, { name: "cli board", prefix: "CLI" }).close();
133
+ const added = await cli(dir, "add", "Born owing", "--status", "todo", "--ask", "Approve the plan, then the budget", "--ask", "Add STRIPE_SECRET_KEY to the worker", "--json");
134
+ assert.equal(added.code, 0, added.stderr);
135
+ const { task } = JSON.parse(added.stdout);
136
+ // One ask per --ask, verbatim — a comma never splits an ask in two.
137
+ assert.deepEqual(task.asks.map((a) => a.text), ["Approve the plan, then the budget", "Add STRIPE_SECRET_KEY to the worker"]);
138
+ assert.equal(task.needsHuman, true);
139
+ });
140
+ test("inbox is in-progress only: todo asks wait for their claim", async () => {
141
+ const dir = tempDir();
142
+ const store = initProject(dir, { name: "inbox board", prefix: "INB" });
143
+ const active = store.create({ title: "Being worked", status: "in_progress" });
144
+ const queued = store.create({ title: "Waiting its turn", status: "todo" });
145
+ store.addAsk(active.key, "Upgrade the org to Pro", "claude");
146
+ store.addAsk(queued.key, "Decide pricing", "claude");
147
+ store.close();
148
+ // Not a git repo — the resolver degrades silently to file truth.
149
+ const result = await cli(dir, "inbox", "--json");
150
+ assert.equal(result.code, 0, result.stderr);
151
+ const { inbox } = JSON.parse(result.stdout);
152
+ assert.deepEqual(inbox.map((e) => e.task.key), [active.key]);
153
+ assert.equal(inbox[0].claim, null);
154
+ assert.equal(inbox[0].asks[0].text, "Upgrade the org to Pro");
155
+ });
156
+ // ── The claim-branch read (TAS-26's core) ────────────────────────────────────
157
+ function sh(cwd, ...args) {
158
+ return execFileSync(args[0], args.slice(1), { cwd, encoding: "utf8" }).trim();
159
+ }
160
+ test("a claimed ticket's asks reach the inbox from its branch", async () => {
161
+ const home = tempDir();
162
+ const bare = join(home, "origin.git");
163
+ sh(home, "git", "init", "--quiet", "--bare", "-b", "main", bare);
164
+ const seed = join(home, "seed");
165
+ sh(home, "git", "clone", "--quiet", bare, seed);
166
+ sh(seed, "git", "config", "user.name", "Test");
167
+ sh(seed, "git", "config", "user.email", "test@example.com");
168
+ const store = initProject(seed, { name: "claim inbox", prefix: "CIN" });
169
+ const key = store.create({ title: "Agent work with a human side", status: "todo" }).key;
170
+ const branch = `task/claim/cin-${key}`;
171
+ store.close();
172
+ sh(seed, "git", "add", "-A");
173
+ sh(seed, "git", "commit", "--quiet", "-m", "board");
174
+ sh(seed, "git", "push", "--quiet", "-u", "origin", "main");
175
+ // Worker: claim (flips the ticket on the branch), file an ask mid-run, push.
176
+ const worker = join(home, "worker");
177
+ sh(home, "git", "clone", "--quiet", bare, worker);
178
+ sh(worker, "git", "config", "user.name", "Worker");
179
+ sh(worker, "git", "config", "user.email", "worker@example.com");
180
+ assert.equal((await cli(worker, "claim", key)).code, 0);
181
+ assert.equal((await cli(worker, "ask", `CIN-${key}`, "Create the OAuth app in the dashboard", "--author", "claude")).code, 0);
182
+ sh(worker, "git", "add", "-A");
183
+ sh(worker, "git", "commit", "--quiet", "-m", "ask");
184
+ sh(worker, "git", "push", "--quiet", "origin", branch);
185
+ // Owner, on a fresh clone of main, where the ticket still reads `todo` and
186
+ // has no ask files at all: the inbox says what the claim branch knows.
187
+ const owner = join(home, "owner");
188
+ sh(home, "git", "clone", "--quiet", bare, owner);
189
+ sh(owner, "git", "config", "user.name", "Nick");
190
+ sh(owner, "git", "config", "user.email", "nick@example.com");
191
+ assert.equal(existsSync(join(owner, ".task", "tickets", key, "asks")), false);
192
+ const result = await cli(owner, "inbox", "--json");
193
+ assert.equal(result.code, 0, result.stderr);
194
+ const { inbox } = JSON.parse(result.stdout);
195
+ assert.equal(inbox.length, 1);
196
+ assert.equal(inbox[0].task.status, "todo"); // file truth, kept honest
197
+ assert.equal(inbox[0].claim?.branch, branch);
198
+ assert.deepEqual(inbox[0].asks.map((a) => a.text), ["Create the OAuth app in the dashboard"]);
199
+ // The claim owns the ticket's asks, so the owner's writes land on the
200
+ // branch as pushed commits — the checkout never switches, the working
201
+ // tree never grows an ask file.
202
+ const resolved = await cli(owner, "resolve", `CIN-${key}`, "1", "--author", "nick");
203
+ assert.equal(resolved.code, 0, resolved.stderr);
204
+ assert.ok(resolved.stdout.includes(`committed and pushed to ${branch}`), resolved.stdout);
205
+ assert.equal(existsSync(join(owner, ".task", "tickets", key, "asks")), false);
206
+ assert.equal(sh(owner, "git", "rev-parse", "--abbrev-ref", "HEAD"), "main");
207
+ // A third clone reads the resolution straight off origin's branch.
208
+ const verify = join(home, "verify");
209
+ sh(home, "git", "clone", "--quiet", bare, verify);
210
+ sh(verify, "git", "fetch", "--quiet", "origin", branch);
211
+ const askFile = sh(verify, "git", "ls-tree", "--name-only", `FETCH_HEAD:.task/tickets/${key}/asks`);
212
+ assert.match(sh(verify, "git", "show", `FETCH_HEAD:.task/tickets/${key}/asks/${askFile}`), /resolved_by: "nick"/);
213
+ const cleared = await cli(owner, "inbox", "--json");
214
+ assert.equal(JSON.parse(cleared.stdout).inbox.length, 0);
215
+ // Adding to a claimed ticket routes to the branch too — the worker's done
216
+ // gate has to see debt the owner files mid-claim.
217
+ const added = await cli(owner, "ask", `CIN-${key}`, "Also rotate the old key", "--author", "nick");
218
+ assert.equal(added.code, 0, added.stderr);
219
+ assert.ok(added.stdout.includes(`committed and pushed to ${branch}`), added.stdout);
220
+ assert.equal(existsSync(join(owner, ".task", "tickets", key, "asks")), false);
221
+ sh(verify, "git", "fetch", "--quiet", "origin", branch);
222
+ assert.equal(sh(verify, "git", "ls-tree", "--name-only", `FETCH_HEAD:.task/tickets/${key}/asks`).split("\n").length, 2);
223
+ const again = await cli(owner, "inbox", "--json");
224
+ const entries = JSON.parse(again.stdout).inbox;
225
+ assert.deepEqual(entries[0].asks.map((a) => a.text), ["Also rotate the old key"]);
226
+ // And the worker's next tick simply pulls its branch and has everything.
227
+ sh(worker, "git", "pull", "--quiet", "origin", branch);
228
+ const workerView = await cli(worker, "show", `CIN-${key}`, "--json");
229
+ const workerAsks = JSON.parse(workerView.stdout).task.asks;
230
+ assert.deepEqual(workerAsks.map((a) => [a.text, a.resolvedBy]), [["Create the OAuth app in the dashboard", "nick"], ["Also rotate the old key", null]]);
231
+ });
232
+ test("branch writes hold up in shallow clones and worktrees", async () => {
233
+ const home = tempDir();
234
+ const bare = join(home, "origin.git");
235
+ sh(home, "git", "init", "--quiet", "--bare", "-b", "main", bare);
236
+ const seed = join(home, "seed");
237
+ sh(home, "git", "clone", "--quiet", bare, seed);
238
+ sh(seed, "git", "config", "user.name", "Test");
239
+ sh(seed, "git", "config", "user.email", "test@example.com");
240
+ const store = initProject(seed, { name: "envs board", prefix: "ENV" });
241
+ const key = store.create({ title: "Worked while owed", status: "todo" }).key;
242
+ const branch = `task/claim/env-${key}`;
243
+ store.close();
244
+ sh(seed, "git", "add", "-A");
245
+ sh(seed, "git", "commit", "--quiet", "-m", "board");
246
+ sh(seed, "git", "push", "--quiet", "-u", "origin", "main");
247
+ assert.equal((await cli(seed, "claim", key)).code, 0);
248
+ assert.equal((await cli(seed, "ask", `ENV-${key}`, "Bless the rollout", "--author", "claude")).code, 0);
249
+ sh(seed, "git", "add", "-A");
250
+ sh(seed, "git", "commit", "--quiet", "-m", "ask");
251
+ sh(seed, "git", "push", "--quiet", "origin", branch);
252
+ // Shallow clone — what CI checkouts default to. The plumbing must build
253
+ // its commit from a fetched claim tip whose history it doesn't have.
254
+ const shallow = join(home, "shallow");
255
+ sh(home, "git", "clone", "--quiet", "--depth", "1", `file://${bare}`, shallow);
256
+ sh(shallow, "git", "config", "user.name", "Nick");
257
+ sh(shallow, "git", "config", "user.email", "nick@example.com");
258
+ const resolved = await cli(shallow, "resolve", `ENV-${key}`, "1", "--author", "nick");
259
+ assert.equal(resolved.code, 0, resolved.stderr);
260
+ assert.ok(resolved.stdout.includes(`committed and pushed to ${branch}`), resolved.stdout);
261
+ // Worktree — refs shared with the main checkout, index elsewhere.
262
+ const full = join(home, "full");
263
+ sh(home, "git", "clone", "--quiet", bare, full);
264
+ sh(full, "git", "config", "user.name", "Nick");
265
+ sh(full, "git", "config", "user.email", "nick@example.com");
266
+ const worktree = join(home, "wt");
267
+ sh(full, "git", "worktree", "add", "--quiet", "--detach", worktree);
268
+ const added = await cli(worktree, "ask", `ENV-${key}`, "Sign the SOC2 form", "--author", "nick");
269
+ assert.equal(added.code, 0, added.stderr);
270
+ assert.ok(added.stdout.includes(`committed and pushed to ${branch}`), added.stdout);
271
+ // Origin's branch carries both writes; the checkout that made them doesn't.
272
+ sh(full, "git", "fetch", "--quiet", "origin", branch);
273
+ const files = sh(full, "git", "ls-tree", "--name-only", `FETCH_HEAD:.task/tickets/${key}/asks`).split("\n");
274
+ assert.equal(files.length, 2);
275
+ assert.equal(existsSync(join(shallow, ".task", "tickets", key, "asks")), false);
276
+ assert.equal(existsSync(join(worktree, ".task", "tickets", key, "asks")), false);
277
+ });
278
+ //# sourceMappingURL=asks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asks.test.js","sourceRoot":"","sources":["../src/asks.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * `task check` — lint the board files.
3
+ *
4
+ * A database enforced its constraints at write time; a text store has two
5
+ * extra write paths no CLI code ever sees — git merges and hand-edits — so
6
+ * validation has to be a lint you can run. This strictly parses every ticket
7
+ * comment and goal file on every board at or below the check root (the same
8
+ * walk `task serve` does) and reports what would degrade or throw at read
9
+ * time: files that don't parse, invalid timestamps, dangling `blocked_by`
10
+ * references (one branch deleted a ticket another branch linked to), `goal:`
11
+ * refs naming a goal that doesn't exist, tickets duplicated between the board
12
+ * and the archive, unknown frontmatter keys, and formatting drift from the
13
+ * canonical serialization. Retired pre-0.8 spellings (`milestone:`,
14
+ * `claimPrefix`) are refused by the parsers with the rename in the error —
15
+ * this lint just surfaces those messages; there is no migration machinery.
16
+ *
17
+ * The mechanical repairs — pruning dangling or self references, deduping and
18
+ * sorting `blocked_by`, rewriting a file into canonical form — are applied by
19
+ * `--fix`. Anything that needs a decision (a status that isn't a status, a
20
+ * missing title) is reported and left alone. Cheap enough for pre-commit and
21
+ * CI, which is where merge-introduced drift gets caught.
22
+ */
23
+ export interface CheckIssue {
24
+ /** Board id relative to the check root — "." for the root board. */
25
+ board: string;
26
+ /** File (or directory) the problem is in, relative to the check root. */
27
+ file: string;
28
+ message: string;
29
+ /** `task check --fix` repairs this mechanically. */
30
+ fixable: boolean;
31
+ }
32
+ export interface CheckResult {
33
+ boards: number;
34
+ /** Ticket and comment files inspected. */
35
+ files: number;
36
+ issues: CheckIssue[];
37
+ /** Files rewritten, relative to the check root. Empty unless fixing. */
38
+ fixed: string[];
39
+ }
40
+ /** The boards `task check` covers from `cwd` — the same set `task serve` has. */
41
+ export declare function checkRoot(cwd: string): string;
42
+ export declare function checkBoards(root: string, fix: boolean): CheckResult;
43
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AA0CH,MAAM,WAAW,UAAU;IACzB,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,wEAAwE;IACxE,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,iFAAiF;AACjF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AA2BD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,WAAW,CAwBnE"}