@clipboard-health/groundcrew 4.52.6 → 4.52.8
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 +3 -0
- package/crew.config.example.ts +14 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/commands/completions.d.ts.map +1 -1
- package/dist/commands/completions.js +17 -0
- package/dist/commands/orchestrator.d.ts.map +1 -1
- package/dist/commands/orchestrator.js +3 -0
- package/dist/commands/prStageSync.d.ts +74 -0
- package/dist/commands/prStageSync.d.ts.map +1 -0
- package/dist/commands/prStageSync.js +397 -0
- package/dist/commands/stage.d.ts +9 -0
- package/dist/commands/stage.d.ts.map +1 -0
- package/dist/commands/stage.js +138 -0
- package/dist/lib/cmuxAdapter.d.ts +15 -0
- package/dist/lib/cmuxAdapter.d.ts.map +1 -1
- package/dist/lib/cmuxAdapter.js +62 -1
- package/dist/lib/cmuxStatusFields.d.ts +33 -0
- package/dist/lib/cmuxStatusFields.d.ts.map +1 -0
- package/dist/lib/cmuxStatusFields.js +62 -0
- package/dist/lib/config.d.ts +42 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +51 -0
- package/dist/lib/prStageRules.d.ts +40 -0
- package/dist/lib/prStageRules.d.ts.map +1 -0
- package/dist/lib/prStageRules.js +108 -0
- package/dist/lib/pullRequestDetails.d.ts +26 -0
- package/dist/lib/pullRequestDetails.d.ts.map +1 -0
- package/dist/lib/pullRequestDetails.js +114 -0
- package/dist/lib/pullRequests.d.ts +7 -0
- package/dist/lib/pullRequests.d.ts.map +1 -1
- package/dist/lib/pullRequests.js +27 -15
- package/dist/lib/workspaces.d.ts.map +1 -1
- package/dist/lib/workspaces.js +2 -11
- package/docs/commands.md +12 -0
- package/docs/configuration.md +36 -33
- package/docs/troubleshooting.md +4 -5
- package/package.json +7 -7
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `crew stage` — operator commands for `pr-stage-sync`'s two gating labels
|
|
3
|
+
* (`label-add` / `label-remove`) and an on-demand sync pass (`refresh`).
|
|
4
|
+
* Labels are restricted to the two names configured under
|
|
5
|
+
* `cmux.prStages.labels`; each is created in the PR's repo on first use with
|
|
6
|
+
* a fixed color so the two gates stay visually distinct in GitHub's label UI.
|
|
7
|
+
*/
|
|
8
|
+
import { runCommandAsync } from "../lib/commandRunner.js";
|
|
9
|
+
import { loadConfig } from "../lib/config.js";
|
|
10
|
+
import { worktrees } from "../lib/worktrees.js";
|
|
11
|
+
import { createPrStageSync, createPrStageSyncDeps } from "./prStageSync.js";
|
|
12
|
+
const PULL_REQUEST_URL_PATTERN = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)$/;
|
|
13
|
+
const LABEL_COLORS = {
|
|
14
|
+
selfReviewed: "5319E7",
|
|
15
|
+
tested: "0E8A16",
|
|
16
|
+
};
|
|
17
|
+
const STAGE_USAGE = `Usage: crew stage <subcommand>
|
|
18
|
+
|
|
19
|
+
Subcommands:
|
|
20
|
+
label-add <pr-url> <label> Add a configured gating label to a pull request
|
|
21
|
+
label-remove <pr-url> <label> Remove a configured gating label from a pull request
|
|
22
|
+
refresh Run one pr-stage-sync pass now`;
|
|
23
|
+
function parsePullRequestUrl(url) {
|
|
24
|
+
const match = PULL_REQUEST_URL_PATTERN.exec(url);
|
|
25
|
+
const [, owner, repo] = match ?? [];
|
|
26
|
+
if (owner === undefined || repo === undefined) {
|
|
27
|
+
throw new Error(`crew stage: invalid pull request URL: ${url}\nExpected https://github.com/<owner>/<repo>/pull/<number>`);
|
|
28
|
+
}
|
|
29
|
+
return { owner, repo };
|
|
30
|
+
}
|
|
31
|
+
function resolveLabelRole(label, labels) {
|
|
32
|
+
if (label === labels.selfReviewed) {
|
|
33
|
+
return "selfReviewed";
|
|
34
|
+
}
|
|
35
|
+
if (label === labels.tested) {
|
|
36
|
+
return "tested";
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`crew stage: unknown label: ${label}\nConfigured labels are "${labels.selfReviewed}" and "${labels.tested}" (cmux.prStages.labels).`);
|
|
39
|
+
}
|
|
40
|
+
function isRecord(value) {
|
|
41
|
+
return typeof value === "object" && value !== null;
|
|
42
|
+
}
|
|
43
|
+
function isGithubLabelNamed(value, label) {
|
|
44
|
+
return isRecord(value) && value["name"] === label;
|
|
45
|
+
}
|
|
46
|
+
async function labelExists(repo, label) {
|
|
47
|
+
const output = await runCommandAsync("gh", [
|
|
48
|
+
"label",
|
|
49
|
+
"list",
|
|
50
|
+
"--repo",
|
|
51
|
+
repo,
|
|
52
|
+
"--search",
|
|
53
|
+
label,
|
|
54
|
+
"--json",
|
|
55
|
+
"name",
|
|
56
|
+
]);
|
|
57
|
+
let parsed;
|
|
58
|
+
try {
|
|
59
|
+
parsed = JSON.parse(output);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
if (!Array.isArray(parsed)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return parsed.some((entry) => isGithubLabelNamed(entry, label));
|
|
68
|
+
}
|
|
69
|
+
async function ensureLabelExists(repo, label, role) {
|
|
70
|
+
if (await labelExists(repo, label)) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
await runCommandAsync("gh", [
|
|
74
|
+
"label",
|
|
75
|
+
"create",
|
|
76
|
+
label,
|
|
77
|
+
"--repo",
|
|
78
|
+
repo,
|
|
79
|
+
"--color",
|
|
80
|
+
LABEL_COLORS[role],
|
|
81
|
+
"--force",
|
|
82
|
+
]);
|
|
83
|
+
}
|
|
84
|
+
async function syncOnce(config) {
|
|
85
|
+
const prStageSync = createPrStageSync(createPrStageSyncDeps(config));
|
|
86
|
+
const worktreeEntries = worktrees.list(config);
|
|
87
|
+
await prStageSync.syncOnce({ worktreeEntries });
|
|
88
|
+
}
|
|
89
|
+
function parseLabelCliArgs(argv, usage) {
|
|
90
|
+
const [prUrl, label, ...extras] = argv;
|
|
91
|
+
if (prUrl === undefined || label === undefined || extras.length > 0) {
|
|
92
|
+
throw new Error(usage);
|
|
93
|
+
}
|
|
94
|
+
return { prUrl, label };
|
|
95
|
+
}
|
|
96
|
+
const LABEL_ADD_USAGE = "Usage: crew stage label-add <pr-url> <label>";
|
|
97
|
+
const LABEL_REMOVE_USAGE = "Usage: crew stage label-remove <pr-url> <label>";
|
|
98
|
+
async function stageLabelAddCli(argv) {
|
|
99
|
+
const { prUrl, label } = parseLabelCliArgs(argv, LABEL_ADD_USAGE);
|
|
100
|
+
const config = await loadConfig();
|
|
101
|
+
const role = resolveLabelRole(label, config.cmux.prStages.labels);
|
|
102
|
+
const { repo: repoName, owner } = parsePullRequestUrl(prUrl);
|
|
103
|
+
const repo = `${owner}/${repoName}`;
|
|
104
|
+
await ensureLabelExists(repo, label, role);
|
|
105
|
+
await runCommandAsync("gh", ["pr", "edit", prUrl, "--add-label", label]);
|
|
106
|
+
await syncOnce(config);
|
|
107
|
+
}
|
|
108
|
+
async function stageLabelRemoveCli(argv) {
|
|
109
|
+
const { prUrl, label } = parseLabelCliArgs(argv, LABEL_REMOVE_USAGE);
|
|
110
|
+
const config = await loadConfig();
|
|
111
|
+
resolveLabelRole(label, config.cmux.prStages.labels);
|
|
112
|
+
parsePullRequestUrl(prUrl);
|
|
113
|
+
await runCommandAsync("gh", ["pr", "edit", prUrl, "--remove-label", label]);
|
|
114
|
+
await syncOnce(config);
|
|
115
|
+
}
|
|
116
|
+
async function stageRefreshCli(argv) {
|
|
117
|
+
if (argv.length > 0) {
|
|
118
|
+
throw new Error("Usage: crew stage refresh");
|
|
119
|
+
}
|
|
120
|
+
const config = await loadConfig();
|
|
121
|
+
await syncOnce(config);
|
|
122
|
+
}
|
|
123
|
+
export async function stageCli(argv) {
|
|
124
|
+
const [verb, ...rest] = argv;
|
|
125
|
+
if (verb === "label-add") {
|
|
126
|
+
await stageLabelAddCli(rest);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (verb === "label-remove") {
|
|
130
|
+
await stageLabelRemoveCli(rest);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (verb === "refresh") {
|
|
134
|
+
await stageRefreshCli(rest);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
throw new Error(STAGE_USAGE);
|
|
138
|
+
}
|
|
@@ -5,4 +5,19 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { type Adapter } from "./workspaceAdapter.ts";
|
|
7
7
|
export declare const cmuxAdapter: Adapter;
|
|
8
|
+
/** A live cmux workspace, shaped for `pr-stage-sync` matching: its stable id (to target with `set-status`/`clear-status`), the task id it carries (or its title, for legacy workspaces), its title, and cmux's reported cwd. */
|
|
9
|
+
export interface CmuxWorkspaceSummary {
|
|
10
|
+
/** Stable id to pass as `--workspace` to status commands. */
|
|
11
|
+
id: string;
|
|
12
|
+
taskId: string;
|
|
13
|
+
title: string;
|
|
14
|
+
currentDirectory: string | undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Enumerates live cmux workspaces for `pr-stage-sync`, independent of the
|
|
18
|
+
* `Adapter.list()` contract (which returns only `{name}` for workspace-probe
|
|
19
|
+
* purposes). Returns `undefined` on the same unavailable-vs-empty terms as
|
|
20
|
+
* `listCmuxRaw`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function listCmuxWorkspaceSummaries(signal?: AbortSignal): Promise<CmuxWorkspaceSummary[] | undefined>;
|
|
8
23
|
//# sourceMappingURL=cmuxAdapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cmuxAdapter.d.ts","sourceRoot":"","sources":["../../src/lib/cmuxAdapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"cmuxAdapter.d.ts","sourceRoot":"","sources":["../../src/lib/cmuxAdapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EACL,KAAK,OAAO,EAKb,MAAM,uBAAuB,CAAC;AAG/B,eAAO,MAAM,WAAW,EAAE,OA+FzB,CAAC;AAsGF,gOAAgO;AAChO,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,oBAAoB,EAAE,GAAG,SAAS,CAAC,CAQ7C"}
|
package/dist/lib/cmuxAdapter.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* own app, so `accessHint` has nothing concise to emit. cmux can paint a
|
|
4
4
|
* per-workspace status pill, which `open` applies best-effort.
|
|
5
5
|
*/
|
|
6
|
+
import { TICKET_KEY, TICKET_PRIORITY, writeCmuxStatus } from "./cmuxStatusFields.js";
|
|
7
|
+
import { deriveTicket } from "./prStageRules.js";
|
|
6
8
|
import { isSignalAborted, runWorkspaceCommand, } from "./workspaceAdapter.js";
|
|
7
9
|
import { debug, errorMessage, log, logEvent } from "./util.js";
|
|
8
10
|
export const cmuxAdapter = {
|
|
@@ -50,6 +52,15 @@ export const cmuxAdapter = {
|
|
|
50
52
|
signal,
|
|
51
53
|
});
|
|
52
54
|
}
|
|
55
|
+
await writeCrewTicketBestEffort({
|
|
56
|
+
workspaceId,
|
|
57
|
+
taskId: spec.name,
|
|
58
|
+
derivedTicket: deriveTicket({
|
|
59
|
+
title: spec.displayName ?? spec.name,
|
|
60
|
+
currentDirectory: spec.cwd,
|
|
61
|
+
}),
|
|
62
|
+
...(signal === undefined ? {} : { signal }),
|
|
63
|
+
});
|
|
53
64
|
},
|
|
54
65
|
async list(signal) {
|
|
55
66
|
const raw = await listCmuxRaw(signal);
|
|
@@ -121,7 +132,14 @@ function parseCmuxList(output) {
|
|
|
121
132
|
debug(`cmux workspace list returned workspace "${ws.title}" without a usable id or ref; skipping`);
|
|
122
133
|
continue;
|
|
123
134
|
}
|
|
124
|
-
items.push({
|
|
135
|
+
items.push({
|
|
136
|
+
title: ws.title,
|
|
137
|
+
id,
|
|
138
|
+
description: ws.description ?? null,
|
|
139
|
+
...(typeof ws.current_directory === "string"
|
|
140
|
+
? { currentDirectory: ws.current_directory }
|
|
141
|
+
: {}),
|
|
142
|
+
});
|
|
125
143
|
}
|
|
126
144
|
return items;
|
|
127
145
|
}
|
|
@@ -153,6 +171,21 @@ async function listCmuxRaw(signal) {
|
|
|
153
171
|
return undefined;
|
|
154
172
|
}
|
|
155
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Enumerates live cmux workspaces for `pr-stage-sync`, independent of the
|
|
176
|
+
* `Adapter.list()` contract (which returns only `{name}` for workspace-probe
|
|
177
|
+
* purposes). Returns `undefined` on the same unavailable-vs-empty terms as
|
|
178
|
+
* `listCmuxRaw`.
|
|
179
|
+
*/
|
|
180
|
+
export async function listCmuxWorkspaceSummaries(signal) {
|
|
181
|
+
const raw = await listCmuxRaw(signal);
|
|
182
|
+
return raw?.map((ws) => ({
|
|
183
|
+
id: ws.id,
|
|
184
|
+
taskId: cmuxTaskId(ws),
|
|
185
|
+
title: ws.title,
|
|
186
|
+
currentDirectory: ws.currentDirectory,
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
156
189
|
function extractCmuxOpenId(output) {
|
|
157
190
|
try {
|
|
158
191
|
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- cmux --json prints a workspace_id/ref object
|
|
@@ -172,6 +205,34 @@ function extractCmuxOpenId(output) {
|
|
|
172
205
|
const match = /workspace:\d+/.exec(output);
|
|
173
206
|
return match ? match[0] : undefined;
|
|
174
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Written the moment a workspace exists, so a brand-new ticket-shaped
|
|
210
|
+
* workspace shows its ticket pill and `Cleanup workspace` action
|
|
211
|
+
* immediately, without waiting on an orchestrator tick (`pr-stage-sync.ts`'s
|
|
212
|
+
* ticket-only pass covers every tick after this one, including when
|
|
213
|
+
* `cmux.prStages.enabled` is false). `derivedTicket` must use the exact same
|
|
214
|
+
* `deriveTicket` rule the sync loop applies on every subsequent tick — a raw
|
|
215
|
+
* task id (which may be a whole branch slug, lowercase, or carry no ticket
|
|
216
|
+
* at all) would disagree with that derivation and either flicker to a
|
|
217
|
+
* different value or paint a bogus Linear link on the very first sync.
|
|
218
|
+
* `undefined` skips the write entirely rather than clearing a key that was
|
|
219
|
+
* never set. Sidebar metadata is best-effort for the same reason
|
|
220
|
+
* `applyCmuxStatusBestEffort` is: a cmux build that dropped `set-status`
|
|
221
|
+
* must never fail workspace creation.
|
|
222
|
+
*/
|
|
223
|
+
async function writeCrewTicketBestEffort(input) {
|
|
224
|
+
if (input.derivedTicket === undefined) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
await writeCmuxStatus(input.workspaceId, { key: TICKET_KEY, priority: TICKET_PRIORITY, value: input.derivedTicket }, input.signal);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
if (!isCmuxSetStatusUnsupported(error)) {
|
|
232
|
+
debug(`cmux crew_ticket write failed for ${input.taskId} (continuing): ${errorMessage(error)}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
175
236
|
async function applyCmuxStatusBestEffort(input) {
|
|
176
237
|
try {
|
|
177
238
|
await applyCmuxStatus(input);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arbitrary-key cmux sidebar status read/write, for the `crew_stage` /
|
|
3
|
+
* `crew_ticket` / `crew_labels` / `crew_poller_heartbeat` fields `pr-stage-sync`
|
|
4
|
+
* owns. Deliberately separate from `cmuxAdapter.ts`'s `Adapter` implementation,
|
|
5
|
+
* whose `set-status` helper is typed to the two keys (`"agent" | "task"`) the
|
|
6
|
+
* workspace-lifecycle contract uses — these keys are a different namespace
|
|
7
|
+
* with their own priorities, so a shared untyped-key helper would weaken both.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Shared by `cmuxAdapter.ts` (writes it once, from the task id, the moment a
|
|
11
|
+
* cmux workspace is created — so a custom sidebar has a ticket to show
|
|
12
|
+
* before any watch-loop tick ever runs) and `prStageSync.ts` (keeps it
|
|
13
|
+
* current on every tick, including when `cmux.prStages.enabled` is false).
|
|
14
|
+
*/
|
|
15
|
+
export declare const TICKET_KEY = "crew_ticket";
|
|
16
|
+
export declare const TICKET_PRIORITY = -11;
|
|
17
|
+
export interface CmuxStatusWrite {
|
|
18
|
+
key: string;
|
|
19
|
+
priority: number;
|
|
20
|
+
/** Empty string clears the key; otherwise it is set verbatim. */
|
|
21
|
+
value: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Parses `cmux list-status`'s `key=value [attr=val ...]` lines into a
|
|
25
|
+
* key -> value map. A value is the token immediately after `=`, up to the
|
|
26
|
+
* next whitespace — matching the retired bash poller's `sed` extraction, so
|
|
27
|
+
* the two stay byte-for-byte comparable during cutover.
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseCmuxStatusLines(output: string): Map<string, string>;
|
|
30
|
+
export declare function readCmuxStatus(workspaceId: string, signal?: AbortSignal): Promise<Map<string, string>>;
|
|
31
|
+
/** Sets `write.key`, or clears it when `write.value` is empty. */
|
|
32
|
+
export declare function writeCmuxStatus(workspaceId: string, write: CmuxStatusWrite, signal?: AbortSignal): Promise<void>;
|
|
33
|
+
//# sourceMappingURL=cmuxStatusFields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cmuxStatusFields.d.ts","sourceRoot":"","sources":["../../src/lib/cmuxStatusFields.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;;GAKG;AACH,eAAO,MAAM,UAAU,gBAAgB,CAAC;AACxC,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAkBxE;AAED,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAO9B;AAED,kEAAkE;AAClE,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,eAAe,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAsBf"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arbitrary-key cmux sidebar status read/write, for the `crew_stage` /
|
|
3
|
+
* `crew_ticket` / `crew_labels` / `crew_poller_heartbeat` fields `pr-stage-sync`
|
|
4
|
+
* owns. Deliberately separate from `cmuxAdapter.ts`'s `Adapter` implementation,
|
|
5
|
+
* whose `set-status` helper is typed to the two keys (`"agent" | "task"`) the
|
|
6
|
+
* workspace-lifecycle contract uses — these keys are a different namespace
|
|
7
|
+
* with their own priorities, so a shared untyped-key helper would weaken both.
|
|
8
|
+
*/
|
|
9
|
+
import { runWorkspaceCommand } from "./workspaceAdapter.js";
|
|
10
|
+
/**
|
|
11
|
+
* Shared by `cmuxAdapter.ts` (writes it once, from the task id, the moment a
|
|
12
|
+
* cmux workspace is created — so a custom sidebar has a ticket to show
|
|
13
|
+
* before any watch-loop tick ever runs) and `prStageSync.ts` (keeps it
|
|
14
|
+
* current on every tick, including when `cmux.prStages.enabled` is false).
|
|
15
|
+
*/
|
|
16
|
+
export const TICKET_KEY = "crew_ticket";
|
|
17
|
+
export const TICKET_PRIORITY = -11;
|
|
18
|
+
/**
|
|
19
|
+
* Parses `cmux list-status`'s `key=value [attr=val ...]` lines into a
|
|
20
|
+
* key -> value map. A value is the token immediately after `=`, up to the
|
|
21
|
+
* next whitespace — matching the retired bash poller's `sed` extraction, so
|
|
22
|
+
* the two stay byte-for-byte comparable during cutover.
|
|
23
|
+
*/
|
|
24
|
+
export function parseCmuxStatusLines(output) {
|
|
25
|
+
const result = new Map();
|
|
26
|
+
for (const rawLine of output.split("\n")) {
|
|
27
|
+
const line = rawLine.trim();
|
|
28
|
+
if (line.length === 0) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const equalsIndex = line.indexOf("=");
|
|
32
|
+
if (equalsIndex <= 0) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const key = line.slice(0, equalsIndex);
|
|
36
|
+
const rest = line.slice(equalsIndex + 1);
|
|
37
|
+
const spaceIndex = rest.indexOf(" ");
|
|
38
|
+
const value = spaceIndex === -1 ? rest : rest.slice(0, spaceIndex);
|
|
39
|
+
result.set(key, value);
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
export async function readCmuxStatus(workspaceId, signal) {
|
|
44
|
+
const output = await runWorkspaceCommand("cmux", ["list-status", "--workspace", workspaceId], signal);
|
|
45
|
+
return parseCmuxStatusLines(output);
|
|
46
|
+
}
|
|
47
|
+
/** Sets `write.key`, or clears it when `write.value` is empty. */
|
|
48
|
+
export async function writeCmuxStatus(workspaceId, write, signal) {
|
|
49
|
+
if (write.value.length === 0) {
|
|
50
|
+
await runWorkspaceCommand("cmux", ["clear-status", write.key, "--workspace", workspaceId], signal);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
await runWorkspaceCommand("cmux", [
|
|
54
|
+
"set-status",
|
|
55
|
+
write.key,
|
|
56
|
+
write.value,
|
|
57
|
+
"--priority",
|
|
58
|
+
String(write.priority),
|
|
59
|
+
"--workspace",
|
|
60
|
+
workspaceId,
|
|
61
|
+
], signal);
|
|
62
|
+
}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -304,6 +304,34 @@ export interface Config {
|
|
|
304
304
|
* to fail loudly when the chosen backend is missing.
|
|
305
305
|
*/
|
|
306
306
|
workspaceKind?: WorkspaceKindSetting;
|
|
307
|
+
/**
|
|
308
|
+
* cmux-only features. Every setting here is inert under the tmux/zellij
|
|
309
|
+
* adapters: `resolveWorkspaceKind` must resolve to `"cmux"` for any of it
|
|
310
|
+
* to run.
|
|
311
|
+
*/
|
|
312
|
+
cmux?: {
|
|
313
|
+
/**
|
|
314
|
+
* Paints each tracked task's cmux sidebar with its pull request's review
|
|
315
|
+
* stage (`crew_stage`), the two gating labels present (`crew_labels`),
|
|
316
|
+
* and the task id (`crew_ticket`), refreshed once per orchestrator tick.
|
|
317
|
+
* Off by default — this replaces a previously standalone poller, so
|
|
318
|
+
* existing setups opt in explicitly rather than getting new sidebar
|
|
319
|
+
* writes on upgrade.
|
|
320
|
+
*/
|
|
321
|
+
prStages?: {
|
|
322
|
+
enabled?: boolean;
|
|
323
|
+
/**
|
|
324
|
+
* PR label names gating the `my_review`/`needs_testing` stages and
|
|
325
|
+
* toggled by `crew stage label-add`/`label-remove`. Defaults to
|
|
326
|
+
* `"self-reviewed"`/`"tested"`; override only if those names collide
|
|
327
|
+
* with existing repo labels.
|
|
328
|
+
*/
|
|
329
|
+
labels?: {
|
|
330
|
+
selfReviewed?: string;
|
|
331
|
+
tested?: string;
|
|
332
|
+
};
|
|
333
|
+
};
|
|
334
|
+
};
|
|
307
335
|
/**
|
|
308
336
|
* Local isolation backend selector. Defaults to `"auto"` (macOS →
|
|
309
337
|
* safehouse, Linux → sdx). `"none"` is an explicit unsandboxed escape
|
|
@@ -414,6 +442,16 @@ export interface ResolvedConfig {
|
|
|
414
442
|
* `auto` resolves to cmux when installed, else tmux.
|
|
415
443
|
*/
|
|
416
444
|
workspaceKind: WorkspaceKindSetting;
|
|
445
|
+
/** cmux-only features; always resolved, inert unless the cmux adapter is active. */
|
|
446
|
+
cmux: {
|
|
447
|
+
prStages: {
|
|
448
|
+
enabled: boolean;
|
|
449
|
+
labels: {
|
|
450
|
+
selfReviewed: string;
|
|
451
|
+
tested: string;
|
|
452
|
+
};
|
|
453
|
+
};
|
|
454
|
+
};
|
|
417
455
|
/**
|
|
418
456
|
* Local isolation selection. The user-facing `auto` is preserved here
|
|
419
457
|
* so `localRunner.resolve()` can pick the platform default later — the
|
|
@@ -461,6 +499,10 @@ export interface LoadedConfig {
|
|
|
461
499
|
config: Readonly<ResolvedConfig>;
|
|
462
500
|
source: Readonly<ConfigSource>;
|
|
463
501
|
}
|
|
502
|
+
export declare const DEFAULT_PR_STAGE_LABELS: {
|
|
503
|
+
readonly selfReviewed: "self-reviewed";
|
|
504
|
+
readonly tested: "tested";
|
|
505
|
+
};
|
|
464
506
|
/**
|
|
465
507
|
* Single source of truth for "is preLaunchEnv asking us to forward anything?"
|
|
466
508
|
*
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.js
CHANGED
|
@@ -72,6 +72,52 @@ function normalizeReadOnlyDirs(value) {
|
|
|
72
72
|
}
|
|
73
73
|
return dirs.map(expandHome);
|
|
74
74
|
}
|
|
75
|
+
export const DEFAULT_PR_STAGE_LABELS = {
|
|
76
|
+
selfReviewed: "self-reviewed",
|
|
77
|
+
tested: "tested",
|
|
78
|
+
};
|
|
79
|
+
const DEFAULT_CMUX = {
|
|
80
|
+
prStages: { enabled: false, labels: { ...DEFAULT_PR_STAGE_LABELS } },
|
|
81
|
+
};
|
|
82
|
+
function normalizePrStageLabels(value) {
|
|
83
|
+
if (value === undefined) {
|
|
84
|
+
return { ...DEFAULT_PR_STAGE_LABELS };
|
|
85
|
+
}
|
|
86
|
+
if (!isPlainObject(value)) {
|
|
87
|
+
fail("cmux.prStages.labels must be an object");
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
selfReviewed: normalizeOptionalString(value["selfReviewed"], "cmux.prStages.labels.selfReviewed") ??
|
|
91
|
+
DEFAULT_PR_STAGE_LABELS.selfReviewed,
|
|
92
|
+
tested: normalizeOptionalString(value["tested"], "cmux.prStages.labels.tested") ??
|
|
93
|
+
DEFAULT_PR_STAGE_LABELS.tested,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function normalizePrStages(value) {
|
|
97
|
+
if (value === undefined) {
|
|
98
|
+
return { ...DEFAULT_CMUX.prStages };
|
|
99
|
+
}
|
|
100
|
+
if (!isPlainObject(value)) {
|
|
101
|
+
fail("cmux.prStages must be an object");
|
|
102
|
+
}
|
|
103
|
+
const { enabled } = value;
|
|
104
|
+
if (enabled !== undefined && typeof enabled !== "boolean") {
|
|
105
|
+
fail(`cmux.prStages.enabled must be a boolean (got ${JSON.stringify(enabled)})`);
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
enabled: enabled ?? false,
|
|
109
|
+
labels: normalizePrStageLabels(value["labels"]),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function normalizeCmux(value) {
|
|
113
|
+
if (value === undefined) {
|
|
114
|
+
return { prStages: { ...DEFAULT_CMUX.prStages } };
|
|
115
|
+
}
|
|
116
|
+
if (!isPlainObject(value)) {
|
|
117
|
+
fail("cmux must be an object");
|
|
118
|
+
}
|
|
119
|
+
return { prStages: normalizePrStages(value["prStages"]) };
|
|
120
|
+
}
|
|
75
121
|
const DEFAULT_ORCHESTRATOR = {
|
|
76
122
|
maximumInProgress: 4,
|
|
77
123
|
pollIntervalMilliseconds: 120_000,
|
|
@@ -803,6 +849,7 @@ function applyDefaults(user, configDir) {
|
|
|
803
849
|
initial: resolveInitialPrompt(user.prompts, configDir),
|
|
804
850
|
},
|
|
805
851
|
workspaceKind: normalizeWorkspaceKind(user.workspaceKind, "workspaceKind") ?? "auto",
|
|
852
|
+
cmux: normalizeCmux(user.cmux),
|
|
806
853
|
local: normalizeLocal(userLocal),
|
|
807
854
|
logging: {
|
|
808
855
|
file: expandHome(normalizeOptionalString(user.logging?.file, "logging.file") ?? defaultLogFile()),
|
|
@@ -819,6 +866,10 @@ function validatePromptPlaceholders(template) {
|
|
|
819
866
|
function validate(config) {
|
|
820
867
|
requireString(config.git.remote, "git.remote");
|
|
821
868
|
requireString(config.git.defaultBranch, "git.defaultBranch");
|
|
869
|
+
const { selfReviewed, tested } = config.cmux.prStages.labels;
|
|
870
|
+
if (selfReviewed === tested) {
|
|
871
|
+
fail(`cmux.prStages.labels.selfReviewed and cmux.prStages.labels.tested must be distinct (both "${selfReviewed}")`);
|
|
872
|
+
}
|
|
822
873
|
requireString(config.workspace.projectDir, "workspace.projectDir");
|
|
823
874
|
config.workspace.repositories.forEach((recipe, index) => {
|
|
824
875
|
const label = `workspace.knownRepositories[${index}]`;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure PR-stage and ticket derivation rules, ported from the standalone
|
|
3
|
+
* `crew-pr-stages.jq` / `crew-ticket.jq` poller this feature replaces. Keeping
|
|
4
|
+
* these as pure functions (no I/O) is what makes the 17 stage fixtures and 8
|
|
5
|
+
* ticket fixtures portable as plain unit tests.
|
|
6
|
+
*/
|
|
7
|
+
export type PullRequestLifecycleState = "OPEN" | "CLOSED" | "MERGED";
|
|
8
|
+
export type PullRequestReviewDecision = "APPROVED" | "CHANGES_REQUESTED" | "REVIEW_REQUIRED" | null;
|
|
9
|
+
export interface PrStageInput {
|
|
10
|
+
state: PullRequestLifecycleState;
|
|
11
|
+
isDraft: boolean;
|
|
12
|
+
labels: readonly string[];
|
|
13
|
+
reviewDecision: PullRequestReviewDecision;
|
|
14
|
+
/** `statusCheckRollup.state`, or `null` when the PR has no checks (treated as passing). */
|
|
15
|
+
checks: string | null;
|
|
16
|
+
}
|
|
17
|
+
declare const PR_STAGES: readonly ["merged", "closed", "ci_failing", "ci_running", "my_review", "needs_testing", "changes_requested", "ready_to_merge", "peer_review"];
|
|
18
|
+
export type PrStage = (typeof PR_STAGES)[number];
|
|
19
|
+
export interface PrStageLabelNames {
|
|
20
|
+
selfReviewed: string;
|
|
21
|
+
tested: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Rule order is significant (first match wins) and mirrors the jq filter's
|
|
25
|
+
* `if/elif` chain exactly: self-review and testing are explicit manual gates
|
|
26
|
+
* (PR labels toggled from the sidebar), not proxies like draft state — a PR
|
|
27
|
+
* sits at `my_review` until self-reviewed is applied (draft or not), and at
|
|
28
|
+
* `needs_testing` until tested is applied, ahead of CI and review-decision.
|
|
29
|
+
*/
|
|
30
|
+
export declare function derivePrStage(input: PrStageInput, labelNames: PrStageLabelNames): PrStage;
|
|
31
|
+
/** The managed-label subset of a PR's labels, sorted and comma-joined — the `crew_labels` sidebar value. */
|
|
32
|
+
export declare function managedLabelsField(labels: readonly string[], labelNames: PrStageLabelNames): string;
|
|
33
|
+
export interface TicketDerivationInput {
|
|
34
|
+
title?: string | null;
|
|
35
|
+
currentDirectory?: string | null;
|
|
36
|
+
}
|
|
37
|
+
/** Directory wins over title, matching the retired sidebar's precedence. */
|
|
38
|
+
export declare function deriveTicket(input: TicketDerivationInput): string | undefined;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=prStageRules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prStageRules.d.ts","sourceRoot":"","sources":["../../src/lib/prStageRules.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAErE,MAAM,MAAM,yBAAyB,GAAG,UAAU,GAAG,mBAAmB,GAAG,iBAAiB,GAAG,IAAI,CAAC;AAEpG,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,yBAAyB,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,cAAc,EAAE,yBAAyB,CAAC;IAC1C,2FAA2F;IAC3F,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,QAAA,MAAM,SAAS,YACb,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,CACL,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAKD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,GAAG,OAAO,CA0BzF;AAED,4GAA4G;AAC5G,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,UAAU,EAAE,iBAAiB,GAC5B,MAAM,CAMR;AAmDD,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAE7E"}
|