@detergent-software/conductor 3.2.0 → 3.3.0-dev.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/CHANGELOG.md +17 -0
- package/README.md +3 -2
- package/build/cli.js +3 -0
- package/build/cli.js.map +1 -1
- package/build/conditions.js +80 -5
- package/build/conditions.js.map +1 -1
- package/build/help.js +12 -1
- package/build/help.js.map +1 -1
- package/build/lib/providers/ado/code-host.js +27 -0
- package/build/lib/providers/ado/code-host.js.map +1 -1
- package/build/lib/providers/github/code-host.js +27 -0
- package/build/lib/providers/github/code-host.js.map +1 -1
- package/build/links.js +23 -0
- package/build/links.js.map +1 -1
- package/build/manager.js +7 -0
- package/build/manager.js.map +1 -1
- package/build/protocol.js +2 -0
- package/build/protocol.js.map +1 -1
- package/build/rules.js +11 -1
- package/build/rules.js.map +1 -1
- package/build/store.js +15 -4
- package/build/store.js.map +1 -1
- package/build/watchers/ado.js +10 -5
- package/build/watchers/ado.js.map +1 -1
- package/build/watchers/conflicts.js +3 -7
- package/build/watchers/conflicts.js.map +1 -1
- package/build/watchers/github.js +7 -3
- package/build/watchers/github.js.map +1 -1
- package/build/watchers/source.js +22 -1
- package/build/watchers/source.js.map +1 -1
- package/package.json +12 -12
- package/plugin/hooks/model.ts +7 -1
- package/plugin/hooks/register.tsx +11 -8
- package/plugin/types/index.d.ts +2 -0
- package/protocol/PROTOCOL.md +2 -1
package/plugin/hooks/model.ts
CHANGED
|
@@ -254,6 +254,11 @@ export function waitLabel(condition: string, now: number): string {
|
|
|
254
254
|
if (host) return `PR #${number} ${PR_EVENTS[on] ?? on}${host === 'github' ? ` (${last(repo)})` : ''}`;
|
|
255
255
|
break;
|
|
256
256
|
}
|
|
257
|
+
case 'pr-opened': {
|
|
258
|
+
const [repo = ''] = read(/^(?:ado|github):([^:]+)/) ?? [];
|
|
259
|
+
if (repo) return `a new PR (${last(repo)})`;
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
257
262
|
case 'run': {
|
|
258
263
|
const [pipeline = '', id = ''] = read(/^(?:ado|github):(.+)#(\d+):done$/) ?? [];
|
|
259
264
|
if (pipeline) return `run #${id} to finish (${last(pipeline).replace(/\.ya?ml$/, '')})`;
|
|
@@ -427,6 +432,7 @@ export function parseFleet(body: unknown): ConductorWorker[] | null {
|
|
|
427
432
|
activity: typeof w.activity === 'string' ? w.activity : w.status,
|
|
428
433
|
id: w.id,
|
|
429
434
|
item: typeof w.item === 'string' ? w.item : w.name,
|
|
435
|
+
links: links(w.links),
|
|
430
436
|
name: w.name,
|
|
431
437
|
phase: typeof w.phase === 'string' ? w.phase : null,
|
|
432
438
|
pr: typeof w.pr === 'string' ? w.pr : null,
|
|
@@ -902,7 +908,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
902
908
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
903
909
|
}
|
|
904
910
|
|
|
905
|
-
// An inbox item's named links; one without an href or a label is left out.
|
|
911
|
+
// An inbox item's or a worker's named links; one without an href or a label is left out.
|
|
906
912
|
function links(value: unknown): ConductorLink[] {
|
|
907
913
|
if (!Array.isArray(value)) return [];
|
|
908
914
|
return value.flatMap((l: unknown) =>
|
|
@@ -2,7 +2,7 @@ import type { EngineInterface, Register, RenderElement, Timer } from 'claude-cod
|
|
|
2
2
|
|
|
3
3
|
import { atom, read, update } from 'claude-code';
|
|
4
4
|
|
|
5
|
-
import type { ConductorSnapshot } from '../types';
|
|
5
|
+
import type { ConductorLink, ConductorSnapshot } from '../types';
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
age,
|
|
@@ -877,6 +877,14 @@ export const register: Register = (on) => {
|
|
|
877
877
|
const now = await $.clock.now();
|
|
878
878
|
const rule = (title: string): string =>
|
|
879
879
|
`─ ${title} ${'─'.repeat(Math.max(0, e.props.bodyColumns - title.length - 3))}`;
|
|
880
|
+
// An inbox item's or a worker's [open <label>]: on the Windows terminal a Button that runs the
|
|
881
|
+
// browser once, else a Link (ATK-494).
|
|
882
|
+
const openButton = (key: string, { href, label }: ConductorLink): RenderElement =>
|
|
883
|
+
e.surface === 'terminal' && isWindows && isWebLink(href) ? (
|
|
884
|
+
<Button key={key} label={`open ${label}`} onPress={() => openLink($, href)} />
|
|
885
|
+
) : (
|
|
886
|
+
<Link href={href} key={key} label={`open ${label}`} />
|
|
887
|
+
);
|
|
880
888
|
if (snap === null) return <Text dimColor>Reading the conductor…</Text>;
|
|
881
889
|
if (snap.error !== null) {
|
|
882
890
|
return (
|
|
@@ -977,13 +985,7 @@ export const register: Register = (on) => {
|
|
|
977
985
|
onPress={(press) => copy($, command, press.surface)}
|
|
978
986
|
/>
|
|
979
987
|
))}
|
|
980
|
-
{item.links.map((
|
|
981
|
-
e.surface === 'terminal' && isWindows && isWebLink(href) ? (
|
|
982
|
-
<Button key={`link-${item.id}-${n}`} label={`open ${label}`} onPress={() => openLink($, href)} />
|
|
983
|
-
) : (
|
|
984
|
-
<Link href={href} key={`link-${item.id}-${n}`} label={`open ${label}`} />
|
|
985
|
-
),
|
|
986
|
-
)}
|
|
988
|
+
{item.links.map((l, n) => openButton(`link-${item.id}-${n}`, l))}
|
|
987
989
|
{item.kind !== 'plan' && (
|
|
988
990
|
<Button
|
|
989
991
|
key={`done-${item.id}`}
|
|
@@ -1038,6 +1040,7 @@ export const register: Register = (on) => {
|
|
|
1038
1040
|
onPress={async () => $.ui.toast(await attach($, w.id, w.name))}
|
|
1039
1041
|
/>
|
|
1040
1042
|
<Button key={`why-${w.id}`} label='why' onPress={async () => $.ui.toast(await why($, w.item))} />
|
|
1043
|
+
{w.links.map((l, n) => openButton(`link-worker-${w.id}-${n}`, l))}
|
|
1041
1044
|
<Text dimColor>
|
|
1042
1045
|
{w.status} · {tokens(w.spendToday)} tok today
|
|
1043
1046
|
{w.pr === null ? '' : ` · PR ${w.pr}`}
|
package/plugin/types/index.d.ts
CHANGED
|
@@ -43,6 +43,8 @@ export type ConductorWorker = {
|
|
|
43
43
|
activity: string;
|
|
44
44
|
id: number;
|
|
45
45
|
item: string;
|
|
46
|
+
// Its PR's page and its item's, named by the daemon (ATK-742).
|
|
47
|
+
links: ConductorLink[];
|
|
46
48
|
name: string;
|
|
47
49
|
phase: null | string;
|
|
48
50
|
// Its PR as the daemon spells it, such as `ado:Contoso.Web#1850`; null before it has one.
|
package/protocol/PROTOCOL.md
CHANGED
|
@@ -85,11 +85,12 @@ An answer by anyone else is ignored, and the plan's inbox item says whose it was
|
|
|
85
85
|
|
|
86
86
|
## Waits
|
|
87
87
|
|
|
88
|
-
`conduct wait <verb …>` registers a wait for the worker whose worktree it runs in. The daemon parks the worker once its turn ends, and resumes it when the wait holds. With no daemon, it checks the wait here and blocks: exit 0 when the wait holds, exit 2 after 29 minutes, exit 1 when it can't check. Each verb has a full form, which the store keeps. `item <item> comment` holds on the first comment by an approver (as Approvals defines them) after the item's newest note of any phase, and no more than 10 minutes before the wait registered. A note never counts, and a comment by anyone else is ignored and named on the Handoff's inbox item (`comment.ignored`). `item <item> unlabelled <label>` holds once the daemon has seen the label on since the wait registered and then sees it off, so a label added after the note doesn't resolve it at once. A verb or full form that doesn't parse is refused with exit 1, and the error names the form it expects.
|
|
88
|
+
`conduct wait <verb …>` registers a wait for the worker whose worktree it runs in. The daemon parks the worker once its turn ends, and resumes it when the wait holds. With no daemon, it checks the wait here and blocks: exit 0 when the wait holds, exit 2 after 29 minutes, exit 1 when it can't check. Each verb has a full form, which the store keeps. `item <item> comment` holds on the first comment by an approver (as Approvals defines them) after the item's newest note of any phase, and no more than 10 minutes before the wait registered. A note never counts, and a comment by anyone else is ignored and named on the Handoff's inbox item (`comment.ignored`). `item <item> unlabelled <label>` holds once the daemon has seen the label on since the wait registered and then sees it off, so a label added after the note doesn't resolve it at once. `pr opened` holds on a PR created in the repo after the wait registered, in any state, that its filters let through; the author lists are kept lowercase and sorted, so the same filters are the same wait. A verb or full form that doesn't parse is refused with exit 1, and the error names the form it expects.
|
|
89
89
|
|
|
90
90
|
| Verb | Full form |
|
|
91
91
|
|---|---|
|
|
92
92
|
| `pr <n> [merged\|checks\|comment …] [--repo …]` | `pr:<ado\|github>:<repo>#<n>:<verdict\|merged\|checks\|comment>` |
|
|
93
|
+
| `pr opened [--author a,b \| --not-author a,b] [--base b] [--repo …]` | `pr-opened:<ado\|github>:<repo>[:base=<b>][:author=a,b \| :not-author=a,b]` |
|
|
93
94
|
| `merge <sha> [--for a,b] [--repo …]` | `merge:<ado\|github>:<repo>@<sha>[:for=a,b]` |
|
|
94
95
|
| `run <pipeline> <id> [done]` | `run:ado:<pipeline>#<id>:done` |
|
|
95
96
|
| `npm <version> [--tag t] [--package p]` | `npm:<package>@<version>:<tag>` |
|