@clipboard-health/groundcrew 4.34.3 → 4.35.1
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 -0
- package/dist/cli.js +2 -2
- package/dist/commands/dispatcher.d.ts.map +1 -1
- package/dist/commands/dispatcher.js +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +88 -18
- package/dist/commands/orchestrator.d.ts.map +1 -1
- package/dist/commands/orchestrator.js +6 -1
- package/dist/commands/resumeWorkspace.d.ts.map +1 -1
- package/dist/commands/resumeWorkspace.js +6 -1
- package/dist/commands/setupWorkspace.d.ts +2 -0
- package/dist/commands/setupWorkspace.d.ts.map +1 -1
- package/dist/commands/setupWorkspace.js +7 -0
- package/dist/commands/task.d.ts.map +1 -1
- package/dist/commands/task.js +87 -0
- package/dist/lib/adapters/shell/factory.d.ts.map +1 -1
- package/dist/lib/adapters/shell/factory.js +13 -3
- package/dist/lib/adapters/shell/parseOutput.d.ts +23 -0
- package/dist/lib/adapters/shell/parseOutput.d.ts.map +1 -0
- package/dist/lib/adapters/shell/parseOutput.js +67 -0
- package/dist/lib/agentLaunch.d.ts +2 -0
- package/dist/lib/agentLaunch.d.ts.map +1 -1
- package/dist/lib/agentLaunch.js +5 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +1 -0
- package/dist/lib/launchCommand.d.ts +9 -0
- package/dist/lib/launchCommand.d.ts.map +1 -1
- package/dist/lib/launchCommand.js +38 -7
- package/dist/lib/runState.d.ts +6 -0
- package/dist/lib/runState.d.ts.map +1 -1
- package/dist/lib/runState.js +4 -0
- package/dist/lib/taskSource.d.ts +13 -0
- package/dist/lib/taskSource.d.ts.map +1 -1
- package/dist/lib/taskSource.js +16 -0
- package/docs/commands.md +42 -4
- package/docs/configuration.md +25 -25
- package/docs/credentials.md +2 -2
- package/docs/runners.md +3 -3
- package/docs/task-sources.md +9 -3
- package/docs/troubleshooting.md +8 -6
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -94,6 +94,7 @@ crew source list|verify [<source>] # inspect configured ta
|
|
|
94
94
|
crew task list [--source <name>] # list tasks across sources
|
|
95
95
|
crew task get <TASK> [--source <name>] [--prompt] # inspect one task or its prompt
|
|
96
96
|
crew task create "Title" --source <name> [--agent <name>] # create a source task
|
|
97
|
+
crew task done <TASK> [--allow-dirty] # mark a no-PR task done
|
|
97
98
|
crew task validate [<source>] # validate task content
|
|
98
99
|
crew status [<TASK>] # inspect current state or one task
|
|
99
100
|
crew run [--watch] # one-shot or --watch forever
|
package/dist/cli.js
CHANGED
|
@@ -136,8 +136,8 @@ const SUBCOMMANDS = {
|
|
|
136
136
|
invoke: sourceCli,
|
|
137
137
|
},
|
|
138
138
|
task: {
|
|
139
|
-
summary: "List, get, and
|
|
140
|
-
usage: "<list|get|create> [...]",
|
|
139
|
+
summary: "List, get, create, and complete tasks across configured sources",
|
|
140
|
+
usage: "<list|get|create|done|validate> [...]",
|
|
141
141
|
invoke: taskCli,
|
|
142
142
|
},
|
|
143
143
|
status: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/commands/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EACL,KAAK,UAAU,EAGf,KAAK,KAAK,EAEX,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAWzD,UAAU,cAAc;IACtB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,CAAC,UAAU,EAAE;QACpB,KAAK,EAAE,UAAU,CAAC;QAClB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;QAC1C,+FAA+F;QAC/F,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;QACvD,MAAM,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB;;;;WAIG;QACH,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB;AAiCD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/commands/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EACL,KAAK,UAAU,EAGf,KAAK,KAAK,EAEX,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAWzD,UAAU,cAAc;IACtB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,CAAC,UAAU,EAAE;QACpB,KAAK,EAAE,UAAU,CAAC;QAClB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;QAC1C,+FAA+F;QAC/F,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;QACvD,MAAM,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB;;;;WAIG;QACH,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB;AAiCD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,CAoOjE;AA2BD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,MAAM,CAQrE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuQH,wBAAsB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,CAmF/C"}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
* Returns true if every required check passes; false otherwise.
|
|
4
4
|
*/
|
|
5
5
|
import { existsSync, statSync } from "node:fs";
|
|
6
|
-
import { createBoard } from "../lib/board.js";
|
|
7
6
|
import { buildSources, sourcesFromConfig } from "../lib/buildSources.js";
|
|
8
7
|
import { loadConfigWithSource, worktreeBaseDir, } from "../lib/config.js";
|
|
9
8
|
import { detectHostCapabilities, which } from "../lib/host.js";
|
|
10
9
|
import { isEnvironmentAssignment } from "../lib/launchCommand.js";
|
|
11
10
|
import { resolveLocalRunner } from "../lib/localRunner.js";
|
|
11
|
+
import { naturalIdFromCanonical } from "../lib/taskSource.js";
|
|
12
12
|
import { gatedAgents } from "../lib/usage.js";
|
|
13
13
|
import { errorMessage, writeOutput } from "../lib/util.js";
|
|
14
14
|
import { resolveWorkspaceKind } from "../lib/workspaces.js";
|
|
@@ -34,27 +34,97 @@ async function checkCmd(cmd, required, hint) {
|
|
|
34
34
|
}
|
|
35
35
|
return result;
|
|
36
36
|
}
|
|
37
|
+
function isRecord(value) {
|
|
38
|
+
return typeof value === "object" && value !== null;
|
|
39
|
+
}
|
|
37
40
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* "api key + reachability" probe so a misconfigured shell (or future Jira)
|
|
41
|
-
* source surfaces here too. A missing Linear API key still fails verify with
|
|
42
|
-
* its own user-facing message, so the prior behavior is preserved.
|
|
41
|
+
* True when a raw source config entry declares `kind: "shell"`. Gates the
|
|
42
|
+
* shell-only read probe.
|
|
43
43
|
*/
|
|
44
|
-
|
|
44
|
+
function isShellSource(raw) {
|
|
45
|
+
if (!isRecord(raw)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const { kind } = raw;
|
|
49
|
+
return kind === "shell";
|
|
50
|
+
}
|
|
51
|
+
function hasExplicitGetTaskCommand(raw) {
|
|
52
|
+
const { commands } = raw;
|
|
53
|
+
if (!isRecord(commands)) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const { getTask, resolveOne } = commands;
|
|
57
|
+
return typeof getTask === "string" || typeof resolveOne === "string";
|
|
58
|
+
}
|
|
59
|
+
function shellReadProbeFor(raw) {
|
|
60
|
+
if (!isShellSource(raw)) {
|
|
61
|
+
return "none";
|
|
62
|
+
}
|
|
63
|
+
return hasExplicitGetTaskCommand(raw) ? "listTasksAndGetTask" : "listTasks";
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Probe each configured task source independently and emit one `Check` per
|
|
67
|
+
* source (named `source: <name>`), so a single broken source is attributable
|
|
68
|
+
* instead of hidden behind an aggregate "N source(s) verified" line.
|
|
69
|
+
*
|
|
70
|
+
* Every source runs its `verify()`. Shell sources are additionally deep-probed
|
|
71
|
+
* via `listTasks()`: their `verify` command can discard stdout (e.g.
|
|
72
|
+
* `... fetch >/dev/null`), so a malformed task payload sails through verify and
|
|
73
|
+
* only blows up later in `crew run`. Running listTasks here surfaces a
|
|
74
|
+
* wrong-shape payload (a `TaskSourceOutputError` with a readable message) at
|
|
75
|
+
* doctor time. Non-shell sources (Linear) are left to `verify()` alone — their
|
|
76
|
+
* fetch is an expensive network call that verify already exercises.
|
|
77
|
+
*/
|
|
78
|
+
async function checkSourceProbes(config) {
|
|
79
|
+
const rawSources = sourcesFromConfig(config);
|
|
80
|
+
let sources;
|
|
45
81
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
};
|
|
82
|
+
sources = await buildSources(rawSources, { globalConfig: config });
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
// Building sources failed before any individual probe (bad config / unknown
|
|
86
|
+
// kind). Surface it as a single failed check rather than per-source.
|
|
87
|
+
return [{ name: "sources", ok: false, required: true, hint: errorMessage(error) }];
|
|
88
|
+
}
|
|
89
|
+
if (sources.length === 0) {
|
|
90
|
+
return [{ name: "sources", ok: false, required: true, hint: "no task sources configured" }];
|
|
91
|
+
}
|
|
92
|
+
const checks = [];
|
|
93
|
+
for (const [index, source] of sources.entries()) {
|
|
94
|
+
const shellReadProbe = shellReadProbeFor(rawSources[index]);
|
|
95
|
+
// oxlint-disable-next-line no-await-in-loop -- sequential keeps each verdict attributable to one source
|
|
96
|
+
checks.push(await probeSource(source, shellReadProbe));
|
|
97
|
+
}
|
|
98
|
+
return checks;
|
|
99
|
+
}
|
|
100
|
+
async function probeSource(source, shellReadProbe) {
|
|
101
|
+
const name = `source: ${source.name}`;
|
|
102
|
+
try {
|
|
103
|
+
await source.verify();
|
|
104
|
+
if (shellReadProbe === "none") {
|
|
105
|
+
return { name, ok: true, required: true, hint: "verified" };
|
|
106
|
+
}
|
|
107
|
+
const tasks = await source.listTasks();
|
|
108
|
+
const parts = [`fetched ${tasks.length} task(s)`];
|
|
109
|
+
// Read-path symmetry: an id listTasks emitted must resolve via getTask.
|
|
110
|
+
// Skipped when getTask is only the adapter's listTasks fallback, since that
|
|
111
|
+
// would just re-run listTasks and can race changing source output.
|
|
112
|
+
const [first] = tasks;
|
|
113
|
+
if (first !== undefined && shellReadProbe === "listTasksAndGetTask") {
|
|
114
|
+
const naturalId = naturalIdFromCanonical(first.id);
|
|
115
|
+
const resolved = await source.getTask(naturalId);
|
|
116
|
+
if (resolved === null) {
|
|
117
|
+
throw new Error(`getTask("${naturalId}") returned nothing, but listTasks emitted it`);
|
|
118
|
+
}
|
|
119
|
+
if (resolved.id !== first.id) {
|
|
120
|
+
throw new Error(`getTask("${naturalId}") resolved "${resolved.id}", but listTasks emitted "${first.id}"`);
|
|
121
|
+
}
|
|
122
|
+
parts.push("getTask round-trips");
|
|
123
|
+
}
|
|
124
|
+
return { name, ok: true, required: true, hint: `verified; ${parts.join("; ")}` };
|
|
55
125
|
}
|
|
56
126
|
catch (error) {
|
|
57
|
-
return { name
|
|
127
|
+
return { name, ok: false, required: true, hint: errorMessage(error) };
|
|
58
128
|
}
|
|
59
129
|
}
|
|
60
130
|
function checkDir(path, label) {
|
|
@@ -190,7 +260,7 @@ export async function doctor() {
|
|
|
190
260
|
const workspaceOutcome = resolveWorkspaceOutcome(config, host);
|
|
191
261
|
reportWorkspaceKind(config, workspaceOutcome);
|
|
192
262
|
const checks = [
|
|
193
|
-
await
|
|
263
|
+
...(await checkSourceProbes(config)),
|
|
194
264
|
await checkCmd("git", true, "https://git-scm.com/"),
|
|
195
265
|
...(await workspaceChecks(workspaceOutcome)),
|
|
196
266
|
checkDir(config.workspace.projectDir, "workspace.projectDir"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/commands/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/commands/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoEH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAiBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgE7E"}
|
|
@@ -8,7 +8,7 @@ import { createBoard } from "../lib/board.js";
|
|
|
8
8
|
import { buildSources, sourcesFromConfig } from "../lib/buildSources.js";
|
|
9
9
|
import { loadConfigWithSource } from "../lib/config.js";
|
|
10
10
|
import { findPullRequestsForBranch } from "../lib/pullRequests.js";
|
|
11
|
-
import { RepositoryResolutionError } from "../lib/taskSource.js";
|
|
11
|
+
import { RepositoryResolutionError, TaskSourceOutputError, } from "../lib/taskSource.js";
|
|
12
12
|
import { getUsageByAgent } from "../lib/usage.js";
|
|
13
13
|
import { errorMessage, log, sleep, writeOutput } from "../lib/util.js";
|
|
14
14
|
import { worktrees } from "../lib/worktrees.js";
|
|
@@ -30,6 +30,11 @@ async function withRetry(function_, signal, maxRetries = RETRY_MAX_ATTEMPTS, bas
|
|
|
30
30
|
if (error instanceof RepositoryResolutionError) {
|
|
31
31
|
throw error;
|
|
32
32
|
}
|
|
33
|
+
// A source returned unparseable output — deterministic, so retrying just
|
|
34
|
+
// delays a guaranteed failure behind confusing "Retrying in Ns" lines.
|
|
35
|
+
if (error instanceof TaskSourceOutputError) {
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
33
38
|
if (attempt === maxRetries) {
|
|
34
39
|
throw error;
|
|
35
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resumeWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/resumeWorkspace.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"resumeWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/resumeWorkspace.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAenE,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AA0ID,wBAAsB,eAAe,CACnC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA6Ef;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGtE"}
|
|
@@ -3,9 +3,10 @@ import { getLinearClient } from "../lib/adapters/linear/client.js";
|
|
|
3
3
|
import { isLinearEnabled } from "../lib/buildSources.js";
|
|
4
4
|
import { loadConfig } from "../lib/config.js";
|
|
5
5
|
import { composeAgentLaunch, openAgentWorkspace, prepareAgentLaunch } from "../lib/agentLaunch.js";
|
|
6
|
+
import { workerEnvironmentForTask } from "../lib/launchCommand.js";
|
|
6
7
|
import { readRunState, recordRunState } from "../lib/runState.js";
|
|
7
8
|
import { removeStagedPrompt, stageBuildSecrets, stagePromptText, stageWorkspaceLaunchCommand, } from "../lib/stagedLaunch.js";
|
|
8
|
-
import { naturalIdFromCanonical } from "../lib/taskSource.js";
|
|
9
|
+
import { naturalIdFromCanonical, toCanonicalId } from "../lib/taskSource.js";
|
|
9
10
|
import { errorMessage, log } from "../lib/util.js";
|
|
10
11
|
import { workspaces } from "../lib/workspaces.js";
|
|
11
12
|
import { resolveLaunchDir, worktrees } from "../lib/worktrees.js";
|
|
@@ -38,6 +39,7 @@ async function contextFromLinear(config, task, worktree) {
|
|
|
38
39
|
worktree,
|
|
39
40
|
title: resolved.title,
|
|
40
41
|
description: resolved.description,
|
|
42
|
+
completionTaskId: toCanonicalId("linear", task),
|
|
41
43
|
resumeCount: 0,
|
|
42
44
|
};
|
|
43
45
|
}
|
|
@@ -53,6 +55,7 @@ async function contextFromState(config, task, state, worktree) {
|
|
|
53
55
|
worktree,
|
|
54
56
|
title: details?.title ?? task.toUpperCase(),
|
|
55
57
|
description: details?.description ?? "",
|
|
58
|
+
completionTaskId: state.completionTaskId ?? task,
|
|
56
59
|
...(state.reason === undefined ? {} : { reason: state.reason }),
|
|
57
60
|
resumeCount: state.resumeCount,
|
|
58
61
|
};
|
|
@@ -147,6 +150,7 @@ export async function resumeWorkspace(config, options) {
|
|
|
147
150
|
workingDir: launchDir,
|
|
148
151
|
secretsFile,
|
|
149
152
|
sandboxName,
|
|
153
|
+
workerEnvironment: workerEnvironmentForTask(context.completionTaskId),
|
|
150
154
|
}));
|
|
151
155
|
const launchCmd = stageWorkspaceLaunchCommand(stagedPrompt.directory, launchCommand);
|
|
152
156
|
await openAgentWorkspace({
|
|
@@ -178,6 +182,7 @@ export async function resumeWorkspace(config, options) {
|
|
|
178
182
|
workspaceName: task,
|
|
179
183
|
state: "resumed",
|
|
180
184
|
resumeCount: context.resumeCount + 1,
|
|
185
|
+
completionTaskId: context.completionTaskId,
|
|
181
186
|
...(context.reason === undefined ? {} : { reason: context.reason }),
|
|
182
187
|
},
|
|
183
188
|
});
|
|
@@ -7,6 +7,8 @@ export interface TaskDetails {
|
|
|
7
7
|
}
|
|
8
8
|
export interface SetupWorkspaceOptions {
|
|
9
9
|
task: string;
|
|
10
|
+
/** Canonical source id for worker self-completion; falls back to `task`. */
|
|
11
|
+
completionTaskId?: string;
|
|
10
12
|
repository: string;
|
|
11
13
|
agent: string;
|
|
12
14
|
details: TaskDetails;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setupWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/setupWorkspace.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"setupWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/setupWorkspace.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAuBnE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAuBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,qBAAqB,EAC9B,UAAU,GAAE,wBAA6B,GACxC,OAAO,CAAC,IAAI,CAAC,CA8Hf;AAgJD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CA6Cf"}
|
|
@@ -3,6 +3,7 @@ import { loadConfig } from "../lib/config.js";
|
|
|
3
3
|
import { composeAgentLaunch, openAgentWorkspace, prepareAgentLaunch } from "../lib/agentLaunch.js";
|
|
4
4
|
import { createBoard } from "../lib/board.js";
|
|
5
5
|
import { buildSources, sourcesFromConfig } from "../lib/buildSources.js";
|
|
6
|
+
import { workerEnvironmentForTask } from "../lib/launchCommand.js";
|
|
6
7
|
import { resolvePrepareWorktreeCommand } from "../lib/repositoryHooks.js";
|
|
7
8
|
import { recordRunState } from "../lib/runState.js";
|
|
8
9
|
import { stageBuildSecrets, stagePromptFromTemplate, stageWorkspaceLaunchCommand, } from "../lib/stagedLaunch.js";
|
|
@@ -80,6 +81,7 @@ export async function setupWorkspace(config, options, runOptions = {}) {
|
|
|
80
81
|
defaultHooks: config.defaults.hooks,
|
|
81
82
|
});
|
|
82
83
|
const secretsFile = prepareWorktreeCommand === undefined ? undefined : stageBuildSecrets(promptDir);
|
|
84
|
+
const completionTaskId = options.completionTaskId ?? task;
|
|
83
85
|
const { launchCommand, srtSettingsDir: stagedSrtSettingsDir } = composeAgentLaunch({
|
|
84
86
|
runner,
|
|
85
87
|
task,
|
|
@@ -90,6 +92,7 @@ export async function setupWorkspace(config, options, runOptions = {}) {
|
|
|
90
92
|
secretsFile,
|
|
91
93
|
prepareWorktreeCommand,
|
|
92
94
|
sandboxName,
|
|
95
|
+
workerEnvironment: workerEnvironmentForTask(completionTaskId),
|
|
93
96
|
});
|
|
94
97
|
srtSettingsDir = stagedSrtSettingsDir;
|
|
95
98
|
const launchCmd = stageWorkspaceLaunchCommand(promptDir, launchCommand);
|
|
@@ -113,6 +116,7 @@ export async function setupWorkspace(config, options, runOptions = {}) {
|
|
|
113
116
|
workspaceName: task,
|
|
114
117
|
state: "running",
|
|
115
118
|
title: taskDetails.title,
|
|
119
|
+
completionTaskId,
|
|
116
120
|
...(taskDetails.url === undefined ? {} : { url: taskDetails.url }),
|
|
117
121
|
});
|
|
118
122
|
log(`${okMark()} "${task}" launched (${agent}) worktree ${worktreeName}`);
|
|
@@ -135,6 +139,7 @@ export async function setupWorkspace(config, options, runOptions = {}) {
|
|
|
135
139
|
state: "failed-to-launch",
|
|
136
140
|
detail: errorMessage(error),
|
|
137
141
|
title: options.details.title,
|
|
142
|
+
completionTaskId: options.completionTaskId ?? task,
|
|
138
143
|
...(options.details.url === undefined ? {} : { url: options.details.url }),
|
|
139
144
|
});
|
|
140
145
|
throw error;
|
|
@@ -197,6 +202,7 @@ function recordRunStateBestEffort(arguments_) {
|
|
|
197
202
|
workspaceName: arguments_.workspaceName,
|
|
198
203
|
state: arguments_.state,
|
|
199
204
|
title: arguments_.title,
|
|
205
|
+
completionTaskId: arguments_.completionTaskId,
|
|
200
206
|
...(arguments_.detail === undefined ? {} : { detail: arguments_.detail }),
|
|
201
207
|
...(arguments_.url === undefined ? {} : { url: arguments_.url }),
|
|
202
208
|
},
|
|
@@ -275,6 +281,7 @@ export async function setupWorkspaceCli(task, options = {}) {
|
|
|
275
281
|
const naturalId = naturalIdFromCanonical(resolved.id);
|
|
276
282
|
await setupWorkspace(config, {
|
|
277
283
|
task: naturalId,
|
|
284
|
+
completionTaskId: resolved.id,
|
|
278
285
|
repository: resolved.repository,
|
|
279
286
|
agent: resolved.agent,
|
|
280
287
|
details: {
|
|
@@ -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":"AAoyBA,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB3D"}
|
package/dist/commands/task.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import { createBoard } from "../lib/board.js";
|
|
1
2
|
import { buildSources, sourcesFromConfig } from "../lib/buildSources.js";
|
|
2
3
|
import { AGENT_ANY, loadConfig } from "../lib/config.js";
|
|
4
|
+
import { findPullRequestsForBranch } from "../lib/pullRequests.js";
|
|
3
5
|
import { naturalIdFromCanonical, } from "../lib/taskSource.js";
|
|
4
6
|
import { parseSourceFilterArgs, writeOutput } from "../lib/util.js";
|
|
7
|
+
import { worktrees } from "../lib/worktrees.js";
|
|
5
8
|
const TASK_USAGE = `Usage: crew task <subcommand>
|
|
6
9
|
|
|
7
10
|
Subcommands:
|
|
8
11
|
list [options] List tasks across configured sources
|
|
9
12
|
get <task-id> [options] Get one task
|
|
10
13
|
create "Short title" [options] Create one task
|
|
14
|
+
done <task-id> [options] Mark one task done
|
|
11
15
|
validate [source] [options] Validate task content`;
|
|
12
16
|
const LIST_USAGE = `Usage: crew task list [options]
|
|
13
17
|
|
|
@@ -27,6 +31,7 @@ Options:
|
|
|
27
31
|
--json Print normalized task JSON.
|
|
28
32
|
--prompt Print only the task description/prompt.`;
|
|
29
33
|
const CREATE_USAGE = `Usage: crew task create "Short title" --source <source> [--agent <agent>] [options]`;
|
|
34
|
+
const DONE_USAGE = `Usage: crew task done <task-id> [--allow-dirty]`;
|
|
30
35
|
const CANONICAL_STATUSES = [
|
|
31
36
|
"todo",
|
|
32
37
|
"in-progress",
|
|
@@ -251,10 +256,34 @@ function parseCreateOptions(argv) {
|
|
|
251
256
|
};
|
|
252
257
|
return { title, sourceName: state.sourceName, input, json: state.json };
|
|
253
258
|
}
|
|
259
|
+
function parseDoneOptions(argv) {
|
|
260
|
+
const positionals = [];
|
|
261
|
+
let allowDirty = false;
|
|
262
|
+
for (const argument of argv) {
|
|
263
|
+
if (argument === "--allow-dirty") {
|
|
264
|
+
allowDirty = true;
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (argument.startsWith("-")) {
|
|
268
|
+
throw new Error(`crew task done: unknown option: ${argument}\n${DONE_USAGE}`);
|
|
269
|
+
}
|
|
270
|
+
positionals.push(argument);
|
|
271
|
+
}
|
|
272
|
+
const [taskId, ...extras] = positionals;
|
|
273
|
+
if (taskId === undefined || taskId.length === 0 || extras.length > 0) {
|
|
274
|
+
throw new Error(DONE_USAGE);
|
|
275
|
+
}
|
|
276
|
+
return { taskId, allowDirty };
|
|
277
|
+
}
|
|
254
278
|
async function loadTaskSources() {
|
|
255
279
|
const config = await loadConfig();
|
|
256
280
|
return await buildSources(sourcesFromConfig(config), { globalConfig: config });
|
|
257
281
|
}
|
|
282
|
+
async function loadTaskBoard() {
|
|
283
|
+
const config = await loadConfig();
|
|
284
|
+
const sources = await buildSources(sourcesFromConfig(config), { globalConfig: config });
|
|
285
|
+
return { config, board: createBoard(sources) };
|
|
286
|
+
}
|
|
258
287
|
function findSource(sources, sourceName) {
|
|
259
288
|
const source = sources.find((candidate) => candidate.name === sourceName);
|
|
260
289
|
if (source === undefined) {
|
|
@@ -472,6 +501,60 @@ async function taskCreateCli(argv) {
|
|
|
472
501
|
}
|
|
473
502
|
writeOutput(created.id);
|
|
474
503
|
}
|
|
504
|
+
function matchingWorktreeEntries(arguments_) {
|
|
505
|
+
const task = naturalIdFromCanonical(arguments_.issue.id);
|
|
506
|
+
return worktrees
|
|
507
|
+
.findByTask(arguments_.config, task)
|
|
508
|
+
.filter((entry) => arguments_.issue.repository === undefined ||
|
|
509
|
+
entry.repository === arguments_.issue.repository);
|
|
510
|
+
}
|
|
511
|
+
function describeDirtiness(dirtiness) {
|
|
512
|
+
if (dirtiness.kind === "dirty") {
|
|
513
|
+
return `${dirtiness.modified} modified, ${dirtiness.untracked} untracked`;
|
|
514
|
+
}
|
|
515
|
+
return "unknown git status";
|
|
516
|
+
}
|
|
517
|
+
async function worktreeHasPullRequest(entry) {
|
|
518
|
+
const pullRequests = await findPullRequestsForBranch({
|
|
519
|
+
cwd: entry.dir,
|
|
520
|
+
branchName: entry.branchName,
|
|
521
|
+
});
|
|
522
|
+
return pullRequests.length > 0;
|
|
523
|
+
}
|
|
524
|
+
async function assertCanMarkDone(arguments_) {
|
|
525
|
+
if (arguments_.allowDirty) {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
for (const entry of matchingWorktreeEntries({
|
|
529
|
+
config: arguments_.config,
|
|
530
|
+
issue: arguments_.issue,
|
|
531
|
+
})) {
|
|
532
|
+
// oxlint-disable-next-line no-await-in-loop -- one git status per matching worktree keeps diagnostics deterministic.
|
|
533
|
+
const dirtiness = await worktrees.probeWorkingTree({ worktreeDir: entry.dir });
|
|
534
|
+
if (dirtiness.kind === "clean") {
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
// oxlint-disable-next-line no-await-in-loop -- only dirty/unknown worktrees need the PR lookup.
|
|
538
|
+
if (dirtiness.kind === "dirty" && (await worktreeHasPullRequest(entry))) {
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
throw new Error(`crew task done: refusing to mark ${arguments_.issue.id} done because ${entry.dir} has ${describeDirtiness(dirtiness)} and no matching PR. Commit or stash the work, open a PR, or rerun with --allow-dirty.`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
async function taskDoneCli(argv) {
|
|
545
|
+
const options = parseDoneOptions(argv);
|
|
546
|
+
const { config, board } = await loadTaskBoard();
|
|
547
|
+
const issue = await board.resolveOne(options.taskId);
|
|
548
|
+
if (issue === undefined) {
|
|
549
|
+
throw new Error(`Task ${options.taskId} not found across configured sources.`);
|
|
550
|
+
}
|
|
551
|
+
await assertCanMarkDone({ config, issue, allowDirty: options.allowDirty });
|
|
552
|
+
const result = await board.markDone(issue);
|
|
553
|
+
if (result.outcome === "unsupported") {
|
|
554
|
+
throw new Error(`crew task done: ${result.reason}`);
|
|
555
|
+
}
|
|
556
|
+
writeOutput(`Marked ${issue.id} done.`);
|
|
557
|
+
}
|
|
475
558
|
const VALIDATE_USAGE = `Usage: crew task validate [source]
|
|
476
559
|
|
|
477
560
|
Options:
|
|
@@ -536,6 +619,10 @@ export async function taskCli(argv) {
|
|
|
536
619
|
await taskCreateCli(rest);
|
|
537
620
|
return;
|
|
538
621
|
}
|
|
622
|
+
if (verb === "done") {
|
|
623
|
+
await taskDoneCli(rest);
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
539
626
|
if (verb === "validate") {
|
|
540
627
|
await taskValidateCli(rest);
|
|
541
628
|
return;
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAK7B,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,CAsMZ"}
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
import { toCanonicalId, } from "../../taskSource.js";
|
|
23
23
|
import { errorMessage, writeError } from "../../util.js";
|
|
24
24
|
import { invokeShellCommand } from "./invoke.js";
|
|
25
|
+
import { parseShellJson } from "./parseOutput.js";
|
|
25
26
|
import { shellFetchOutputSchema, shellIssueSchema, shellValidateOutputSchema, } from "./schema.js";
|
|
26
27
|
const DEFAULT_TIMEOUTS = {
|
|
27
28
|
verify: 10_000,
|
|
@@ -134,7 +135,10 @@ export function createShellTaskSource(config, _context) {
|
|
|
134
135
|
env: config.env,
|
|
135
136
|
sourceName,
|
|
136
137
|
});
|
|
137
|
-
const parsed = shellFetchOutputSchema
|
|
138
|
+
const parsed = parseShellJson(shellFetchOutputSchema, stdout, {
|
|
139
|
+
sourceName,
|
|
140
|
+
command: "listTasks",
|
|
141
|
+
});
|
|
138
142
|
return parsed.map((si) => toCanonicalIssue(si, sourceName));
|
|
139
143
|
}
|
|
140
144
|
async function getTask(naturalId) {
|
|
@@ -158,7 +162,10 @@ export function createShellTaskSource(config, _context) {
|
|
|
158
162
|
if (result.exitCode === 3 || result.stdout.trim().length === 0) {
|
|
159
163
|
return null;
|
|
160
164
|
}
|
|
161
|
-
const parsed = shellIssueSchema
|
|
165
|
+
const parsed = parseShellJson(shellIssueSchema, result.stdout, {
|
|
166
|
+
sourceName,
|
|
167
|
+
command: "getTask",
|
|
168
|
+
});
|
|
162
169
|
return toCanonicalIssue(parsed, sourceName);
|
|
163
170
|
}
|
|
164
171
|
// Shared by markInProgress / markInReview: both pipe the canonical issue's
|
|
@@ -259,7 +266,10 @@ export function createShellTaskSource(config, _context) {
|
|
|
259
266
|
if (trimmed.length === 0) {
|
|
260
267
|
throw new Error(`shell source "${sourceName}" createTask command produced no output (expected one ShellIssue JSON)`);
|
|
261
268
|
}
|
|
262
|
-
const parsed = shellIssueSchema
|
|
269
|
+
const parsed = parseShellJson(shellIssueSchema, trimmed, {
|
|
270
|
+
sourceName,
|
|
271
|
+
command: "createTask",
|
|
272
|
+
});
|
|
263
273
|
return toCanonicalIssue(parsed, sourceName);
|
|
264
274
|
};
|
|
265
275
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Friendly stdout parsing for the shell adapter. A shell source emits JSON on
|
|
3
|
+
* stdout; both `JSON.parse` and the Zod schema can reject it. A raw `ZodError`
|
|
4
|
+
* stringifies to a JSON array of issues — cryptic, unattributed, and (for a
|
|
5
|
+
* fetch array) repeated once per task. This module collapses that into a
|
|
6
|
+
* single user-facing `TaskSourceOutputError` that names the source, the
|
|
7
|
+
* command, and the offending field(s), with a targeted hint for the common
|
|
8
|
+
* "missing `agent`" mistake.
|
|
9
|
+
*/
|
|
10
|
+
import type { z } from "zod";
|
|
11
|
+
export interface ShellParseContext {
|
|
12
|
+
/** The source's configured `name`, surfaced so the user knows which source broke. */
|
|
13
|
+
sourceName: string;
|
|
14
|
+
/** The contract method that produced the output, e.g. `"listTasks"` or `"getTask"`. */
|
|
15
|
+
command: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parse `stdout` as JSON and validate it against `schema`. On any failure,
|
|
19
|
+
* throws a `TaskSourceOutputError` with a readable, source-attributed message
|
|
20
|
+
* instead of a raw `SyntaxError` / `ZodError`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseShellJson<T>(schema: z.ZodType<T>, stdout: string, context: ShellParseContext): T;
|
|
23
|
+
//# sourceMappingURL=parseOutput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseOutput.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/shell/parseOutput.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAK7B,MAAM,WAAW,iBAAiB;IAChC,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,GACzB,CAAC,CAcH"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Friendly stdout parsing for the shell adapter. A shell source emits JSON on
|
|
3
|
+
* stdout; both `JSON.parse` and the Zod schema can reject it. A raw `ZodError`
|
|
4
|
+
* stringifies to a JSON array of issues — cryptic, unattributed, and (for a
|
|
5
|
+
* fetch array) repeated once per task. This module collapses that into a
|
|
6
|
+
* single user-facing `TaskSourceOutputError` that names the source, the
|
|
7
|
+
* command, and the offending field(s), with a targeted hint for the common
|
|
8
|
+
* "missing `agent`" mistake.
|
|
9
|
+
*/
|
|
10
|
+
import { TaskSourceOutputError } from "../../taskSource.js";
|
|
11
|
+
import { errorMessage } from "../../util.js";
|
|
12
|
+
/**
|
|
13
|
+
* Parse `stdout` as JSON and validate it against `schema`. On any failure,
|
|
14
|
+
* throws a `TaskSourceOutputError` with a readable, source-attributed message
|
|
15
|
+
* instead of a raw `SyntaxError` / `ZodError`.
|
|
16
|
+
*/
|
|
17
|
+
export function parseShellJson(schema, stdout, context) {
|
|
18
|
+
let json;
|
|
19
|
+
try {
|
|
20
|
+
json = JSON.parse(stdout);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
throw new TaskSourceOutputError(`source "${context.sourceName}": the ${context.command} command did not return valid JSON (${errorMessage(error)}).`);
|
|
24
|
+
}
|
|
25
|
+
const result = schema.safeParse(json);
|
|
26
|
+
if (result.success) {
|
|
27
|
+
return result.data;
|
|
28
|
+
}
|
|
29
|
+
throw new TaskSourceOutputError(formatSchemaError(result.error, context));
|
|
30
|
+
}
|
|
31
|
+
/** The last string segment of an issue path — the field name, ignoring array indices. */
|
|
32
|
+
function fieldName(path) {
|
|
33
|
+
for (let index = path.length - 1; index >= 0; index -= 1) {
|
|
34
|
+
const segment = path[index];
|
|
35
|
+
if (typeof segment === "string") {
|
|
36
|
+
return segment;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
/** One human-readable phrase describing what's wrong with a single issue. */
|
|
42
|
+
function describeIssue(issue) {
|
|
43
|
+
const field = fieldName(issue.path);
|
|
44
|
+
const label = field === undefined ? "field" : `"${field}"`;
|
|
45
|
+
// Zod v4 reports a missing required key as an `invalid_type` whose message
|
|
46
|
+
// ends in "received undefined"; there is no separate `received` property to
|
|
47
|
+
// branch on, so we match the message.
|
|
48
|
+
if (issue.code === "invalid_type" && issue.message.includes("received undefined")) {
|
|
49
|
+
return `are missing the required ${label} field`;
|
|
50
|
+
}
|
|
51
|
+
return `have an invalid ${label} field: ${issue.message}`;
|
|
52
|
+
}
|
|
53
|
+
function formatSchemaError(error, context) {
|
|
54
|
+
// A fetch array yields one issue per task (48 tasks missing `agent` → 48
|
|
55
|
+
// identical issues). Collapse identical phrasings into a single counted line,
|
|
56
|
+
// preserving first-seen order via the Map's insertion order.
|
|
57
|
+
const counts = new Map();
|
|
58
|
+
for (const issue of error.issues) {
|
|
59
|
+
const description = describeIssue(issue);
|
|
60
|
+
counts.set(description, (counts.get(description) ?? 0) + 1);
|
|
61
|
+
}
|
|
62
|
+
const lines = [...counts].map(([description, count]) => ` • ${count} issue(s) ${description}`);
|
|
63
|
+
return [
|
|
64
|
+
`source "${context.sourceName}": the ${context.command} command returned task JSON that doesn't match the expected shape:`,
|
|
65
|
+
...lines,
|
|
66
|
+
].join("\n");
|
|
67
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type LocalRunner, type AgentDefinition, type ResolvedConfig } from "./config.ts";
|
|
2
|
+
import { type WorkerEnvironment } from "./launchCommand.ts";
|
|
2
3
|
/**
|
|
3
4
|
* Stage any srt settings and build the workspace launch command — the assembly
|
|
4
5
|
* shared verbatim by `setupWorkspace` (fresh runs) and `resumeWorkspace`
|
|
@@ -16,6 +17,7 @@ export declare function composeAgentLaunch(input: {
|
|
|
16
17
|
secretsFile?: string | undefined;
|
|
17
18
|
prepareWorktreeCommand?: string | undefined;
|
|
18
19
|
sandboxName?: string | undefined;
|
|
20
|
+
workerEnvironment?: WorkerEnvironment | undefined;
|
|
19
21
|
}): {
|
|
20
22
|
launchCommand: string;
|
|
21
23
|
srtSettingsDir: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentLaunch.d.ts","sourceRoot":"","sources":["../../src/lib/agentLaunch.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"agentLaunch.d.ts","sourceRoot":"","sources":["../../src/lib/agentLaunch.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAOhF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,eAAe,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,sBAAsB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CACnD,GAAG;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CA2BhE;AAsBD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,eAAe,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAqD/B;AAwBD,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB"}
|