@nickmeriano/task 0.8.0 → 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.
- package/README.md +65 -22
- package/dist/asks.test.d.ts +17 -0
- package/dist/asks.test.d.ts.map +1 -0
- package/dist/asks.test.js +278 -0
- package/dist/asks.test.js.map +1 -0
- package/dist/check.d.ts +3 -2
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +99 -60
- package/dist/check.js.map +1 -1
- package/dist/check.test.js +99 -60
- package/dist/check.test.js.map +1 -1
- package/dist/claim-io.d.ts +73 -0
- package/dist/claim-io.d.ts.map +1 -0
- package/dist/claim-io.js +344 -0
- package/dist/claim-io.js.map +1 -0
- package/dist/claim.d.ts +21 -22
- package/dist/claim.d.ts.map +1 -1
- package/dist/claim.js +58 -83
- package/dist/claim.js.map +1 -1
- package/dist/claim.test.d.ts +2 -2
- package/dist/claim.test.js +111 -94
- package/dist/claim.test.js.map +1 -1
- package/dist/cli.js +241 -64
- package/dist/cli.js.map +1 -1
- package/dist/file-store.d.ts +70 -24
- package/dist/file-store.d.ts.map +1 -1
- package/dist/file-store.js +319 -141
- package/dist/file-store.js.map +1 -1
- package/dist/git-serve.d.ts +183 -0
- package/dist/git-serve.d.ts.map +1 -0
- package/dist/git-serve.js +503 -0
- package/dist/git-serve.js.map +1 -0
- package/dist/git-serve.test.d.ts +16 -0
- package/dist/git-serve.test.d.ts.map +1 -0
- package/dist/git-serve.test.js +183 -0
- package/dist/git-serve.test.js.map +1 -0
- package/dist/git.d.ts +65 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +114 -0
- package/dist/git.js.map +1 -0
- package/dist/id.d.ts +39 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +67 -0
- package/dist/id.js.map +1 -0
- package/dist/inbox.d.ts +41 -0
- package/dist/inbox.d.ts.map +1 -0
- package/dist/inbox.js +56 -0
- package/dist/inbox.js.map +1 -0
- package/dist/overview.d.ts +9 -0
- package/dist/overview.d.ts.map +1 -1
- package/dist/overview.js +19 -11
- package/dist/overview.js.map +1 -1
- package/dist/overview.test.js +6 -5
- package/dist/overview.test.js.map +1 -1
- package/dist/promote.test.d.ts +3 -2
- package/dist/promote.test.d.ts.map +1 -1
- package/dist/promote.test.js +29 -31
- package/dist/promote.test.js.map +1 -1
- package/dist/publish.d.ts +2 -17
- package/dist/publish.d.ts.map +1 -1
- package/dist/publish.js +4 -49
- package/dist/publish.js.map +1 -1
- package/dist/search.d.ts +3 -1
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +15 -2
- package/dist/search.js.map +1 -1
- package/dist/search.test.js +9 -9
- package/dist/search.test.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +218 -21
- package/dist/server.js.map +1 -1
- package/dist/store.d.ts +28 -14
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js.map +1 -1
- package/dist/store.test.js +88 -75
- package/dist/store.test.js.map +1 -1
- package/dist/ticket-doc.d.ts +26 -10
- package/dist/ticket-doc.d.ts.map +1 -1
- package/dist/ticket-doc.js +71 -27
- package/dist/ticket-doc.js.map +1 -1
- package/dist/types.d.ts +51 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/skill/SKILL.md +70 -23
- package/src/asks.test.ts +355 -0
- package/src/check.test.ts +129 -72
- package/src/check.ts +101 -58
- package/src/claim-io.ts +401 -0
- package/src/claim.test.ts +141 -99
- package/src/claim.ts +69 -96
- package/src/cli.ts +251 -63
- package/src/file-store.ts +357 -145
- package/src/git-serve.test.ts +240 -0
- package/src/git-serve.ts +595 -0
- package/src/git.ts +141 -0
- package/src/id.ts +68 -0
- package/src/inbox.ts +77 -0
- package/src/overview.test.ts +6 -5
- package/src/overview.ts +25 -10
- package/src/promote.test.ts +40 -28
- package/src/publish.ts +6 -53
- package/src/search.test.ts +11 -11
- package/src/search.ts +17 -3
- package/src/server.ts +221 -19
- package/src/store.test.ts +95 -77
- package/src/store.ts +28 -13
- package/src/ticket-doc.ts +93 -30
- package/src/types.ts +52 -17
- package/ui/dist/assets/index-BjsorZOU.js +229 -0
- package/ui/dist/assets/index-CoKCUYic.css +1 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/index-BJmOsOdR.js +0 -229
- package/ui/dist/assets/index-BoqQlqSU.css +0 -1
package/src/claim.ts
CHANGED
|
@@ -10,9 +10,15 @@
|
|
|
10
10
|
* (the implement-task skill, a human).
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { spawnSync } from "node:child_process"
|
|
14
13
|
import { join } from "node:path"
|
|
15
14
|
import { FileStore, TICKETS_DIR, openBoard } from "./file-store.ts"
|
|
15
|
+
import {
|
|
16
|
+
GIT_NETWORK_TIMEOUT_MS,
|
|
17
|
+
defaultBase,
|
|
18
|
+
git,
|
|
19
|
+
gitMust,
|
|
20
|
+
runGit,
|
|
21
|
+
} from "./git.ts"
|
|
16
22
|
import {
|
|
17
23
|
boardConfig,
|
|
18
24
|
findBoardsByPrefix,
|
|
@@ -37,23 +43,23 @@ export const DEFAULT_CLAIM_PREFIX = "task/claim/"
|
|
|
37
43
|
const CLAIM_PREFIX_SHAPE = /^([A-Za-z0-9._-]+\/)+$/
|
|
38
44
|
|
|
39
45
|
/**
|
|
40
|
-
* The board's
|
|
41
|
-
* `claims.branchPrefix`, falling back to the pre-0.8 top-level `claimPrefix`
|
|
42
|
-
* (still read for one release so a version bump can't strand in-flight
|
|
43
|
-
* claims; `task check` nags, `--fix` migrates). Exported for `task check`,
|
|
44
|
-
* which wants the raw value to lint without the throw below.
|
|
45
|
-
*/
|
|
46
|
-
export function configuredBranchPrefix(config: ProjectConfig): string | undefined {
|
|
47
|
-
return config.claims?.branchPrefix ?? config.claimPrefix
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* The board's claim namespace: configured branch prefix (a trailing slash is
|
|
46
|
+
* The board's claim namespace: `claims.branchPrefix` (a trailing slash is
|
|
52
47
|
* implied) or the default. Validated here because it becomes a git ref and an
|
|
53
48
|
* ls-remote glob — a malformed value must fail the claim, not corrupt it.
|
|
49
|
+
*
|
|
50
|
+
* The pre-0.8 top-level `claimPrefix` spelling is not honored — no consumers,
|
|
51
|
+
* no compat (TAS-41) — but silently *defaulting* over it would be worse than
|
|
52
|
+
* a shim: the board's committed lock convention would change under every
|
|
53
|
+
* worker at once. So its presence refuses, loudly, by name.
|
|
54
54
|
*/
|
|
55
55
|
export function claimNamespace(config: ProjectConfig): string {
|
|
56
|
-
|
|
56
|
+
if (config.claimPrefix !== undefined && config.claims?.branchPrefix === undefined) {
|
|
57
|
+
throw new ClaimError(
|
|
58
|
+
'`claimPrefix` in .task/config.json is the pre-0.8 spelling and is no longer read — rename it to `claims: { "branchPrefix": … }`',
|
|
59
|
+
"invalid",
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
const raw = config.claims?.branchPrefix ?? DEFAULT_CLAIM_PREFIX
|
|
57
63
|
const prefix = raw.endsWith("/") ? raw : `${raw}/`
|
|
58
64
|
if (!CLAIM_PREFIX_SHAPE.test(prefix) || prefix.includes("..") || /(^|\/)\./.test(prefix)) {
|
|
59
65
|
throw new ClaimError(
|
|
@@ -79,9 +85,9 @@ export function openClaimCap(root: string): number | undefined {
|
|
|
79
85
|
}
|
|
80
86
|
}
|
|
81
87
|
|
|
82
|
-
/** { prefix: "TAS" },
|
|
83
|
-
export function claimBranch(config: ProjectConfig,
|
|
84
|
-
return `${claimNamespace(config)}${config.prefix.toLowerCase()}-${
|
|
88
|
+
/** { prefix: "TAS" }, "x7k4m" → "task/claim/tas-x7k4m" (or under the configured namespace). */
|
|
89
|
+
export function claimBranch(config: ProjectConfig, key: string): string {
|
|
90
|
+
return `${claimNamespace(config)}${config.prefix.toLowerCase()}-${key}`
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
/**
|
|
@@ -97,52 +103,18 @@ export class ClaimError extends Error {
|
|
|
97
103
|
}
|
|
98
104
|
}
|
|
99
105
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
stderr: string
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function git(cwd: string, ...args: string[]): GitResult {
|
|
107
|
-
const result = spawnSync("git", args, { cwd, encoding: "utf8" })
|
|
108
|
-
if (result.error) throw result.error
|
|
109
|
-
return {
|
|
110
|
-
status: result.status ?? 1,
|
|
111
|
-
stdout: (result.stdout ?? "").trim(),
|
|
112
|
-
stderr: (result.stderr ?? "").trim(),
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** Run git and throw on failure — for the steps that have no soft outcome. */
|
|
117
|
-
function gitMust(cwd: string, ...args: string[]): string {
|
|
118
|
-
const result = git(cwd, ...args)
|
|
106
|
+
/** Network git that throws on failure, with the timeout a real remote deserves. */
|
|
107
|
+
function gitNetMust(cwd: string, ...args: string[]): string {
|
|
108
|
+
const result = runGit(cwd, args, { timeoutMs: GIT_NETWORK_TIMEOUT_MS })
|
|
119
109
|
if (result.status !== 0) {
|
|
120
110
|
throw new Error(`git ${args[0]} failed: ${result.stderr || result.stdout}`)
|
|
121
111
|
}
|
|
122
112
|
return result.stdout
|
|
123
113
|
}
|
|
124
114
|
|
|
125
|
-
/**
|
|
126
|
-
* The base every claim branch starts from: origin's default branch. Resolved
|
|
127
|
-
* from `origin/HEAD` when the clone recorded it, with a main/master fallback
|
|
128
|
-
* for repos wired up by hand (`git remote add` + push never sets origin/HEAD).
|
|
129
|
-
*/
|
|
130
|
-
function defaultBase(cwd: string): string {
|
|
131
|
-
const head = git(cwd, "symbolic-ref", "--quiet", "refs/remotes/origin/HEAD")
|
|
132
|
-
if (head.status === 0) return head.stdout.replace(/^refs\/remotes\//, "")
|
|
133
|
-
for (const name of ["main", "master"]) {
|
|
134
|
-
if (git(cwd, "show-ref", "--verify", "--quiet", `refs/remotes/origin/${name}`).status === 0) {
|
|
135
|
-
return `origin/${name}`
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
throw new Error(
|
|
139
|
-
"couldn't resolve origin's default branch — origin/HEAD is unset and neither origin/main nor origin/master exists",
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
115
|
/** Every claim branch that exists on origin right now — one network call. */
|
|
144
116
|
export function remoteClaims(cwd: string, namespace: string): Set<string> {
|
|
145
|
-
const out =
|
|
117
|
+
const out = gitNetMust(cwd, "ls-remote", "--heads", "origin", `${namespace}*`)
|
|
146
118
|
const names = new Set<string>()
|
|
147
119
|
for (const line of out.split("\n")) {
|
|
148
120
|
const ref = line.split("\t")[1]
|
|
@@ -152,25 +124,30 @@ export function remoteClaims(cwd: string, namespace: string): Set<string> {
|
|
|
152
124
|
}
|
|
153
125
|
|
|
154
126
|
function remoteBranchExists(cwd: string, branch: string): boolean {
|
|
155
|
-
return
|
|
127
|
+
return gitNetMust(cwd, "ls-remote", "--heads", "origin", branch) !== ""
|
|
156
128
|
}
|
|
157
129
|
|
|
158
130
|
/** Blockers still in the way — anything not done or canceled still blocks. */
|
|
159
131
|
function openBlockers(store: Store, task: Task): string[] {
|
|
160
132
|
return task.blockedBy
|
|
161
|
-
.map((
|
|
133
|
+
.map((k) => store.get(k))
|
|
162
134
|
.filter((b): b is Task => b !== null && b.status !== "done" && b.status !== "canceled")
|
|
163
135
|
.map((b) => b.id)
|
|
164
136
|
}
|
|
165
137
|
|
|
166
|
-
/**
|
|
167
|
-
|
|
168
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Throws ClaimError("invalid") unless `task` is claimable right now. Open asks
|
|
140
|
+
* deliberately don't gate here: a ticket can be agent-implementable while a
|
|
141
|
+
* person owes it something in parallel — the done gate keeps that honest. An
|
|
142
|
+
* ask that must land *before* the work starts is a `blocked_by` on a thin
|
|
143
|
+
* human ticket, which the blocker check below already enforces.
|
|
144
|
+
*/
|
|
145
|
+
function assertClaimable(store: Store, task: Task | null, key: string): asserts task is Task {
|
|
146
|
+
const id = store.displayId(key)
|
|
169
147
|
if (!task) throw new ClaimError(`no such task: ${id}`, "invalid")
|
|
170
148
|
if (task.status !== "todo") {
|
|
171
149
|
throw new ClaimError(`${id} is ${task.status} — only todo tickets can be claimed`, "invalid")
|
|
172
150
|
}
|
|
173
|
-
if (task.needsHuman) throw new ClaimError(`${id} needs a human — not claimable`, "invalid")
|
|
174
151
|
const blockers = openBlockers(store, task)
|
|
175
152
|
if (blockers.length) {
|
|
176
153
|
throw new ClaimError(`${id} is blocked by ${blockers.join(", ")} — not claimable`, "invalid")
|
|
@@ -215,7 +192,7 @@ function assertUnderCap(openClaims: Set<string>, root: string, namespace: string
|
|
|
215
192
|
* someone pre-created without a claim commit can't be hijacked by a plain
|
|
216
193
|
* fast-forward. Leaves the winner checked out on the claim branch.
|
|
217
194
|
*/
|
|
218
|
-
export function claim(store: Store,
|
|
195
|
+
export function claim(store: Store, key: string, options: ClaimOptions = {}): ClaimResult {
|
|
219
196
|
// Unreachable since openBoard refuses pre-0.6 boards, kept as the narrowing
|
|
220
197
|
// that lets the rest of this function assume text-canonical semantics.
|
|
221
198
|
if (!(store instanceof FileStore)) {
|
|
@@ -225,8 +202,8 @@ export function claim(store: Store, number: number, options: ClaimOptions = {}):
|
|
|
225
202
|
)
|
|
226
203
|
}
|
|
227
204
|
const cwd = store.root
|
|
228
|
-
const branch = claimBranch(store.config,
|
|
229
|
-
const id = store.displayId(
|
|
205
|
+
const branch = claimBranch(store.config, key)
|
|
206
|
+
const id = store.displayId(key)
|
|
230
207
|
|
|
231
208
|
// The local-branch check comes before ticket validation on purpose: on the
|
|
232
209
|
// claim branch itself the ticket reads in_progress, and "already claimed"
|
|
@@ -246,7 +223,7 @@ export function claim(store: Store, number: number, options: ClaimOptions = {}):
|
|
|
246
223
|
)
|
|
247
224
|
}
|
|
248
225
|
|
|
249
|
-
assertClaimable(store, store.get(
|
|
226
|
+
assertClaimable(store, store.get(key), key)
|
|
250
227
|
if (tree.stdout !== "") {
|
|
251
228
|
throw new ClaimError(
|
|
252
229
|
"working tree is dirty — commit or stash before claiming, the claim switches branches",
|
|
@@ -254,7 +231,7 @@ export function claim(store: Store, number: number, options: ClaimOptions = {}):
|
|
|
254
231
|
)
|
|
255
232
|
}
|
|
256
233
|
|
|
257
|
-
|
|
234
|
+
gitNetMust(cwd, "fetch", "--quiet", "origin")
|
|
258
235
|
// One ls-remote answers both gates: is this ticket taken, and is the repo
|
|
259
236
|
// at its WIP cap. "Already claimed" wins — that's exit 1 (pick the next
|
|
260
237
|
// ticket), where the cap is exit 2 (fix something).
|
|
@@ -282,23 +259,19 @@ export function claim(store: Store, number: number, options: ClaimOptions = {}):
|
|
|
282
259
|
// Re-validate against the base branch: the pre-checkout validation read
|
|
283
260
|
// whatever happened to be checked out, this one reads the truth the claim
|
|
284
261
|
// will actually be built on.
|
|
285
|
-
assertClaimable(store, store.get(
|
|
286
|
-
store.update(
|
|
287
|
-
gitMust(cwd, "add", "--", join(store.taskDir, TICKETS_DIR,
|
|
262
|
+
assertClaimable(store, store.get(key), key)
|
|
263
|
+
store.update(key, { status: "in_progress" })
|
|
264
|
+
gitMust(cwd, "add", "--", join(store.taskDir, TICKETS_DIR, key))
|
|
288
265
|
gitMust(cwd, "commit", "--quiet", "-m", `chore(board): claim ${id} → in_progress`)
|
|
289
266
|
} catch (error) {
|
|
290
267
|
undo()
|
|
291
268
|
throw error
|
|
292
269
|
}
|
|
293
270
|
|
|
294
|
-
const push =
|
|
271
|
+
const push = runGit(
|
|
295
272
|
cwd,
|
|
296
|
-
"push",
|
|
297
|
-
|
|
298
|
-
"-u",
|
|
299
|
-
"origin",
|
|
300
|
-
branch,
|
|
301
|
-
`--force-with-lease=refs/heads/${branch}:`,
|
|
273
|
+
["push", "--quiet", "-u", "origin", branch, `--force-with-lease=refs/heads/${branch}:`],
|
|
274
|
+
{ timeoutMs: GIT_NETWORK_TIMEOUT_MS },
|
|
302
275
|
)
|
|
303
276
|
if (push.status !== 0) {
|
|
304
277
|
undo()
|
|
@@ -311,7 +284,7 @@ export function claim(store: Store, number: number, options: ClaimOptions = {}):
|
|
|
311
284
|
)
|
|
312
285
|
}
|
|
313
286
|
|
|
314
|
-
return { task: store.get(
|
|
287
|
+
return { task: store.get(key)!, branch, base }
|
|
315
288
|
}
|
|
316
289
|
|
|
317
290
|
export interface ReleaseResult {
|
|
@@ -326,9 +299,9 @@ export interface ReleaseResult {
|
|
|
326
299
|
* flip only ever existed as a commit on that branch, so deleting it *is* the
|
|
327
300
|
* revert — the default branch never saw in_progress.
|
|
328
301
|
*/
|
|
329
|
-
export function release(store: Store,
|
|
302
|
+
export function release(store: Store, key: string): ReleaseResult {
|
|
330
303
|
const cwd = store.root
|
|
331
|
-
const branch = claimBranch(store.config,
|
|
304
|
+
const branch = claimBranch(store.config, key)
|
|
332
305
|
|
|
333
306
|
const onBranch =
|
|
334
307
|
git(cwd, "symbolic-ref", "--quiet", "--short", "HEAD").stdout === branch
|
|
@@ -353,22 +326,22 @@ export function release(store: Store, number: number): ReleaseResult {
|
|
|
353
326
|
|
|
354
327
|
const local = git(cwd, "branch", "--quiet", "-D", branch).status === 0
|
|
355
328
|
const remote = remoteBranchExists(cwd, branch)
|
|
356
|
-
if (remote)
|
|
329
|
+
if (remote) gitNetMust(cwd, "push", "--quiet", "origin", "--delete", branch)
|
|
357
330
|
return { branch, remote, local }
|
|
358
331
|
}
|
|
359
332
|
|
|
360
333
|
/**
|
|
361
|
-
* The dispatcher's queue view: `todo` in position order, minus
|
|
362
|
-
*
|
|
363
|
-
*
|
|
334
|
+
* The dispatcher's queue view: `todo` in position order, minus blocked, minus
|
|
335
|
+
* tickets whose claim branch already exists on origin (one ls-remote for the
|
|
336
|
+
* whole namespace). The top entry is next up. Open asks don't exclude a
|
|
337
|
+
* ticket — see assertClaimable.
|
|
364
338
|
*/
|
|
365
339
|
export function claimableTasks(store: Store): Task[] {
|
|
366
340
|
const claimed = remoteClaims(store.root, claimNamespace(store.config))
|
|
367
341
|
return store
|
|
368
342
|
.list({ statuses: ["todo"] })
|
|
369
|
-
.filter((t) => !t.needsHuman)
|
|
370
343
|
.filter((t) => openBlockers(store, t).length === 0)
|
|
371
|
-
.filter((t) => !claimed.has(claimBranch(store.config, t.
|
|
344
|
+
.filter((t) => !claimed.has(claimBranch(store.config, t.key)))
|
|
372
345
|
}
|
|
373
346
|
|
|
374
347
|
export interface PromoteResult {
|
|
@@ -380,15 +353,16 @@ export interface PromoteResult {
|
|
|
380
353
|
/**
|
|
381
354
|
* `task promote` — the human "build this" call, as a verb: `backlog` → `todo`.
|
|
382
355
|
* No quality gate: planning happens at claim time (the worker's plan tick),
|
|
383
|
-
* so a one-line backlog ticket is promotable.
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
* `update` does; committing is
|
|
356
|
+
* so a one-line backlog ticket is promotable. Blockers are claim-time facts
|
|
357
|
+
* that `claim`/`--claimable` already enforce live, so promoting a blocked
|
|
358
|
+
* ticket is legitimate sequencing ("build this once NIC-11 lands") — reported
|
|
359
|
+
* as a hold, never refused. Open asks aren't a hold at all: they don't gate
|
|
360
|
+
* claiming, only done. Writes the ticket like `update` does; committing is
|
|
361
|
+
* the caller's job.
|
|
388
362
|
*/
|
|
389
|
-
export function promote(store: Store,
|
|
390
|
-
const task = store.get(
|
|
391
|
-
const id = store.displayId(
|
|
363
|
+
export function promote(store: Store, key: string): PromoteResult {
|
|
364
|
+
const task = store.get(key)
|
|
365
|
+
const id = store.displayId(key)
|
|
392
366
|
if (!task) throw new ClaimError(`no such task: ${id}`, "invalid")
|
|
393
367
|
if (task.status !== "backlog") {
|
|
394
368
|
throw new ClaimError(
|
|
@@ -396,9 +370,8 @@ export function promote(store: Store, number: number): PromoteResult {
|
|
|
396
370
|
"invalid",
|
|
397
371
|
)
|
|
398
372
|
}
|
|
399
|
-
const updated = store.update(
|
|
373
|
+
const updated = store.update(key, { status: "todo" })
|
|
400
374
|
const holds: string[] = []
|
|
401
|
-
if (updated.needsHuman) holds.push("flagged needs-human")
|
|
402
375
|
const blockers = openBlockers(store, updated)
|
|
403
376
|
if (blockers.length) holds.push(`blocked by ${blockers.join(", ")}`)
|
|
404
377
|
return { task: updated, holds }
|
|
@@ -474,7 +447,7 @@ export function claimNext(stores: Store[], options: ClaimOptions = {}): ClaimRes
|
|
|
474
447
|
for (const store of stores) {
|
|
475
448
|
for (const task of claimableTasks(store)) {
|
|
476
449
|
try {
|
|
477
|
-
return claim(store, task.
|
|
450
|
+
return claim(store, task.key, options)
|
|
478
451
|
} catch (error) {
|
|
479
452
|
// Claimed out from under us, or changed since listing — next in line.
|
|
480
453
|
if (error instanceof ClaimError) continue
|