@clipboard-health/groundcrew 4.24.1 → 4.24.2
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 +1 -1
- package/dist/commands/task.d.ts.map +1 -1
- package/dist/commands/task.js +3 -6
- package/dist/lib/adapters/todo-txt/normalizer.d.ts.map +1 -1
- package/dist/lib/adapters/todo-txt/normalizer.js +2 -4
- package/dist/lib/adapters/todo-txt/source.d.ts.map +1 -1
- package/dist/lib/adapters/todo-txt/source.js +13 -3
- package/dist/lib/adapters/todo-txt/writeback.d.ts.map +1 -1
- package/dist/lib/adapters/todo-txt/writeback.js +8 -5
- package/docs/commands.md +1 -1
- package/docs/task-sources.md +7 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -95,7 +95,7 @@ crew init [--global | --local] [--force] [--dry-run] # create a crew.config.
|
|
|
95
95
|
crew doctor # check setup
|
|
96
96
|
crew task list [--source <name>] # list tasks across sources
|
|
97
97
|
crew task get <TASK> [--source <name>] [--prompt] # inspect one task or its prompt
|
|
98
|
-
crew task create "Title" --source <name> --agent <name>
|
|
98
|
+
crew task create "Title" --source <name> [--agent <name>] # create a source task
|
|
99
99
|
crew status [<TASK>] # inspect current state or one task
|
|
100
100
|
crew run [--watch] # one-shot or --watch forever
|
|
101
101
|
crew start <TASK> # provision + launch one task now
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/commands/task.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/commands/task.ts"],"names":[],"mappings":"AAomBA,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAe3D"}
|
package/dist/commands/task.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildSources, sourcesFromConfig } from "../lib/buildSources.js";
|
|
2
|
-
import { loadConfig } from "../lib/config.js";
|
|
2
|
+
import { AGENT_ANY_MODEL, loadConfig } from "../lib/config.js";
|
|
3
3
|
import { naturalIdFromCanonical, } from "../lib/taskSource.js";
|
|
4
4
|
import { writeOutput } from "../lib/util.js";
|
|
5
5
|
const TASK_USAGE = `Usage: crew task <subcommand>
|
|
@@ -25,7 +25,7 @@ Options:
|
|
|
25
25
|
--source <name> Resolve a source-native ID against a specific source.
|
|
26
26
|
--json Print normalized task JSON.
|
|
27
27
|
--prompt Print only the task description/prompt.`;
|
|
28
|
-
const CREATE_USAGE = `Usage: crew task create "Short title" --source <source> --agent <agent> [options]`;
|
|
28
|
+
const CREATE_USAGE = `Usage: crew task create "Short title" --source <source> [--agent <agent>] [options]`;
|
|
29
29
|
const CANONICAL_STATUSES = [
|
|
30
30
|
"todo",
|
|
31
31
|
"in-progress",
|
|
@@ -232,12 +232,9 @@ function parseCreateOptions(argv) {
|
|
|
232
232
|
if (state.sourceName === undefined) {
|
|
233
233
|
throw new Error("crew task create: --source is required");
|
|
234
234
|
}
|
|
235
|
-
if (state.agent === undefined) {
|
|
236
|
-
throw new Error("crew task create: --agent is required");
|
|
237
|
-
}
|
|
238
235
|
const input = {
|
|
239
236
|
title,
|
|
240
|
-
agent: state.agent,
|
|
237
|
+
agent: state.agent ?? AGENT_ANY_MODEL,
|
|
241
238
|
projects: state.projects,
|
|
242
239
|
contexts: state.contexts,
|
|
243
240
|
dependencies: state.dependencies,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalizer.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/todo-txt/normalizer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"normalizer.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/todo-txt/normalizer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsC,KAAK,KAAK,EAAiB,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAA8C,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9F,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAkED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,CAAC,cAAc,GAAG,IAAI,CAAC,EAAE,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,KAAK,GAAG,SAAS,CAqD7E;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAShE"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { AGENT_ANY_MODEL } from "../../config.js";
|
|
2
3
|
import { toCanonicalId } from "../../taskSource.js";
|
|
3
4
|
import { getMetadataAll, getMetadataFirst, hashLine } from "./parser.js";
|
|
4
5
|
function derivedCanonicalStatus(parsed) {
|
|
@@ -58,7 +59,7 @@ export function normalizeToIssue(options) {
|
|
|
58
59
|
if (id === undefined) {
|
|
59
60
|
return undefined;
|
|
60
61
|
}
|
|
61
|
-
const agent = getMetadataFirst(parsed, "agent");
|
|
62
|
+
const agent = getMetadataFirst(parsed, "agent") ?? AGENT_ANY_MODEL;
|
|
62
63
|
const status = derivedCanonicalStatus(parsed);
|
|
63
64
|
const repository = getMetadataFirst(parsed, "repo") ?? defaultRepository;
|
|
64
65
|
const depIds = getMetadataAll(parsed, "dep");
|
|
@@ -96,9 +97,6 @@ export function isActiveForFetch(parsed) {
|
|
|
96
97
|
if (getMetadataFirst(parsed, "id") === undefined) {
|
|
97
98
|
return false;
|
|
98
99
|
}
|
|
99
|
-
if (getMetadataFirst(parsed, "agent") === undefined) {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
100
|
const statusValue = getMetadataFirst(parsed, "status");
|
|
103
101
|
return statusValue === "todo" || statusValue === "in-progress" || statusValue === "in-review";
|
|
104
102
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/todo-txt/source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/todo-txt/source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AA0RxD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,oBAAoB,EAC5B,QAAQ,EAAE,cAAc,GACvB,UAAU,CA4IZ"}
|
|
@@ -8,13 +8,23 @@ import { getMetadataFirst, parseAllLines } from "./parser.js";
|
|
|
8
8
|
import { copyPromptFile, updateTaskStatus, validateTodoFile, withLock } from "./writeback.js";
|
|
9
9
|
const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
10
10
|
const RECURRENCE_RE = /^\+?\d+[dwmy]$/;
|
|
11
|
-
function
|
|
11
|
+
function readPromptFile(promptPath) {
|
|
12
12
|
try {
|
|
13
13
|
return readFileSync(promptPath, "utf8");
|
|
14
14
|
}
|
|
15
15
|
catch {
|
|
16
|
-
return
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function descriptionFor(parsed, promptPath) {
|
|
20
|
+
const promptContent = readPromptFile(promptPath);
|
|
21
|
+
if (promptContent !== undefined && promptContent.trim().length > 0) {
|
|
22
|
+
return promptContent;
|
|
23
|
+
}
|
|
24
|
+
if (parsed.title.trim().length > 0) {
|
|
25
|
+
return `${parsed.title}\n`;
|
|
17
26
|
}
|
|
27
|
+
return promptContent ?? "";
|
|
18
28
|
}
|
|
19
29
|
function fileUpdatedAt(filePath) {
|
|
20
30
|
try {
|
|
@@ -51,7 +61,7 @@ function buildIssue(options) {
|
|
|
51
61
|
}
|
|
52
62
|
const promptOverride = getMetadataFirst(parsed, "prompt");
|
|
53
63
|
const promptPath = promptOverride ?? `${tasksDir}/${id}.md`;
|
|
54
|
-
const description =
|
|
64
|
+
const description = descriptionFor(parsed, promptPath);
|
|
55
65
|
return normalizeToIssue({
|
|
56
66
|
parsed,
|
|
57
67
|
allParsed: parsedAll,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeback.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/todo-txt/writeback.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAoKD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,gBAAgB,CAAC;IACtB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,wBAAsB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAQxF;AAED,KAAK,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,MAAM,CAAC;AA6E3D,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAsElC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAQrE;
|
|
1
|
+
{"version":3,"file":"writeback.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/todo-txt/writeback.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAoKD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,gBAAgB,CAAC;IACtB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,wBAAsB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAQxF;AAED,KAAK,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,MAAM,CAAC;AA6E3D,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAsElC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAQrE;AA4FD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CA0C7E"}
|
|
@@ -262,16 +262,19 @@ export function copyPromptFile(oldPath, newPath) {
|
|
|
262
262
|
// prompt file is optional — copy is best-effort
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
|
-
function validatePromptFile(tasksDir, id, promptOverride, prefix, errors) {
|
|
265
|
+
function validatePromptFile(tasksDir, id, promptOverride, title, prefix, errors) {
|
|
266
266
|
const promptPath = promptOverride ?? path.join(tasksDir, `${id}.md`);
|
|
267
|
+
const shouldRequirePrompt = promptOverride !== undefined || title.trim().length === 0;
|
|
267
268
|
try {
|
|
268
269
|
const desc = readFileSync(promptPath, "utf8");
|
|
269
|
-
if (desc.trim().length === 0) {
|
|
270
|
+
if (desc.trim().length === 0 && shouldRequirePrompt) {
|
|
270
271
|
errors.push(`${prefix}: empty prompt file "${promptPath}" for ready task "${id}"`);
|
|
271
272
|
}
|
|
272
273
|
}
|
|
273
274
|
catch {
|
|
274
|
-
|
|
275
|
+
if (shouldRequirePrompt) {
|
|
276
|
+
errors.push(`${prefix}: missing prompt file "${promptPath}" for ready task "${id}"`);
|
|
277
|
+
}
|
|
275
278
|
}
|
|
276
279
|
}
|
|
277
280
|
function validateDepsAndDates(parsed, parsedAll, id, prefix, errors) {
|
|
@@ -308,7 +311,7 @@ function validateActiveTaskLine(parsed, parsedAll, tasksDir, id, prefix, errors)
|
|
|
308
311
|
errors.push(`${prefix}: task "${id}" has status:todo but it is not the final token — task will not be dispatched`);
|
|
309
312
|
}
|
|
310
313
|
if (statusValue === "todo" && parsed.isStatusFinalToken) {
|
|
311
|
-
validatePromptFile(tasksDir, id, parsed.metadata["prompt"]?.[0], prefix, errors);
|
|
314
|
+
validatePromptFile(tasksDir, id, parsed.metadata["prompt"]?.[0], parsed.title, prefix, errors);
|
|
312
315
|
}
|
|
313
316
|
validateDepsAndDates(parsed, parsedAll, id, prefix, errors);
|
|
314
317
|
}
|
|
@@ -340,7 +343,7 @@ export function validateTodoFile(todoPath, tasksDir) {
|
|
|
340
343
|
idsSeen.set(lower, lineNum);
|
|
341
344
|
}
|
|
342
345
|
}
|
|
343
|
-
if (id === undefined
|
|
346
|
+
if (id === undefined) {
|
|
344
347
|
continue;
|
|
345
348
|
}
|
|
346
349
|
if (parsed.completed) {
|
package/docs/commands.md
CHANGED
|
@@ -18,7 +18,7 @@ crew task get GC-20260608-001 --source todo
|
|
|
18
18
|
crew task get todo:GC-20260608-001 --prompt
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
`crew task create "Short title" --source <source> --agent <agent
|
|
21
|
+
`crew task create "Short title" --source <source> [--agent <agent>]` creates a task in a source that supports creation. When `--agent` is omitted, it defaults to `any`. Todo.txt creation appends the todo line, defaults to priority `A` unless `--priority` is provided, writes `.tasks/<id>.md`, and leaves `status:todo` as the final meaningful token, so no separate ready command is required. Hand-written todo-txt lines can omit `.tasks/<id>.md` when the line has a non-empty title; that title becomes the prompt text.
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
crew task create "Fix cancellation retry race" \
|
package/docs/task-sources.md
CHANGED
|
@@ -78,7 +78,7 @@ export default {
|
|
|
78
78
|
};
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
Creating a todo task appends a line with `status:todo` as the final meaningful token and writes the prompt to `.tasks/<id>.md`. New todo tasks default to priority `A`; pass `--priority <letter>` to override it.
|
|
81
|
+
Creating a todo task appends a line with `status:todo` as the final meaningful token and writes the prompt to `.tasks/<id>.md`. New todo tasks default to priority `A`; pass `--priority <letter>` to override it. If `--agent` is omitted, the task uses `agent:any`.
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
84
|
crew task create "Fix cancellation retry race" \
|
|
@@ -94,6 +94,12 @@ crew task create "Fix cancellation retry race" \
|
|
|
94
94
|
(A) Fix cancellation retry race +marketplace @backend id:GC-20260608-001 repo:ClipboardHealth/api agent:codex status:todo
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
+
For hand-written todo lines, a non-empty title is enough prompt text when `.tasks/<id>.md` is absent. Omit `agent:` to default to `agent:any`:
|
|
98
|
+
|
|
99
|
+
```txt
|
|
100
|
+
Say goodbye repo:ClipboardHealth/groundcrew id:GC-20260608-002 status:todo
|
|
101
|
+
```
|
|
102
|
+
|
|
97
103
|
## Linear
|
|
98
104
|
|
|
99
105
|
The built-in Linear source supports listing, getting, writeback, and task creation through `crew task create`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clipboard-health/groundcrew",
|
|
3
|
-
"version": "4.24.
|
|
3
|
+
"version": "4.24.2",
|
|
4
4
|
"description": "Linear-driven orchestrator that launches AI coding agents in git worktrees, with workspace lifecycle and usage tracking.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"@nx/js": "22.7.5",
|
|
82
82
|
"@tsconfig/node24": "24.0.4",
|
|
83
83
|
"@tsconfig/strictest": "2.0.8",
|
|
84
|
-
"@types/node": "25.9.
|
|
84
|
+
"@types/node": "25.9.2",
|
|
85
85
|
"@typescript/native-preview": "7.0.0-dev.20260604.1",
|
|
86
86
|
"@vitest/coverage-v8": "4.1.8",
|
|
87
87
|
"cspell": "10.0.1",
|