@detergent-software/conductor 1.0.0-dev.1 → 1.0.0-dev.10
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 +87 -0
- package/README.md +175 -9
- package/build/cli.js +368 -21
- package/build/cli.js.map +1 -1
- package/build/clock.js +17 -0
- package/build/clock.js.map +1 -0
- package/build/conditions.js +5 -6
- package/build/conditions.js.map +1 -1
- package/build/config.js +92 -1
- package/build/config.js.map +1 -1
- package/build/credential.js +52 -0
- package/build/credential.js.map +1 -0
- package/build/daemon.js +56 -1
- package/build/daemon.js.map +1 -1
- package/build/events.js +106 -0
- package/build/events.js.map +1 -0
- package/build/inbox.js +385 -0
- package/build/inbox.js.map +1 -0
- package/build/manager.js +26 -3
- package/build/manager.js.map +1 -1
- package/build/mod.js +51 -0
- package/build/mod.js.map +1 -0
- package/build/note.js +71 -0
- package/build/note.js.map +1 -0
- package/build/notes.js +188 -0
- package/build/notes.js.map +1 -0
- package/build/notify.js +393 -0
- package/build/notify.js.map +1 -0
- package/build/paths.js +1 -0
- package/build/paths.js.map +1 -1
- package/build/profile.js +7 -0
- package/build/profile.js.map +1 -1
- package/build/pushover.js +67 -0
- package/build/pushover.js.map +1 -0
- package/build/registry.js +3 -1
- package/build/registry.js.map +1 -1
- package/build/rule-input.js +17 -0
- package/build/rule-input.js.map +1 -0
- package/build/rules-service.js +391 -0
- package/build/rules-service.js.map +1 -0
- package/build/rules.js +842 -0
- package/build/rules.js.map +1 -0
- package/build/server.js +140 -0
- package/build/server.js.map +1 -1
- package/build/spend.js +8 -0
- package/build/spend.js.map +1 -1
- package/build/startup.js +30 -0
- package/build/startup.js.map +1 -1
- package/build/store.js +196 -0
- package/build/store.js.map +1 -1
- package/build/token.js +3 -3
- package/build/token.js.map +1 -1
- package/build/upgrade.js +105 -0
- package/build/upgrade.js.map +1 -0
- package/build/wait.js +32 -32
- package/build/wait.js.map +1 -1
- package/build/watchers/linear-key.js +6 -45
- package/build/watchers/linear-key.js.map +1 -1
- package/build/watchers/linear.js +16 -7
- package/build/watchers/linear.js.map +1 -1
- package/mod/.claude-plugin/marketplace.json +6 -0
- package/mod/.claude-plugin/plugin.json +7 -0
- package/mod/README.md +17 -0
- package/mod/hooks/hooks.json +1 -0
- package/mod/hooks/model.ts +395 -0
- package/mod/hooks/register.tsx +505 -0
- package/mod/types/index.d.ts +57 -0
- package/package.json +6 -1
package/build/events.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { NotRunningError, readEndpoint } from "./client.js";
|
|
2
|
+
import { ConductorError } from "./errors.js";
|
|
3
|
+
// The daemon writes this comment once a stream's replay is out and live events follow.
|
|
4
|
+
const CONNECTED = ': connected';
|
|
5
|
+
const RETRY_MS = [1000, 2000, 5000];
|
|
6
|
+
// `conduct events [--since <id>] [--follow]`: the event log, one JSON event per line. Without
|
|
7
|
+
// --follow it prints the events after --since (all of them without it) and exits. With --follow it
|
|
8
|
+
// starts after --since (live without it), keeps the stream open, and reconnects with Last-Event-ID
|
|
9
|
+
// when the daemon goes away, so a restart loses nothing. --follow also prints the stream's state
|
|
10
|
+
// as lines without an id, `{"kind":"conduct.connected"}` and `{"kind":"conduct.disconnected",
|
|
11
|
+
// "error":…}`, which the conductor mod reads to refetch or clear what it shows.
|
|
12
|
+
export async function eventsCommand(paths, options, io) {
|
|
13
|
+
// Ends early on the signal, so Ctrl+C doesn't wait out a retry while the daemon is down.
|
|
14
|
+
const sleep = io.sleep ??
|
|
15
|
+
((ms) => new Promise((done) => {
|
|
16
|
+
const timer = setTimeout(done, ms);
|
|
17
|
+
io.signal?.addEventListener('abort', () => (clearTimeout(timer), done()), { once: true });
|
|
18
|
+
}));
|
|
19
|
+
let last = options.since ?? null;
|
|
20
|
+
if (!options.follow) {
|
|
21
|
+
await readStream(paths, last ?? 0, { onEvent: (line) => io.out(line), signal: io.signal, untilConnected: true });
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
let failures = 0;
|
|
25
|
+
let connected = false;
|
|
26
|
+
while (!io.signal?.aborted) {
|
|
27
|
+
let error;
|
|
28
|
+
try {
|
|
29
|
+
await readStream(paths, last, {
|
|
30
|
+
onConnected: () => {
|
|
31
|
+
connected = true;
|
|
32
|
+
failures = 0;
|
|
33
|
+
io.out(JSON.stringify({ kind: 'conduct.connected' }));
|
|
34
|
+
},
|
|
35
|
+
onEvent: (line, id) => {
|
|
36
|
+
last = id;
|
|
37
|
+
io.out(line);
|
|
38
|
+
},
|
|
39
|
+
signal: io.signal,
|
|
40
|
+
untilConnected: false,
|
|
41
|
+
});
|
|
42
|
+
error = 'the conductor closed the stream';
|
|
43
|
+
}
|
|
44
|
+
catch (caught) {
|
|
45
|
+
if (io.signal?.aborted)
|
|
46
|
+
break;
|
|
47
|
+
error = caught instanceof Error ? caught.message : String(caught);
|
|
48
|
+
}
|
|
49
|
+
if (io.signal?.aborted)
|
|
50
|
+
break;
|
|
51
|
+
// Said once per outage, not on every retry while the daemon stays down.
|
|
52
|
+
if (connected || failures === 0)
|
|
53
|
+
io.out(JSON.stringify({ error, kind: 'conduct.disconnected' }));
|
|
54
|
+
connected = false;
|
|
55
|
+
await sleep(RETRY_MS[Math.min(failures, RETRY_MS.length - 1)] ?? 5000);
|
|
56
|
+
failures++;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Reads one connection of GET /events: from `since` (Last-Event-ID), or live when it is null.
|
|
60
|
+
async function readStream(paths, since, handlers) {
|
|
61
|
+
const endpoint = readEndpoint(paths);
|
|
62
|
+
if (!endpoint)
|
|
63
|
+
throw new NotRunningError();
|
|
64
|
+
let response;
|
|
65
|
+
try {
|
|
66
|
+
response = await fetch(`http://127.0.0.1:${endpoint.port}/events`, {
|
|
67
|
+
headers: { authorization: `Bearer ${endpoint.token}`, ...(since === null ? {} : { 'last-event-id': String(since) }) },
|
|
68
|
+
signal: handlers.signal,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
throw new ConductorError(`the conductor on port ${endpoint.port} did not answer GET /events`, [String(error)]);
|
|
73
|
+
}
|
|
74
|
+
if (response.status === 404)
|
|
75
|
+
throw new ConductorError('the running conductor has no event stream: it is older than this conduct');
|
|
76
|
+
if (response.status !== 200 || !response.body)
|
|
77
|
+
throw new ConductorError(`GET /events answered ${response.status}`);
|
|
78
|
+
const reader = response.body.getReader();
|
|
79
|
+
const decoder = new TextDecoder();
|
|
80
|
+
let buffer = '';
|
|
81
|
+
try {
|
|
82
|
+
for (;;) {
|
|
83
|
+
const { done, value } = await reader.read();
|
|
84
|
+
if (done)
|
|
85
|
+
return;
|
|
86
|
+
buffer += decoder.decode(value, { stream: true }).replaceAll('\r\n', '\n');
|
|
87
|
+
for (let end = buffer.indexOf('\n\n'); end >= 0; end = buffer.indexOf('\n\n')) {
|
|
88
|
+
const frame = buffer.slice(0, end).split('\n');
|
|
89
|
+
buffer = buffer.slice(end + 2);
|
|
90
|
+
if (frame.includes(CONNECTED)) {
|
|
91
|
+
handlers.onConnected?.();
|
|
92
|
+
if (handlers.untilConnected)
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const id = frame.find((l) => l.startsWith('id: '))?.slice('id: '.length);
|
|
96
|
+
const data = frame.find((l) => l.startsWith('data: '))?.slice('data: '.length);
|
|
97
|
+
if (id !== undefined && data !== undefined)
|
|
98
|
+
handlers.onEvent(data, Number(id));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
await reader.cancel().catch(() => { });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
|
package/build/inbox.js
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { formatCondition, parseCondition } from "./conditions.js";
|
|
3
|
+
import { ConductorError } from "./errors.js";
|
|
4
|
+
import { resolveOpenWait } from "./resolve.js";
|
|
5
|
+
import { formatTokens } from "./spend.js";
|
|
6
|
+
import {} from "./store.js";
|
|
7
|
+
// A Handoff kind (worker protocol v1) to the item it raises. `conductor` and `done` aren't Jason's.
|
|
8
|
+
const NOTE_KINDS = {
|
|
9
|
+
abandoned: 'abandoned',
|
|
10
|
+
blocked: 'blocked',
|
|
11
|
+
failed: 'failed',
|
|
12
|
+
human: 'human',
|
|
13
|
+
jason: 'jason',
|
|
14
|
+
merge: 'merge',
|
|
15
|
+
'npm-otp': 'npm-otp',
|
|
16
|
+
plan: 'plan',
|
|
17
|
+
scope: 'scope',
|
|
18
|
+
};
|
|
19
|
+
// Asks that any later note on the item answers: the worker has moved on.
|
|
20
|
+
const MOVED_ON = new Set(['abandoned', 'blocked', 'failed', 'human', 'jason', 'scope']);
|
|
21
|
+
// The phases that close a gate besides its own condition. A merge waits for the PR, so a Progress
|
|
22
|
+
// note while it waits leaves it open.
|
|
23
|
+
const GATE_PHASES = {
|
|
24
|
+
merge: ['Landed', 'Done'],
|
|
25
|
+
'npm-otp': ['Resumed', 'Landed', 'Done'],
|
|
26
|
+
plan: ['Plan approved'],
|
|
27
|
+
};
|
|
28
|
+
const PUSH_LIMIT = 200;
|
|
29
|
+
// The command on an item about a refused rules file, which also marks it as one.
|
|
30
|
+
const RULES_COMMAND = 'conduct rules';
|
|
31
|
+
// Items about a worker's session, resolved when the session moves.
|
|
32
|
+
const SESSION_KINDS = ['permission', 'stall'];
|
|
33
|
+
const noteData = z.looseObject({
|
|
34
|
+
commands: z.array(z.string()).optional(),
|
|
35
|
+
kind: z.string().nullable().optional(),
|
|
36
|
+
line: z.string().nullable().optional(),
|
|
37
|
+
links: z.array(z.string()).optional(),
|
|
38
|
+
phase: z.string(),
|
|
39
|
+
url: z.string().nullable().optional(),
|
|
40
|
+
worker: z.number().optional(),
|
|
41
|
+
});
|
|
42
|
+
const rulesData = z.looseObject({ file: z.string(), problems: z.array(z.string()).optional() });
|
|
43
|
+
const waitData = z.looseObject({ condition: z.string(), resolution: z.string().optional(), worker: z.number() });
|
|
44
|
+
const workerData = z.looseObject({
|
|
45
|
+
error: z.string().optional(),
|
|
46
|
+
kind: z.string().optional(),
|
|
47
|
+
minutes: z.number().optional(),
|
|
48
|
+
name: z.string(),
|
|
49
|
+
step: z.string().optional(),
|
|
50
|
+
threshold: z.number().optional(),
|
|
51
|
+
tokens: z.number().optional(),
|
|
52
|
+
waitingFor: z.string().optional(),
|
|
53
|
+
worker: z.number(),
|
|
54
|
+
});
|
|
55
|
+
// `conduct inbox`: each open item with its age, text, commands and links.
|
|
56
|
+
export function inboxLines(items, now) {
|
|
57
|
+
return items.flatMap((i) => [
|
|
58
|
+
`#${i.id} ${i.kind} ${[i.item, i.project === null ? null : `(${i.project})`].filter((x) => x !== null).join(' ')} ${age(i.raisedAt, now)}`,
|
|
59
|
+
` ${i.text}`,
|
|
60
|
+
...[...i.commands, ...(i.kind === 'plan' ? [] : [`conduct done ${i.id}`])].map((c) => ` $ ${c}`),
|
|
61
|
+
...i.links.map((l) => ` ${l}`),
|
|
62
|
+
]);
|
|
63
|
+
}
|
|
64
|
+
// The inbox (design note, section 7): everything that waits on Jason, raised from phase notes,
|
|
65
|
+
// waits and session events, each with its exact commands and links. Items resolve themselves when
|
|
66
|
+
// their condition is seen (the approval comment, the PR merged, the version on its tag, a later
|
|
67
|
+
// note), or when Jason answers one (`conduct approve`, `revise`, `done`).
|
|
68
|
+
export function inboxService({ onWaitResolved, store, tracker }) {
|
|
69
|
+
// Items whose approve or revise comment is being posted.
|
|
70
|
+
const answering = new Set();
|
|
71
|
+
const raise = (entry) => store.transaction(() => {
|
|
72
|
+
const item = store.insertInbox(entry);
|
|
73
|
+
store.appendEvent({
|
|
74
|
+
data: { commands: item.commands, condition: item.condition, id: item.id, kind: item.kind, links: item.links, text: item.text, worker: item.worker },
|
|
75
|
+
kind: 'inbox.raised',
|
|
76
|
+
project: item.project,
|
|
77
|
+
subject: item.item,
|
|
78
|
+
});
|
|
79
|
+
// The notifier routes it from this event (notify.ts).
|
|
80
|
+
return item;
|
|
81
|
+
});
|
|
82
|
+
const resolve = (item, by) => store.transaction(() => {
|
|
83
|
+
const resolved = store.resolveInbox(item.id, by);
|
|
84
|
+
if (resolved) {
|
|
85
|
+
store.appendEvent({
|
|
86
|
+
data: { id: resolved.id, kind: resolved.kind, resolvedBy: by, worker: resolved.worker },
|
|
87
|
+
kind: 'inbox.resolved',
|
|
88
|
+
project: resolved.project,
|
|
89
|
+
subject: resolved.item,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return resolved;
|
|
93
|
+
});
|
|
94
|
+
const openOn = (project, item, kinds) => store
|
|
95
|
+
.openInbox()
|
|
96
|
+
.filter((i) => i.project === project && i.item !== null && i.item.toUpperCase() === item?.toUpperCase() && (!kinds || kinds.includes(i.kind)));
|
|
97
|
+
const openOf = (worker, kinds) => store.openInbox().filter((i) => i.worker === worker && kinds.includes(i.kind));
|
|
98
|
+
const resolveAll = (items, by) => {
|
|
99
|
+
for (const item of items)
|
|
100
|
+
resolve(item, by);
|
|
101
|
+
};
|
|
102
|
+
const onNote = (event) => {
|
|
103
|
+
const data = noteData.safeParse(event.data);
|
|
104
|
+
if (!data.success || event.subject === null)
|
|
105
|
+
return;
|
|
106
|
+
const { commands = [], kind: noteKind = null, links = [], phase, url = null, worker = null } = data.data;
|
|
107
|
+
const key = event.subject;
|
|
108
|
+
for (const open of openOn(event.project, key)) {
|
|
109
|
+
if (MOVED_ON.has(open.kind) || GATE_PHASES[open.kind]?.includes(phase))
|
|
110
|
+
resolve(open, `${phase} note`);
|
|
111
|
+
}
|
|
112
|
+
const kind = noteKind === null ? (phase === 'Plan' ? 'plan' : undefined) : NOTE_KINDS[noteKind];
|
|
113
|
+
if (kind === undefined)
|
|
114
|
+
return;
|
|
115
|
+
// A newer note of the same kind replaces the open one, keeping a condition already attached.
|
|
116
|
+
const replaced = openOn(event.project, key, [kind]);
|
|
117
|
+
resolveAll(replaced, `superseded by a newer ${phase} note`);
|
|
118
|
+
const plan = kind === 'plan';
|
|
119
|
+
raise({
|
|
120
|
+
commands: plan ? planCommands(key) : commands,
|
|
121
|
+
condition: replaced.find((r) => r.condition !== null)?.condition ?? null,
|
|
122
|
+
item: key,
|
|
123
|
+
kind,
|
|
124
|
+
links: unique([...(url ? [url] : []), ...(plan ? [] : links)]),
|
|
125
|
+
project: event.project,
|
|
126
|
+
text: plan ? planText(key) : (data.data.line ?? `${phase} · ${noteKind ?? ''}`),
|
|
127
|
+
worker,
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
const onWaitAdded = (event) => {
|
|
131
|
+
const data = waitData.safeParse(event.data);
|
|
132
|
+
if (!data.success)
|
|
133
|
+
return;
|
|
134
|
+
const { condition: text, worker } = data.data;
|
|
135
|
+
// The worker waits on something now, so it isn't idle.
|
|
136
|
+
resolveAll(openOf(worker, ['stall']), `waiting on ${text}`);
|
|
137
|
+
const condition = conditionOf(text);
|
|
138
|
+
if (condition?.kind === 'approval') {
|
|
139
|
+
gate(event.project, condition.item, 'plan', text, worker, () => ({ commands: planCommands(condition.item), links: [], text: planText(condition.item) }));
|
|
140
|
+
}
|
|
141
|
+
else if (condition?.kind === 'npm' && event.subject !== null) {
|
|
142
|
+
gate(event.project, event.subject, 'npm-otp', text, worker, () => ({
|
|
143
|
+
commands: [],
|
|
144
|
+
links: [],
|
|
145
|
+
text: `approve the npm stage of ${condition.package}@${condition.version} (${condition.tag}); the npm stage approve line is on ${event.subject}`,
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
else if (condition?.kind === 'pr' && condition.on === 'merged') {
|
|
149
|
+
// A merge is Jason's only when a note said so; the wait just names its PR.
|
|
150
|
+
for (const open of openOn(event.project, event.subject, ['merge'])) {
|
|
151
|
+
if (open.condition === null)
|
|
152
|
+
store.setInboxCondition(open.id, text);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
// Attaches the wait to the open item of its kind, or raises one when the note went to the
|
|
157
|
+
// tracker without the daemon.
|
|
158
|
+
const gate = (project, item, kind, condition, worker, fresh) => {
|
|
159
|
+
const open = openOn(project, item, [kind]);
|
|
160
|
+
if (open.length === 0) {
|
|
161
|
+
// Jason approved the plan before its worker waited on it: the comment is there, and the
|
|
162
|
+
// watcher resolves this wait on its next pass. A new Plan note raises a new item anyway.
|
|
163
|
+
const latest = store.latestInbox(project, item, kind);
|
|
164
|
+
if (kind === 'plan' && latest?.resolvedBy?.startsWith('approve (conduct approve'))
|
|
165
|
+
return;
|
|
166
|
+
raise({ ...fresh(), condition, item, kind, project, worker });
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
// The newest npm wait is the version that waits: a stage that failed is replaced by the next.
|
|
170
|
+
for (const o of open)
|
|
171
|
+
if (o.condition === null || kind === 'npm-otp')
|
|
172
|
+
store.setInboxCondition(o.id, condition);
|
|
173
|
+
};
|
|
174
|
+
const onResolvedWait = (event) => {
|
|
175
|
+
const data = waitData.safeParse(event.data);
|
|
176
|
+
if (!data.success)
|
|
177
|
+
return;
|
|
178
|
+
const { condition: text, resolution = text } = data.data;
|
|
179
|
+
const condition = conditionOf(text);
|
|
180
|
+
if (condition?.kind === 'approval') {
|
|
181
|
+
resolveAll(openOn(event.project, condition.item, ['plan']), resolution);
|
|
182
|
+
}
|
|
183
|
+
else if (condition?.kind === 'npm') {
|
|
184
|
+
resolveAll(openOn(event.project, event.subject, ['npm-otp']).filter((i) => i.condition === null || i.condition === text), resolution);
|
|
185
|
+
}
|
|
186
|
+
else if (condition?.kind === 'pr' && /\b(merged|abandoned|closed unmerged)\b/.test(resolution)) {
|
|
187
|
+
const pr = prOf(text);
|
|
188
|
+
resolveAll(openOn(event.project, event.subject, ['merge']).filter((i) => i.condition === null || prOf(i.condition) === pr), resolution);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
// A rules file the conductor refused waits on Jason until it loads again; the last good rules
|
|
192
|
+
// stay in force meanwhile. One item per file, found by its link.
|
|
193
|
+
const openRules = (file) => store.openInbox().filter((i) => isRulesItem(i) && i.links[0] === file);
|
|
194
|
+
const onRules = (event) => {
|
|
195
|
+
const data = rulesData.safeParse(event.data);
|
|
196
|
+
if (!data.success)
|
|
197
|
+
return;
|
|
198
|
+
const { file, problems = [] } = data.data;
|
|
199
|
+
if (event.kind === 'rules.loaded') {
|
|
200
|
+
resolveAll(openRules(file), 'the rules loaded');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
resolveAll(openRules(file), 'refused again');
|
|
204
|
+
raise({
|
|
205
|
+
commands: [RULES_COMMAND],
|
|
206
|
+
condition: null,
|
|
207
|
+
item: null,
|
|
208
|
+
kind: 'failed',
|
|
209
|
+
links: [file],
|
|
210
|
+
project: event.project,
|
|
211
|
+
text: `${file} was refused, so its last good rules stay in force: ${problems.slice(1).join('; ') || (problems[0] ?? 'see conduct rules')}`,
|
|
212
|
+
worker: null,
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
const onWorker = (event) => {
|
|
216
|
+
const data = workerData.safeParse(event.data);
|
|
217
|
+
if (!data.success)
|
|
218
|
+
return;
|
|
219
|
+
const { name, worker } = data.data;
|
|
220
|
+
const attach = `conduct attach ${name}`;
|
|
221
|
+
const own = (kind, text, commands) => {
|
|
222
|
+
if (openOf(worker, [kind]).length > 0)
|
|
223
|
+
return;
|
|
224
|
+
raise({ commands, condition: null, item: event.subject, kind, links: [], project: event.project, text, worker });
|
|
225
|
+
};
|
|
226
|
+
// A new launch of the same worker name answers an earlier one that failed, whether it ran or not.
|
|
227
|
+
const earlierFailures = () => openOn(event.project, event.subject, ['failed']).filter((i) => i.worker !== null && i.worker !== worker && store.getWorker(i.worker)?.name === name);
|
|
228
|
+
switch (event.kind) {
|
|
229
|
+
case 'worker.launch-failed':
|
|
230
|
+
resolveAll(earlierFailures(), `${name} failed to launch again`);
|
|
231
|
+
own('failed', `${name} failed to launch at ${data.data.step ?? 'launch'}: ${data.data.error ?? 'see the log'}`, [
|
|
232
|
+
`conduct launch ${event.subject ?? name}${name.startsWith('probe-') ? ' --probe' : ''}`,
|
|
233
|
+
]);
|
|
234
|
+
return;
|
|
235
|
+
case 'worker.launched':
|
|
236
|
+
resolveAll(earlierFailures(), `${name} launched again`);
|
|
237
|
+
return;
|
|
238
|
+
case 'worker.parked':
|
|
239
|
+
resolveAll(openOf(worker, SESSION_KINDS), `${name} parked`);
|
|
240
|
+
return;
|
|
241
|
+
case 'worker.resumed':
|
|
242
|
+
case 'worker.running-again':
|
|
243
|
+
resolveAll(openOf(worker, [...SESSION_KINDS, 'failed']), `${name} running again`);
|
|
244
|
+
return;
|
|
245
|
+
case 'worker.retired': {
|
|
246
|
+
resolveAll(store.openInbox().filter((i) => i.worker === worker), `${name} retired`);
|
|
247
|
+
// A note posted without a worker belongs to the item; the item's live worker is gone now.
|
|
248
|
+
if (!store.getWorker(worker)?.probe) {
|
|
249
|
+
resolveAll(openOn(event.project, event.subject).filter((i) => i.worker === null), `${name} retired`);
|
|
250
|
+
}
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
case 'worker.runaway':
|
|
254
|
+
if (store.inboxOf(worker).some((i) => i.kind === 'runaway'))
|
|
255
|
+
return; // once per worker
|
|
256
|
+
raise({
|
|
257
|
+
commands: [attach, `conduct retire ${name}`],
|
|
258
|
+
condition: null,
|
|
259
|
+
item: event.subject,
|
|
260
|
+
kind: 'runaway',
|
|
261
|
+
links: [],
|
|
262
|
+
project: event.project,
|
|
263
|
+
text: `${name} has used ${formatTokens(data.data.tokens ?? 0)} tokens, past ${formatTokens(data.data.threshold ?? 0)}`,
|
|
264
|
+
worker,
|
|
265
|
+
});
|
|
266
|
+
return;
|
|
267
|
+
case 'worker.stall-cleared':
|
|
268
|
+
resolveAll(openOf(worker, [data.data.kind === 'permission' ? 'permission' : 'stall']), `${name} moved on`);
|
|
269
|
+
return;
|
|
270
|
+
case 'worker.stalled':
|
|
271
|
+
if (data.data.kind === 'permission') {
|
|
272
|
+
own('permission', `${name} has waited ${data.data.minutes ?? '?'} min on a permission prompt (${data.data.waitingFor ?? 'input'})`, [attach]);
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
own('stall', `${name} has been idle ${data.data.minutes ?? '?'} min with no wait`, [attach]);
|
|
276
|
+
}
|
|
277
|
+
return;
|
|
278
|
+
case 'worker.stopped-unexpectedly':
|
|
279
|
+
resolveAll(openOf(worker, SESSION_KINDS), `${name} stopped`);
|
|
280
|
+
own('failed', `${name}'s session stopped unexpectedly`, [attach, `conduct retire ${name}`]);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
return {
|
|
285
|
+
answer: async (id, answer) => {
|
|
286
|
+
const item = store.getInbox(id);
|
|
287
|
+
if (!item)
|
|
288
|
+
throw new ConductorError(`no inbox item ${id}`);
|
|
289
|
+
if (item.resolvedAt !== null)
|
|
290
|
+
throw new ConductorError(`inbox item ${id} is resolved already (${item.resolvedBy ?? '?'})`);
|
|
291
|
+
if (answer.action === 'done') {
|
|
292
|
+
return { comment: null, item: resolve(item, 'done (conduct done)') ?? item, waits: [] };
|
|
293
|
+
}
|
|
294
|
+
if (item.kind !== 'plan' || item.item === null) {
|
|
295
|
+
throw new ConductorError(`inbox item ${id} is a ${item.kind}, not a plan: only a plan takes approve or revise`, [
|
|
296
|
+
`\`conduct done ${id}\` resolves it`,
|
|
297
|
+
]);
|
|
298
|
+
}
|
|
299
|
+
// One answer at a time: a second approve (or a revise) while the first posts would post twice.
|
|
300
|
+
if (answering.has(id))
|
|
301
|
+
throw new ConductorError(`inbox item ${id} is being answered; try again shortly`);
|
|
302
|
+
const key = item.item;
|
|
303
|
+
const body = answer.action === 'revise' ? `revise: ${answer.text}` : answer.text ? `approve: ${answer.text}` : 'approve';
|
|
304
|
+
answering.add(id);
|
|
305
|
+
let comment;
|
|
306
|
+
try {
|
|
307
|
+
// As Jason: the comment carries the key owner's name, and the worker reads it on the tracker.
|
|
308
|
+
comment = await tracker.comment(key, body);
|
|
309
|
+
}
|
|
310
|
+
finally {
|
|
311
|
+
answering.delete(id);
|
|
312
|
+
}
|
|
313
|
+
const resolved = resolve(item, `${answer.action} (conduct ${answer.action}, comment ${comment.id})`) ?? store.getInbox(id) ?? item;
|
|
314
|
+
// The comment is the fact; resolving the wait now saves the watcher's next pass.
|
|
315
|
+
const condition = formatCondition({ item: key, kind: 'approval', tracker: 'linear' });
|
|
316
|
+
const resolution = `approval ${key}: ${answer.action}`;
|
|
317
|
+
const waits = store
|
|
318
|
+
.openWaits()
|
|
319
|
+
.filter((w) => w.condition === condition)
|
|
320
|
+
.flatMap((w) => resolveOpenWait(store, w, resolution) ?? []);
|
|
321
|
+
if (waits.length > 0)
|
|
322
|
+
onWaitResolved?.();
|
|
323
|
+
return { comment, item: resolved, waits };
|
|
324
|
+
},
|
|
325
|
+
observe: (event) => {
|
|
326
|
+
if (event.kind === 'note.posted')
|
|
327
|
+
onNote(event);
|
|
328
|
+
else if (event.kind === 'wait.added')
|
|
329
|
+
onWaitAdded(event);
|
|
330
|
+
else if (event.kind === 'wait.resolved')
|
|
331
|
+
onResolvedWait(event);
|
|
332
|
+
else if (event.kind.startsWith('worker.'))
|
|
333
|
+
onWorker(event);
|
|
334
|
+
else if (event.kind === 'rules.loaded' || event.kind === 'rules.rejected')
|
|
335
|
+
onRules(event);
|
|
336
|
+
},
|
|
337
|
+
open: () => store.openInbox(),
|
|
338
|
+
raise,
|
|
339
|
+
// Session clocks were in memory, and the rules were read again at start (a file still refused
|
|
340
|
+
// raises its item again), so the items of both start over.
|
|
341
|
+
start: () => resolveAll(store.openInbox().filter((i) => SESSION_KINDS.includes(i.kind) || isRulesItem(i)), 'the daemon restarted; raised again if it persists'),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
// A push's body: the item, then the ask, within PushNotification's 200 characters.
|
|
345
|
+
export function pushMessage(item) {
|
|
346
|
+
const message = item.item === null || item.text.includes(item.item) ? item.text : `${item.item} · ${item.text}`;
|
|
347
|
+
return message.length <= PUSH_LIMIT ? message : `${message.slice(0, PUSH_LIMIT - 1)}…`;
|
|
348
|
+
}
|
|
349
|
+
// "just now", "12 min ago", "3 h 5 min ago", "2 d ago".
|
|
350
|
+
function age(iso, now) {
|
|
351
|
+
const minutes = Math.floor((now.getTime() - Date.parse(iso)) / 60_000);
|
|
352
|
+
if (minutes < 1)
|
|
353
|
+
return 'just now';
|
|
354
|
+
if (minutes < 60)
|
|
355
|
+
return `${minutes} min ago`;
|
|
356
|
+
if (minutes < 24 * 60)
|
|
357
|
+
return `${Math.floor(minutes / 60)} h ${minutes % 60} min ago`;
|
|
358
|
+
return `${Math.floor(minutes / (24 * 60))} d ago`;
|
|
359
|
+
}
|
|
360
|
+
function conditionOf(text) {
|
|
361
|
+
try {
|
|
362
|
+
return parseCondition(text);
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// An item about a refused rules file (onRules raises them).
|
|
369
|
+
function isRulesItem(item) {
|
|
370
|
+
return item.kind === 'failed' && item.item === null && item.commands[0] === RULES_COMMAND;
|
|
371
|
+
}
|
|
372
|
+
function planCommands(item) {
|
|
373
|
+
return [`conduct approve ${item}`, `conduct revise ${item} "<what to change>"`];
|
|
374
|
+
}
|
|
375
|
+
function planText(item) {
|
|
376
|
+
return `${item}'s plan waits on your approval`;
|
|
377
|
+
}
|
|
378
|
+
// A PR condition without its event: `pr:ado:<repo>#1850`.
|
|
379
|
+
function prOf(condition) {
|
|
380
|
+
return condition.replace(/:[a-z]+$/, '');
|
|
381
|
+
}
|
|
382
|
+
function unique(values) {
|
|
383
|
+
return [...new Set(values)];
|
|
384
|
+
}
|
|
385
|
+
//# sourceMappingURL=inbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../src/inbox.ts"],"names":[],"mappings":"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"}
|
package/build/manager.js
CHANGED
|
@@ -44,6 +44,8 @@ export function sessionManager(deps) {
|
|
|
44
44
|
const stalls = new Map();
|
|
45
45
|
const transcripts = new Map();
|
|
46
46
|
const transcriptScans = new Map();
|
|
47
|
+
// Workers this run has logged `worker.runaway` for.
|
|
48
|
+
const runaways = new Set();
|
|
47
49
|
let sessions = [];
|
|
48
50
|
// Until the first sweep, nothing is known about any session.
|
|
49
51
|
let listed = false;
|
|
@@ -221,12 +223,21 @@ export function sessionManager(deps) {
|
|
|
221
223
|
};
|
|
222
224
|
const checkStalls = (worker, session, waiting) => {
|
|
223
225
|
const state = stalls.get(worker.id) ?? {};
|
|
226
|
+
// A stall that was reported says when it ends, so its inbox item resolves.
|
|
227
|
+
const cleared = (kind, reported) => {
|
|
228
|
+
if (reported)
|
|
229
|
+
event(worker, 'worker.stall-cleared', { kind });
|
|
230
|
+
};
|
|
224
231
|
const prompt = permissionPrompt(session);
|
|
225
|
-
if (prompt === null)
|
|
232
|
+
if (prompt === null) {
|
|
233
|
+
cleared('permission', state.permission?.reported);
|
|
226
234
|
state.permission = undefined;
|
|
235
|
+
}
|
|
227
236
|
else {
|
|
228
|
-
if (state.permission?.waitingFor !== prompt)
|
|
237
|
+
if (state.permission?.waitingFor !== prompt) {
|
|
238
|
+
cleared('permission', state.permission?.reported);
|
|
229
239
|
state.permission = { reported: false, since: now().toISOString(), waitingFor: prompt };
|
|
240
|
+
}
|
|
230
241
|
const minutes = minutesSince(state.permission.since);
|
|
231
242
|
if (!state.permission.reported && minutes >= config.permissionMinutes) {
|
|
232
243
|
state.permission.reported = true;
|
|
@@ -234,8 +245,10 @@ export function sessionManager(deps) {
|
|
|
234
245
|
}
|
|
235
246
|
}
|
|
236
247
|
// An attached worker is Jason's while he has it open.
|
|
237
|
-
if (!turnEnded(session) || waiting || worker.attachedAt !== null)
|
|
248
|
+
if (!turnEnded(session) || waiting || worker.attachedAt !== null) {
|
|
249
|
+
cleared('idle', state.idle?.reported);
|
|
238
250
|
state.idle = undefined;
|
|
251
|
+
}
|
|
239
252
|
else {
|
|
240
253
|
state.idle ??= { reported: false, since: now().toISOString() };
|
|
241
254
|
const minutes = minutesSince(state.idle.since);
|
|
@@ -335,6 +348,16 @@ export function sessionManager(deps) {
|
|
|
335
348
|
store.saveTranscript(file, worker.id, cursor);
|
|
336
349
|
});
|
|
337
350
|
}
|
|
351
|
+
// Once per worker in each run of the daemon: the inbox raises one item per worker ever, so a
|
|
352
|
+
// restart (or an event it never saw) costs one more event, not a missing item.
|
|
353
|
+
const { runawayTokens } = deps;
|
|
354
|
+
if (runawayTokens === undefined || runaways.has(worker.id))
|
|
355
|
+
return;
|
|
356
|
+
const tokens = store.workerSpend(worker.id);
|
|
357
|
+
if (tokens < runawayTokens)
|
|
358
|
+
return;
|
|
359
|
+
runaways.add(worker.id);
|
|
360
|
+
event(worker, 'worker.runaway', { threshold: runawayTokens, tokens });
|
|
338
361
|
};
|
|
339
362
|
// Never rejects: it runs on a timer, and an unhandled rejection would end the daemon.
|
|
340
363
|
const sweepOnce = async () => {
|