@clipboard-health/groundcrew 4.29.0 → 4.30.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/dist/lib/adapters/shell/factory.d.ts +6 -2
- package/dist/lib/adapters/shell/factory.d.ts.map +1 -1
- package/dist/lib/adapters/shell/factory.js +109 -11
- package/dist/lib/adapters/shell/schema.d.ts +10 -0
- package/dist/lib/adapters/shell/schema.d.ts.map +1 -1
- package/dist/lib/adapters/shell/schema.js +23 -0
- package/dist/lib/sourceCapabilities.js +2 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shell-adapter `TaskSource` factory. Wires `invokeShellCommand` to the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* TaskSource operations and applies the ShellIssue Zod schema for runtime
|
|
4
|
+
* validation of script stdout.
|
|
5
5
|
*
|
|
6
6
|
* Fallback behavior for omitted commands:
|
|
7
7
|
* - `verify` absent → no-op (always succeeds).
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
* - `markInProgress` absent → silent no-op.
|
|
14
14
|
* - `markInReview` absent → reports unsupported.
|
|
15
15
|
* - `markDone` absent → reports unsupported.
|
|
16
|
+
* - `createTask` absent → method omitted entirely (source reports it cannot
|
|
17
|
+
* create tasks; the optional method is attached only when configured).
|
|
18
|
+
* - `validate` absent → method omitted entirely (same capability-detection
|
|
19
|
+
* contract as createTask).
|
|
16
20
|
* - `fetch` is required by the Zod schema.
|
|
17
21
|
*/
|
|
18
22
|
import type { AdapterContext } from "../../adapterDefinition.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/shell/factory.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/shell/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAIL,KAAK,KAAK,IAAI,cAAc,EAG5B,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EACL,KAAK,kBAAkB,EAEvB,KAAK,UAAU,EAGhB,MAAM,aAAa,CAAC;AAyErB,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAuB3F;AA8BD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE,cAAc,GACvB,UAAU,CA6LZ"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shell-adapter `TaskSource` factory. Wires `invokeShellCommand` to the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* TaskSource operations and applies the ShellIssue Zod schema for runtime
|
|
4
|
+
* validation of script stdout.
|
|
5
5
|
*
|
|
6
6
|
* Fallback behavior for omitted commands:
|
|
7
7
|
* - `verify` absent → no-op (always succeeds).
|
|
@@ -13,12 +13,16 @@
|
|
|
13
13
|
* - `markInProgress` absent → silent no-op.
|
|
14
14
|
* - `markInReview` absent → reports unsupported.
|
|
15
15
|
* - `markDone` absent → reports unsupported.
|
|
16
|
+
* - `createTask` absent → method omitted entirely (source reports it cannot
|
|
17
|
+
* create tasks; the optional method is attached only when configured).
|
|
18
|
+
* - `validate` absent → method omitted entirely (same capability-detection
|
|
19
|
+
* contract as createTask).
|
|
16
20
|
* - `fetch` is required by the Zod schema.
|
|
17
21
|
*/
|
|
18
22
|
import { toCanonicalId, } from "../../taskSource.js";
|
|
19
|
-
import { writeError } from "../../util.js";
|
|
23
|
+
import { errorMessage, writeError } from "../../util.js";
|
|
20
24
|
import { invokeShellCommand } from "./invoke.js";
|
|
21
|
-
import { shellFetchOutputSchema, shellIssueSchema, } from "./schema.js";
|
|
25
|
+
import { shellFetchOutputSchema, shellIssueSchema, shellValidateOutputSchema, } from "./schema.js";
|
|
22
26
|
const DEFAULT_TIMEOUTS = {
|
|
23
27
|
verify: 10_000,
|
|
24
28
|
listTasks: 30_000,
|
|
@@ -26,15 +30,20 @@ const DEFAULT_TIMEOUTS = {
|
|
|
26
30
|
markInProgress: 10_000,
|
|
27
31
|
markInReview: 10_000,
|
|
28
32
|
markDone: 10_000,
|
|
33
|
+
createTask: 30_000,
|
|
34
|
+
validate: 30_000,
|
|
29
35
|
};
|
|
30
36
|
function mergeTimeouts(overrides) {
|
|
37
|
+
const o = overrides ?? {};
|
|
31
38
|
return {
|
|
32
|
-
verify:
|
|
33
|
-
listTasks:
|
|
34
|
-
getTask:
|
|
35
|
-
markInProgress:
|
|
36
|
-
markInReview:
|
|
37
|
-
markDone:
|
|
39
|
+
verify: o.verify ?? DEFAULT_TIMEOUTS.verify,
|
|
40
|
+
listTasks: o.listTasks ?? o.fetch ?? DEFAULT_TIMEOUTS.listTasks,
|
|
41
|
+
getTask: o.getTask ?? o.resolveOne ?? DEFAULT_TIMEOUTS.getTask,
|
|
42
|
+
markInProgress: o.markInProgress ?? DEFAULT_TIMEOUTS.markInProgress,
|
|
43
|
+
markInReview: o.markInReview ?? DEFAULT_TIMEOUTS.markInReview,
|
|
44
|
+
markDone: o.markDone ?? DEFAULT_TIMEOUTS.markDone,
|
|
45
|
+
createTask: o.createTask ?? DEFAULT_TIMEOUTS.createTask,
|
|
46
|
+
validate: o.validate ?? DEFAULT_TIMEOUTS.validate,
|
|
38
47
|
};
|
|
39
48
|
}
|
|
40
49
|
function warnDuplicate(sourceName, preferred, legacy) {
|
|
@@ -85,6 +94,33 @@ export function toCanonicalIssue(shellIssue, sourceName) {
|
|
|
85
94
|
sourceRef: shellIssue.sourceRef,
|
|
86
95
|
};
|
|
87
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Flatten a CreateTaskInput into the `${...}` substitution map the createTask
|
|
99
|
+
* script receives. Every key is always present — absent optionals become an
|
|
100
|
+
* empty string — so no placeholder is ever left literally in the command.
|
|
101
|
+
* List fields are comma-joined into a single value.
|
|
102
|
+
*/
|
|
103
|
+
function createTaskSubstitutions(input) {
|
|
104
|
+
return {
|
|
105
|
+
title: input.title,
|
|
106
|
+
agent: input.agent,
|
|
107
|
+
// Exposed under both `repo` (short form) and `repository` (matches the
|
|
108
|
+
// CreateTaskInput field name) so either placeholder resolves.
|
|
109
|
+
repo: input.repository ?? "",
|
|
110
|
+
repository: input.repository ?? "",
|
|
111
|
+
team: input.team ?? "",
|
|
112
|
+
id: input.id ?? "",
|
|
113
|
+
priority: input.priority ?? "",
|
|
114
|
+
due: input.due ?? "",
|
|
115
|
+
recurrence: input.recurrence ?? "",
|
|
116
|
+
promptFile: input.promptFile ?? "",
|
|
117
|
+
description: input.description ?? "",
|
|
118
|
+
edit: input.edit ? "true" : "",
|
|
119
|
+
projects: input.projects.join(","),
|
|
120
|
+
contexts: input.contexts.join(","),
|
|
121
|
+
dependencies: input.dependencies.join(","),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
88
124
|
export function createShellTaskSource(config, _context) {
|
|
89
125
|
const sourceName = config.name;
|
|
90
126
|
const timeouts = mergeTimeouts(config.timeouts);
|
|
@@ -149,7 +185,7 @@ export function createShellTaskSource(config, _context) {
|
|
|
149
185
|
sourceName,
|
|
150
186
|
});
|
|
151
187
|
}
|
|
152
|
-
|
|
188
|
+
const source = {
|
|
153
189
|
name: sourceName,
|
|
154
190
|
async verify() {
|
|
155
191
|
const verifyCommand = config.commands.verify;
|
|
@@ -198,4 +234,66 @@ export function createShellTaskSource(config, _context) {
|
|
|
198
234
|
return { outcome: "applied" };
|
|
199
235
|
},
|
|
200
236
|
};
|
|
237
|
+
// createTask / validate are attached only when their command is configured.
|
|
238
|
+
// Capability detection keys off `source.createTask === undefined` /
|
|
239
|
+
// `source.validate === undefined`, so a slot left unset must leave the
|
|
240
|
+
// method genuinely absent rather than present-but-failing.
|
|
241
|
+
const createTaskCommand = config.commands.createTask;
|
|
242
|
+
if (createTaskCommand !== undefined) {
|
|
243
|
+
source.createTask = async (input) => {
|
|
244
|
+
const { stdout, exitCode } = await invokeShellCommand({
|
|
245
|
+
command: createTaskCommand,
|
|
246
|
+
timeoutMs: timeouts.createTask,
|
|
247
|
+
cwd: config.cwd,
|
|
248
|
+
env: config.env,
|
|
249
|
+
substitutions: createTaskSubstitutions(input),
|
|
250
|
+
sourceName,
|
|
251
|
+
});
|
|
252
|
+
// invokeShellCommand resolves (does not throw) on exit 3 — its "not
|
|
253
|
+
// found" sentinel for lookups. Creation has no not-found concept, so any
|
|
254
|
+
// nonzero exit is a failure: surface it rather than parse partial output.
|
|
255
|
+
if (exitCode === 3) {
|
|
256
|
+
throw new Error(`shell source "${sourceName}" createTask command exited 3 (not-found); task creation cannot signal not-found`);
|
|
257
|
+
}
|
|
258
|
+
const trimmed = stdout.trim();
|
|
259
|
+
if (trimmed.length === 0) {
|
|
260
|
+
throw new Error(`shell source "${sourceName}" createTask command produced no output (expected one ShellIssue JSON)`);
|
|
261
|
+
}
|
|
262
|
+
const parsed = shellIssueSchema.parse(JSON.parse(trimmed));
|
|
263
|
+
return toCanonicalIssue(parsed, sourceName);
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
const validateCommand = config.commands.validate;
|
|
267
|
+
if (validateCommand !== undefined) {
|
|
268
|
+
source.validate = async () => {
|
|
269
|
+
try {
|
|
270
|
+
const { stdout, exitCode } = await invokeShellCommand({
|
|
271
|
+
command: validateCommand,
|
|
272
|
+
timeoutMs: timeouts.validate,
|
|
273
|
+
cwd: config.cwd,
|
|
274
|
+
env: config.env,
|
|
275
|
+
sourceName,
|
|
276
|
+
});
|
|
277
|
+
// exit 3 is invoke's lookup "not found" sentinel; for validation it is
|
|
278
|
+
// not a meaningful success, so surface it as a failure (and validate
|
|
279
|
+
// never throws — return the failure as an error string).
|
|
280
|
+
if (exitCode === 3) {
|
|
281
|
+
return [
|
|
282
|
+
`shell source "${sourceName}" validate command exited 3 (not-found); treating as a validation failure`,
|
|
283
|
+
];
|
|
284
|
+
}
|
|
285
|
+
const trimmed = stdout.trim();
|
|
286
|
+
if (trimmed.length === 0) {
|
|
287
|
+
return [];
|
|
288
|
+
}
|
|
289
|
+
return shellValidateOutputSchema.parse(JSON.parse(trimmed));
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
// Contract: validate() never throws — fold a nonzero exit, timeout,
|
|
293
|
+
// malformed JSON, or wrong-shape payload into a single error string.
|
|
294
|
+
return [`shell source "${sourceName}" validate command failed: ${errorMessage(error)}`];
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return source;
|
|
201
299
|
}
|
|
@@ -80,6 +80,12 @@ export declare const shellFetchOutputSchema: z.ZodArray<z.ZodObject<{
|
|
|
80
80
|
url: z.ZodOptional<z.ZodURL>;
|
|
81
81
|
sourceRef: z.ZodUnknown;
|
|
82
82
|
}, z.core.$strip>>;
|
|
83
|
+
/**
|
|
84
|
+
* Shape a `commands.validate` script must emit on stdout: a JSON array of
|
|
85
|
+
* human-readable error strings. An empty array (or empty stdout, handled by
|
|
86
|
+
* the factory) means "no problems found".
|
|
87
|
+
*/
|
|
88
|
+
export declare const shellValidateOutputSchema: z.ZodArray<z.ZodString>;
|
|
83
89
|
export declare const shellAdapterConfigSchema: z.ZodObject<{
|
|
84
90
|
kind: z.ZodLiteral<"shell">;
|
|
85
91
|
name: z.ZodString;
|
|
@@ -92,6 +98,8 @@ export declare const shellAdapterConfigSchema: z.ZodObject<{
|
|
|
92
98
|
markInProgress: z.ZodOptional<z.ZodString>;
|
|
93
99
|
markInReview: z.ZodOptional<z.ZodString>;
|
|
94
100
|
markDone: z.ZodOptional<z.ZodString>;
|
|
101
|
+
createTask: z.ZodOptional<z.ZodString>;
|
|
102
|
+
validate: z.ZodOptional<z.ZodString>;
|
|
95
103
|
}, z.core.$strip>;
|
|
96
104
|
cwd: z.ZodOptional<z.ZodString>;
|
|
97
105
|
timeouts: z.ZodOptional<z.ZodObject<{
|
|
@@ -103,6 +111,8 @@ export declare const shellAdapterConfigSchema: z.ZodObject<{
|
|
|
103
111
|
markInProgress: z.ZodOptional<z.ZodNumber>;
|
|
104
112
|
markInReview: z.ZodOptional<z.ZodNumber>;
|
|
105
113
|
markDone: z.ZodOptional<z.ZodNumber>;
|
|
114
|
+
createTask: z.ZodOptional<z.ZodNumber>;
|
|
115
|
+
validate: z.ZodOptional<z.ZodNumber>;
|
|
106
116
|
}, z.core.$strip>>;
|
|
107
117
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
108
118
|
}, z.core.$strip>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/shell/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiB3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAA4B,CAAC;AAEhE,eAAO,MAAM,wBAAwB
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/shell/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiB3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAA4B,CAAC;AAEhE;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,yBAAsB,CAAC;AAE7D,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkEnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
|
|
@@ -36,6 +36,12 @@ export const shellIssueSchema = z.object({
|
|
|
36
36
|
sourceRef: z.unknown(),
|
|
37
37
|
});
|
|
38
38
|
export const shellFetchOutputSchema = z.array(shellIssueSchema);
|
|
39
|
+
/**
|
|
40
|
+
* Shape a `commands.validate` script must emit on stdout: a JSON array of
|
|
41
|
+
* human-readable error strings. An empty array (or empty stdout, handled by
|
|
42
|
+
* the factory) means "no problems found".
|
|
43
|
+
*/
|
|
44
|
+
export const shellValidateOutputSchema = z.array(z.string());
|
|
39
45
|
export const shellAdapterConfigSchema = z.object({
|
|
40
46
|
kind: z.literal("shell"),
|
|
41
47
|
name: z
|
|
@@ -55,6 +61,19 @@ export const shellAdapterConfigSchema = z.object({
|
|
|
55
61
|
markInProgress: z.string().optional(),
|
|
56
62
|
markInReview: z.string().optional(),
|
|
57
63
|
markDone: z.string().optional(),
|
|
64
|
+
/**
|
|
65
|
+
* Create a task from a `CreateTaskInput`. Receives the input fields as
|
|
66
|
+
* shell-quoted `${...}` placeholders (see factory) and must print one
|
|
67
|
+
* ShellIssue JSON on stdout. Omitting it leaves the source unable to
|
|
68
|
+
* create tasks.
|
|
69
|
+
*/
|
|
70
|
+
createTask: z.string().optional(),
|
|
71
|
+
/**
|
|
72
|
+
* Validate task content. Must print a JSON array of error strings on
|
|
73
|
+
* stdout (empty array / empty stdout = no problems). Omitting it leaves
|
|
74
|
+
* the source unable to validate.
|
|
75
|
+
*/
|
|
76
|
+
validate: z.string().optional(),
|
|
58
77
|
})
|
|
59
78
|
.superRefine((commands, ctx) => {
|
|
60
79
|
if (commands.listTasks === undefined && commands.fetch === undefined) {
|
|
@@ -82,6 +101,10 @@ export const shellAdapterConfigSchema = z.object({
|
|
|
82
101
|
markInProgress: z.number().int().positive().optional(),
|
|
83
102
|
markInReview: z.number().int().positive().optional(),
|
|
84
103
|
markDone: z.number().int().positive().optional(),
|
|
104
|
+
/** Timeout for the createTask command. */
|
|
105
|
+
createTask: z.number().int().positive().optional(),
|
|
106
|
+
/** Timeout for the validate command. */
|
|
107
|
+
validate: z.number().int().positive().optional(),
|
|
85
108
|
})
|
|
86
109
|
.optional(),
|
|
87
110
|
env: z.record(z.string(), z.string()).optional(),
|
|
@@ -29,11 +29,11 @@ function shellCapabilities(raw) {
|
|
|
29
29
|
verify: commands.verify !== undefined,
|
|
30
30
|
listTasks: true,
|
|
31
31
|
getTask: true,
|
|
32
|
-
createTask:
|
|
32
|
+
createTask: commands.createTask !== undefined,
|
|
33
33
|
markInProgress: commands.markInProgress !== undefined,
|
|
34
34
|
markInReview: commands.markInReview !== undefined,
|
|
35
35
|
markDone: commands.markDone !== undefined,
|
|
36
|
-
validate:
|
|
36
|
+
validate: commands.validate !== undefined,
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
const TODO_TXT_CAPABILITIES = {
|
package/package.json
CHANGED