toolroll 0.9.59 → 0.9.61
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 +26 -0
- package/README.md +8 -6
- package/dist/agent-board.d.ts +208 -0
- package/dist/agent-board.js +454 -0
- package/dist/agent-fence.d.ts +19 -0
- package/dist/agent-fence.js +100 -8
- package/dist/agent-pulse.d.ts +43 -0
- package/dist/agent-pulse.js +214 -0
- package/dist/agent-turns.d.ts +52 -0
- package/dist/agent-turns.js +137 -0
- package/dist/agents-board.d.ts +101 -0
- package/dist/agents-board.js +225 -0
- package/dist/assignment-adapters.d.ts +2 -1
- package/dist/assignment-adapters.js +1 -1
- package/dist/assignment-delivery.d.ts +16 -0
- package/dist/assignment-delivery.js +54 -28
- package/dist/assignment-status.d.ts +14 -5
- package/dist/assignment-status.js +70 -39
- package/dist/assignment.d.ts +10 -2
- package/dist/assignment.js +21 -14
- package/dist/bin.js +11 -2
- package/dist/brief-fence.d.ts +9 -0
- package/dist/brief-fence.js +22 -0
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +29 -25
- package/dist/browser-crew.js +2 -0
- package/dist/browser-workspace.d.ts +79 -1
- package/dist/browser-workspace.js +1 -0
- package/dist/builder.d.ts +8 -0
- package/dist/builder.js +178 -29
- package/dist/chat-channel.js +10 -1
- package/dist/chat-core.d.ts +6 -0
- package/dist/chat-core.js +8 -0
- package/dist/chat-delivery.js +22 -0
- package/dist/chat-messages.js +8 -1
- package/dist/chat-quiet.js +1 -0
- package/dist/chat-voice.d.ts +2 -0
- package/dist/chat-voice.js +2 -0
- package/dist/checkout-cleanup.d.ts +3 -0
- package/dist/checkout-cleanup.js +11 -2
- package/dist/cli-fast.d.ts +8 -0
- package/dist/cli-fast.js +18 -0
- package/dist/cli-help.d.ts +5 -0
- package/dist/cli-help.js +91 -0
- package/dist/cli.d.ts +6 -5
- package/dist/cli.js +17 -96
- package/dist/contracts/console-api.d.ts +3 -1
- package/dist/contracts/console-api.js +5 -1
- package/dist/contracts/lead-tools.d.ts +16 -2
- package/dist/contracts/lead-tools.js +5 -1
- package/dist/design/tokens.css +234 -0
- package/dist/desktop-update.d.ts +1 -1
- package/dist/discord.js +2 -1
- package/dist/evidence-pack.js +1 -1
- package/dist/evidence.d.ts +28 -0
- package/dist/evidence.js +87 -17
- package/dist/exec.d.ts +32 -0
- package/dist/exec.js +229 -10
- package/dist/flow-actions.js +2 -1
- package/dist/guides.js +14 -11
- package/dist/invoke.js +110 -18
- package/dist/landed-cleanup.d.ts +157 -0
- package/dist/landed-cleanup.js +707 -0
- package/dist/lead-cli.js +22 -19
- package/dist/lead-contract.js +1 -1
- package/dist/lead-doors.js +49 -2
- package/dist/lead-follow.d.ts +2 -0
- package/dist/lead-follow.js +138 -88
- package/dist/lead-tools.js +48 -8
- package/dist/live-input.d.ts +68 -0
- package/dist/live-input.js +254 -0
- package/dist/live.d.ts +1 -1
- package/dist/live.js +4 -2
- package/dist/mailbox.js +3 -2
- package/dist/maintenance.d.ts +2 -0
- package/dist/maintenance.js +5 -2
- package/dist/mcp-core.js +1 -1
- package/dist/operate-remote-arguments.js +5 -1
- package/dist/operate-remote.js +1 -1
- package/dist/operate.d.ts +1 -1
- package/dist/operate.js +201 -19
- package/dist/orphan-sweep.d.ts +2 -0
- package/dist/orphan-sweep.js +5 -3
- package/dist/project-delete-ui.d.ts +11 -0
- package/dist/project-delete-ui.js +29 -2
- package/dist/project-tools.d.ts +7 -11
- package/dist/project-tools.js +13 -37
- package/dist/provider.d.ts +73 -8
- package/dist/provider.js +87 -17
- package/dist/result-completion.d.ts +7 -0
- package/dist/result-completion.js +9 -0
- package/dist/runner.d.ts +4 -2
- package/dist/runner.js +3 -3
- package/dist/serve.js +22 -3
- package/dist/server/chrome.d.ts +6 -3
- package/dist/server/chrome.js +8 -4
- package/dist/server/console.css +9 -64
- package/dist/server/live.d.ts +3 -0
- package/dist/server/live.js +35 -2
- package/dist/server/pages.js +59 -35
- package/dist/server/render-chat.js +14 -2
- package/dist/server/render-tasks.d.ts +14 -2
- package/dist/server/render-tasks.js +38 -20
- package/dist/server/route-table.js +4 -1
- package/dist/server/settings.js +2 -1
- package/dist/server/task-views.js +10 -0
- package/dist/server/tasks.js +63 -0
- package/dist/shared-deps.d.ts +9 -4
- package/dist/shared-deps.js +89 -13
- package/dist/slack-socket.d.ts +12 -0
- package/dist/slack-socket.js +29 -0
- package/dist/slack.d.ts +0 -7
- package/dist/slack.js +2 -24
- package/dist/staged-runtimes.d.ts +16 -4
- package/dist/staged-runtimes.js +160 -38
- package/dist/steer-live.d.ts +19 -0
- package/dist/steer-live.js +93 -0
- package/dist/steer-mailbox.d.ts +39 -0
- package/dist/steer-mailbox.js +207 -0
- package/dist/steer-status.d.ts +25 -0
- package/dist/steer-status.js +44 -0
- package/dist/storage-sweep-child.d.ts +1 -0
- package/dist/storage-sweep-child.js +76 -0
- package/dist/storage-sweep-process.d.ts +41 -0
- package/dist/storage-sweep-process.js +187 -0
- package/dist/storage-sweep.d.ts +30 -6
- package/dist/storage-sweep.js +214 -28
- package/dist/storage-ui.d.ts +2 -0
- package/dist/storage-ui.js +16 -4
- package/dist/storage.d.ts +6 -0
- package/dist/storage.js +35 -0
- package/dist/store.d.ts +202 -2
- package/dist/store.js +440 -13
- package/dist/surface.js +5 -3
- package/dist/sweep-gate.d.ts +10 -0
- package/dist/sweep-gate.js +18 -0
- package/dist/sweep-quarantine.d.ts +28 -0
- package/dist/sweep-quarantine.js +153 -0
- package/dist/task-status.d.ts +2 -0
- package/dist/task-status.js +5 -1
- package/dist/team-updates.js +3 -3
- package/dist/test-temp.d.ts +6 -3
- package/dist/test-temp.js +15 -9
- package/dist/toolroll-update.js +15 -2
- package/dist/work-index.d.ts +1 -0
- package/dist/work-index.js +32 -12
- package/dist/work-summary.d.ts +2 -2
- package/dist/workspace-revision.js +3 -1
- package/dist/worktree.d.ts +3 -1
- package/dist/worktree.js +93 -10
- package/package.json +21 -21
- package/scripts/provider-canary.mjs +235 -147
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Claude build's live input (live steering). The build runs with
|
|
3
|
+
* `--input-format stream-json` and its stdin left open, so Toolroll can talk
|
|
4
|
+
* to the session while it works instead of only through files it reads
|
|
5
|
+
* between steps (checked on Claude Code 2.1.290):
|
|
6
|
+
*
|
|
7
|
+
* - The brief is the FIRST stdin message, a user frame with its own uuid. A
|
|
8
|
+
* `-p` prompt is silently dropped once stdin carries input, so the argv
|
|
9
|
+
* never carries the brief.
|
|
10
|
+
* - A later user frame is taken up as soon as the current tool call ends,
|
|
11
|
+
* inside the turn that is running: it adds no result of its own.
|
|
12
|
+
* - An interrupt control request stops the current turn within milliseconds
|
|
13
|
+
* and keeps the process; the next user frame continues the same session
|
|
14
|
+
* as a new turn. That is Pause; Resume is that next frame with only a
|
|
15
|
+
* short "continue". Stop is still the process-tree kill it always was.
|
|
16
|
+
* - One process emits a result per turn, so the run ends when Toolroll
|
|
17
|
+
* closes stdin, not at the first result: after a turn ends with the
|
|
18
|
+
* handoff written or with nothing more owed, when the turn budget is
|
|
19
|
+
* spent, or when a paused session reaches the idle limit. `--max-turns`
|
|
20
|
+
* applies per user message, so the total is counted here. The idle
|
|
21
|
+
* watchdog stays the transport's own; a paused session only asks it to
|
|
22
|
+
* close stdin first (idleLimit), so the build settles from its handoff.
|
|
23
|
+
* closeReason tells settlement which ending Toolroll chose.
|
|
24
|
+
*
|
|
25
|
+
* Sending is never reading: a note written here still counts as read only
|
|
26
|
+
* when the agent moves its file to handled/ (steer-mailbox.ts). Nothing here
|
|
27
|
+
* touches the store; the builder's dispatcher records what happened.
|
|
28
|
+
*/
|
|
29
|
+
import { randomUUID } from "node:crypto";
|
|
30
|
+
/** What Resume sends a paused session: only a nudge to go on, never a note. */
|
|
31
|
+
export const CONTINUE_TEXT = "continue";
|
|
32
|
+
/** A stdin user frame, in the shape the harness reads. */
|
|
33
|
+
export const userFrame = (text, uuid) => JSON.stringify({ type: "user", message: { role: "user", content: text }, uuid });
|
|
34
|
+
/** A stdin interrupt: stop the current turn, keep the session. */
|
|
35
|
+
export const interruptFrame = (requestId, cancelQueued = false) => JSON.stringify({ type: "control_request", request_id: requestId, request: { subtype: "interrupt", ...(cancelQueued ? { cancel_queued: true } : {}) } });
|
|
36
|
+
/** The session's own words count; a subagent's (parent_tool_use_id set) or a background task's never do. */
|
|
37
|
+
const topLevel = (event) => event["parent_tool_use_id"] === undefined || event["parent_tool_use_id"] === null;
|
|
38
|
+
const primaryResult = (event) => {
|
|
39
|
+
const origin = event["origin"];
|
|
40
|
+
return origin === undefined || origin === null || (typeof origin === "object" && String(origin["kind"] ?? "") === "human");
|
|
41
|
+
};
|
|
42
|
+
export class LiveInput {
|
|
43
|
+
maxTurns;
|
|
44
|
+
#options;
|
|
45
|
+
#io = null;
|
|
46
|
+
#pending = [];
|
|
47
|
+
#begun = false;
|
|
48
|
+
#closed = false;
|
|
49
|
+
#turnActive = false;
|
|
50
|
+
/** A user frame was written while an interrupted turn had not yet ended: that frame's own turn is owed a result. */
|
|
51
|
+
#owed = false;
|
|
52
|
+
#paused = false;
|
|
53
|
+
#interrupts = new Set();
|
|
54
|
+
#turns = new Set();
|
|
55
|
+
#closeReason = null;
|
|
56
|
+
/** The brief's frame uuid, once begun. */
|
|
57
|
+
briefUuid = null;
|
|
58
|
+
constructor(options) {
|
|
59
|
+
this.#options = options;
|
|
60
|
+
this.maxTurns = Math.max(1, Math.floor(options.maxTurns));
|
|
61
|
+
}
|
|
62
|
+
/** Queue the brief as the first frame. Once, before the process is attached. */
|
|
63
|
+
begin(brief, uuid = randomUUID()) {
|
|
64
|
+
if (this.#begun)
|
|
65
|
+
throw new Error("a live session's brief is sent once");
|
|
66
|
+
this.#begun = true;
|
|
67
|
+
this.briefUuid = uuid;
|
|
68
|
+
this.#turnActive = true;
|
|
69
|
+
this.#write(userFrame(brief, uuid));
|
|
70
|
+
}
|
|
71
|
+
/** The transport spawned the child with stdin piped: write what is queued, brief first. */
|
|
72
|
+
attach(io) {
|
|
73
|
+
if (this.#io !== null || this.#closed)
|
|
74
|
+
return;
|
|
75
|
+
this.#io = io;
|
|
76
|
+
const pending = this.#pending;
|
|
77
|
+
this.#pending = [];
|
|
78
|
+
for (const line of pending)
|
|
79
|
+
if (!this.#raw(line))
|
|
80
|
+
return;
|
|
81
|
+
try {
|
|
82
|
+
this.#options.onOpen?.();
|
|
83
|
+
}
|
|
84
|
+
catch { /* display state never touches the session */ }
|
|
85
|
+
}
|
|
86
|
+
/** stdin is attached and still open: a note reaches the agent in seconds, and a Pause can stop its turn. */
|
|
87
|
+
get open() {
|
|
88
|
+
return this.#io !== null && !this.#closed;
|
|
89
|
+
}
|
|
90
|
+
get paused() {
|
|
91
|
+
return this.#paused;
|
|
92
|
+
}
|
|
93
|
+
/** Distinct assistant turns so far, across every message. */
|
|
94
|
+
get turns() {
|
|
95
|
+
return this.#turns.size;
|
|
96
|
+
}
|
|
97
|
+
/** Why stdin closed, once it has. */
|
|
98
|
+
get closeReason() {
|
|
99
|
+
return this.#closeReason;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Send a note (or anything the session should read next). A paused session continues. False once stdin is closed.
|
|
103
|
+
* Mid-turn, the harness folds it into the running turn; after an interrupt that turn is over, so the frame starts a
|
|
104
|
+
* turn of its own whose result is owed before stdin closes.
|
|
105
|
+
*/
|
|
106
|
+
send(text, uuid) {
|
|
107
|
+
if (!this.open)
|
|
108
|
+
return false;
|
|
109
|
+
if (!this.#write(userFrame(text, uuid)))
|
|
110
|
+
return false;
|
|
111
|
+
if (this.#turnActive && this.#interrupts.size > 0)
|
|
112
|
+
this.#owed = true;
|
|
113
|
+
this.#paused = false;
|
|
114
|
+
this.#turnActive = true;
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
/** Resume a paused session with a short continue frame and no note. "not-paused" when nothing waits to go on. */
|
|
118
|
+
resume(uuid) {
|
|
119
|
+
if (!this.open)
|
|
120
|
+
return "closed";
|
|
121
|
+
if (!this.#paused)
|
|
122
|
+
return "not-paused";
|
|
123
|
+
return this.send(CONTINUE_TEXT, uuid) ? "sent" : "closed";
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The transport's idle limit was reached. A paused session closes stdin instead of being killed — the harness exits
|
|
127
|
+
* and the build settles from whatever handoff it saved — and true asks the watchdog to wait once more for that exit.
|
|
128
|
+
* Anything else is an ordinary idle timeout.
|
|
129
|
+
*/
|
|
130
|
+
idleLimit() {
|
|
131
|
+
if (!this.open || !this.#paused)
|
|
132
|
+
return false;
|
|
133
|
+
this.close("paused-idle");
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Pause: stop the current turn, keep the session. "sent" when an interrupt was written; "idle" when no turn was
|
|
138
|
+
* running (the session is already waiting, so it is paused as it stands); "closed" when stdin is gone.
|
|
139
|
+
*/
|
|
140
|
+
interrupt(requestId) {
|
|
141
|
+
if (!this.open)
|
|
142
|
+
return "closed";
|
|
143
|
+
this.#paused = true;
|
|
144
|
+
if (!this.#turnActive)
|
|
145
|
+
return "idle";
|
|
146
|
+
if (!this.#write(interruptFrame(requestId)))
|
|
147
|
+
return "closed";
|
|
148
|
+
this.#interrupts.add(requestId);
|
|
149
|
+
return "sent";
|
|
150
|
+
}
|
|
151
|
+
/** Every parsed stdout event, in order. */
|
|
152
|
+
observe(event) {
|
|
153
|
+
const type = String(event["type"] ?? "");
|
|
154
|
+
if (type === "assistant" && topLevel(event)) {
|
|
155
|
+
this.#turnActive = true;
|
|
156
|
+
const message = event["message"];
|
|
157
|
+
const id = typeof message?.["id"] === "string" ? message["id"] : `turn-${this.#turns.size + 1}`;
|
|
158
|
+
this.#turns.add(id);
|
|
159
|
+
if (this.#turns.size > this.maxTurns && this.open) {
|
|
160
|
+
// The total is spent once a turn past it starts: the last allowed turn ran in full, tools and all. Stop this
|
|
161
|
+
// one, then let the process finish on its own; settlement reads the handoff (closeReason).
|
|
162
|
+
// cancel_queued: a note already queued must not start a turn past the budget after stdin closes.
|
|
163
|
+
this.#write(interruptFrame(`budget-${randomUUID()}`, true));
|
|
164
|
+
this.close("turn-budget");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else if (type === "control_response") {
|
|
168
|
+
const response = event["response"];
|
|
169
|
+
const requestId = typeof response?.["request_id"] === "string" ? response["request_id"] : null;
|
|
170
|
+
if (requestId !== null && this.#interrupts.has(requestId) && response?.["subtype"] === "success" && this.#paused)
|
|
171
|
+
this.#notifyPaused();
|
|
172
|
+
}
|
|
173
|
+
else if (type === "result" && primaryResult(event)) {
|
|
174
|
+
this.#turnActive = false;
|
|
175
|
+
this.#interrupts.clear();
|
|
176
|
+
if (this.#paused) {
|
|
177
|
+
// A paused session waits for the next note; the idle watchdog still bounds the wait.
|
|
178
|
+
this.#notifyPaused();
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// A frame written after this turn was interrupted starts a turn of its own: wait for its result.
|
|
182
|
+
if (this.#owed) {
|
|
183
|
+
this.#owed = false;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
let finished = false;
|
|
187
|
+
try {
|
|
188
|
+
finished = this.#options.finished?.() === true;
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
finished = false;
|
|
192
|
+
}
|
|
193
|
+
this.close(finished ? "finished" : "settled");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/** Close stdin: the harness finishes what it has and exits. Further sends refuse. */
|
|
197
|
+
close(why) {
|
|
198
|
+
if (this.#closed)
|
|
199
|
+
return;
|
|
200
|
+
this.#closed = true;
|
|
201
|
+
this.#closeReason = why;
|
|
202
|
+
this.#paused = false;
|
|
203
|
+
if (this.#io !== null) {
|
|
204
|
+
try {
|
|
205
|
+
this.#io.end();
|
|
206
|
+
}
|
|
207
|
+
catch { /* already gone */ }
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
this.#options.onClose?.(why);
|
|
211
|
+
}
|
|
212
|
+
catch { /* display state never touches the session */ }
|
|
213
|
+
}
|
|
214
|
+
/** The process ended (or its stdin failed): nothing more is written. */
|
|
215
|
+
detach(why = "ended") {
|
|
216
|
+
const closedAlready = this.#closed;
|
|
217
|
+
this.#closed = true;
|
|
218
|
+
if (!closedAlready)
|
|
219
|
+
this.#closeReason = why;
|
|
220
|
+
this.#paused = false;
|
|
221
|
+
this.#io = null;
|
|
222
|
+
if (!closedAlready) {
|
|
223
|
+
try {
|
|
224
|
+
this.#options.onClose?.(why);
|
|
225
|
+
}
|
|
226
|
+
catch { /* display state never touches the session */ }
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
#notifyPaused() {
|
|
230
|
+
try {
|
|
231
|
+
this.#options.onPaused?.();
|
|
232
|
+
}
|
|
233
|
+
catch { /* display state never touches the session */ }
|
|
234
|
+
}
|
|
235
|
+
#write(line) {
|
|
236
|
+
if (this.#closed)
|
|
237
|
+
return false;
|
|
238
|
+
if (this.#io === null) {
|
|
239
|
+
this.#pending.push(line);
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
return this.#raw(line);
|
|
243
|
+
}
|
|
244
|
+
#raw(line) {
|
|
245
|
+
try {
|
|
246
|
+
this.#io.write(`${line}\n`);
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
this.detach("input-failed");
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
package/dist/live.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ export declare function liveActivityKind(event: Record<string, unknown>): LiveAc
|
|
|
46
46
|
* chatter — renders nothing in v1.
|
|
47
47
|
*/
|
|
48
48
|
export declare function renderTranscriptLines(event: Record<string, unknown>): string[];
|
|
49
|
-
/** Sanitize one display line: strip, redact whole on any secret hit, cap. */
|
|
49
|
+
/** Sanitize one display line: strip controls and bidi overrides, redact whole on any secret hit, cap. */
|
|
50
50
|
export declare function sanitizeTranscriptLine(line: string): string;
|
|
51
51
|
export type LiveLog = {
|
|
52
52
|
observe(event: Record<string, unknown>): void;
|
package/dist/live.js
CHANGED
|
@@ -190,9 +190,11 @@ export function renderTranscriptLines(event) {
|
|
|
190
190
|
}
|
|
191
191
|
return lines;
|
|
192
192
|
}
|
|
193
|
-
/**
|
|
193
|
+
/** Bidirectional overrides and isolates (U+202A–U+202E, U+2066–U+2069): they can make shown text read differently from what was written. */
|
|
194
|
+
const BIDI_CONTROLS = /[\u202a-\u202e\u2066-\u2069]/g;
|
|
195
|
+
/** Sanitize one display line: strip controls and bidi overrides, redact whole on any secret hit, cap. */
|
|
194
196
|
export function sanitizeTranscriptLine(line) {
|
|
195
|
-
const stripped = stripControls(line);
|
|
197
|
+
const stripped = stripControls(line).replace(BIDI_CONTROLS, "");
|
|
196
198
|
if (scanForSecrets(stripped).length > 0)
|
|
197
199
|
return LIVE_REDACTED_LINE;
|
|
198
200
|
return capBytes(stripped, LIVE_LINE_CAP);
|
package/dist/mailbox.js
CHANGED
|
@@ -15,8 +15,6 @@
|
|
|
15
15
|
* answering machines. The card keeps the message's ID so a Send email step
|
|
16
16
|
* replying to the sender stays in the same thread.
|
|
17
17
|
*/
|
|
18
|
-
import { ImapFlow } from "imapflow";
|
|
19
|
-
import { simpleParser } from "mailparser";
|
|
20
18
|
import { googleAccessToken, googleConnected } from "./google-mail.js";
|
|
21
19
|
import { readEmailSettings } from "./email-settings.js";
|
|
22
20
|
const BODY_CHARS = 4000;
|
|
@@ -72,6 +70,8 @@ const header = (headers, name) => {
|
|
|
72
70
|
};
|
|
73
71
|
/** One raw message as plain words, and whether a machine sent it. */
|
|
74
72
|
export async function readMail(uid, source) {
|
|
73
|
+
// The mail SDKs load when mail is read, not with every command that imports this module.
|
|
74
|
+
const { simpleParser } = await import("mailparser");
|
|
75
75
|
const parsed = await simpleParser(source, { skipImageLinks: true, skipTextToHtml: true, skipTextLinks: true });
|
|
76
76
|
const sender = parsed.from?.value[0];
|
|
77
77
|
const from = (sender?.address ?? "").toLowerCase();
|
|
@@ -103,6 +103,7 @@ function problemOf(error) {
|
|
|
103
103
|
}
|
|
104
104
|
/** The production reader: one read-only IMAP visit. */
|
|
105
105
|
export const readThroughImap = async (access, folder, after, limit) => {
|
|
106
|
+
const { ImapFlow } = await import("imapflow");
|
|
106
107
|
const client = new ImapFlow({
|
|
107
108
|
host: access.host, port: access.port, secure: access.secure, logger: false, disableAutoIdle: true,
|
|
108
109
|
auth: access.accessToken !== undefined ? { user: access.user, accessToken: access.accessToken } : { user: access.user, pass: access.password ?? "" },
|
package/dist/maintenance.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export declare function startMaintenance(args: {
|
|
|
5
5
|
run: () => Promise<void>;
|
|
6
6
|
shouldStop: () => boolean;
|
|
7
7
|
onError: (error: unknown) => void;
|
|
8
|
+
/** Synchronously cancel owned background work before waiting for the current pass. */
|
|
9
|
+
onStop?: () => void;
|
|
8
10
|
}): {
|
|
9
11
|
runNow: () => Promise<void>;
|
|
10
12
|
stop: () => Promise<void>;
|
package/dist/maintenance.js
CHANGED
package/dist/mcp-core.js
CHANGED
|
@@ -56,7 +56,7 @@ const CONTRACT_GUIDE = [
|
|
|
56
56
|
"recap, list_decisions, get_decision, and queue are the plane's own read queries (shared with the operator's mate). get_decision shows each option's consequence, never the builder's recommendation.",
|
|
57
57
|
"propose_next, propose_reserve, propose_hold, propose_unhold, propose_scope, propose_cancel, and propose_answer write a PROPOSAL row and nothing else: an approver confirms it on the console or the CLI, and a stale one refuses there. Proposals share your hourly filing rate and hold at most 20 pending per credential; they expire after seven days.",
|
|
58
58
|
"Approve, steer, answer, pick, mint, configure, merge: those verbs do not exist on this surface, by construction.",
|
|
59
|
-
"Claim one assignment, then
|
|
59
|
+
"Claim one assignment, then receive its changes with get_assignment_inbox and acknowledge each handled batch with acknowledge_assignment_delivery; inspect get_assignment when a current result or decision needs attention. list_assignment_updates is only the history of handoffs sent to people. claim_assignment records its lead; acknowledge_assignment records that lead's check of an exact ready receipt. Neither operation grants authority, accepts proof, answers decisions, approves work, publishes, or deploys.",
|
|
60
60
|
].join("\n");
|
|
61
61
|
/** An assignment tool: the adapter reads its call with the same schema `toolroll assignment` does. */
|
|
62
62
|
const assignmentHandler = (operation) => (ctx, args) => {
|
|
@@ -29,7 +29,11 @@ export const REMOTE_ARGUMENTS = new Map([
|
|
|
29
29
|
['task block', args('id:task', 'key', { on: 'task' })],
|
|
30
30
|
['task unblock', args('id:task', 'key', { on: 'task' })],
|
|
31
31
|
['task next', args('id:task', 'key undo')],
|
|
32
|
-
|
|
32
|
+
// Live steering: --now pauses the running Claude build first; pause and continue name the exact attempt like stop and
|
|
33
|
+
// resume, and a repeated --request (or --key) id is the same request.
|
|
34
|
+
['task steer', args('id:task', 'note now request key', { run: 'run' })],
|
|
35
|
+
['task pause', args('id:task', 'request key', { run: 'run' })],
|
|
36
|
+
['task continue', args('id:task', 'request key', { run: 'run' })],
|
|
33
37
|
['task assign', args('id:task', 'key runner anyone')],
|
|
34
38
|
['task scope', args('id:task', 'key goal not touches budget-usd risk acceptance candidate model provider repair-model')],
|
|
35
39
|
['task plan', args('id:task', 'key provider model')],
|
package/dist/operate-remote.js
CHANGED
|
@@ -37,7 +37,7 @@ const references = { kind: "references" }, listing = { kind: "listing" };
|
|
|
37
37
|
export const REMOTE_SCOPES = new Map([
|
|
38
38
|
["status", listing], ["integrations", installation], ["ready", listing], ["grants", installation], ["sync", installation],
|
|
39
39
|
["gaps", repo], ["task add", repo],
|
|
40
|
-
...["ask", "checks", "add-tests", "show", "wait", "complete", "revise", "state", "block", "unblock", "next", "steer", "assign", "scope", "plan", "hold",
|
|
40
|
+
...["ask", "checks", "add-tests", "show", "wait", "complete", "revise", "state", "block", "unblock", "next", "steer", "pause", "continue", "assign", "scope", "plan", "hold",
|
|
41
41
|
"unhold", "require", "requeue", "review", "repair", "route", "reopen", "stop", "resume"].map(action => [`task ${action}`, references]),
|
|
42
42
|
["check-progress", references],
|
|
43
43
|
["task list", listing],
|
package/dist/operate.d.ts
CHANGED
|
@@ -102,7 +102,7 @@ type Args = {
|
|
|
102
102
|
* exports are behavior, not commentary — and the declared command guide
|
|
103
103
|
* (surface.ts) is tested for exact equality against them.
|
|
104
104
|
*/
|
|
105
|
-
export declare const TASK_ACTIONS: readonly ["add", "list", "show", "wait", "state", "block", "unblock", "next", "steer", "assign", "reopen", "scope", "approve", "hold", "unhold", "require", "requeue", "regate", "plan", "review", "accept", "repair", "route", "stop", "resume", "complete", "revise", "merge", "ask", "checks", "add-tests"];
|
|
105
|
+
export declare const TASK_ACTIONS: readonly ["add", "list", "show", "wait", "state", "block", "unblock", "next", "steer", "pause", "continue", "assign", "reopen", "scope", "approve", "hold", "unhold", "require", "requeue", "regate", "plan", "review", "accept", "repair", "route", "stop", "resume", "complete", "revise", "merge", "ask", "checks", "add-tests"];
|
|
106
106
|
export declare const PUBLISH_ACTIONS: readonly ["setup", "grant", "revoke", "status", "unblock", "rearm", "merge", "refire"];
|
|
107
107
|
export declare const CONFIG_ACTIONS: readonly ["show", "set", "clear"];
|
|
108
108
|
export declare const APPROVER_ACTIONS: readonly ["list", "add"];
|