@floh-solutions/pharos-cli 0.31.1 → 0.33.0
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 +223 -9
- package/dist/capabilities.d.ts +27 -0
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +144 -41
- package/dist/capabilities.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +79 -16
- package/dist/cli.js.map +1 -1
- package/dist/commands/delegate.d.ts +211 -13
- package/dist/commands/delegate.d.ts.map +1 -1
- package/dist/commands/delegate.js +798 -52
- package/dist/commands/delegate.js.map +1 -1
- package/dist/commands/doctor.d.ts +30 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +382 -39
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/pr.d.ts +56 -0
- package/dist/commands/pr.d.ts.map +1 -0
- package/dist/commands/pr.js +202 -0
- package/dist/commands/pr.js.map +1 -0
- package/dist/commands/setup.js +21 -3
- package/dist/commands/setup.js.map +1 -1
- package/dist/delegate/argus.d.ts +436 -0
- package/dist/delegate/argus.d.ts.map +1 -0
- package/dist/delegate/argus.js +709 -0
- package/dist/delegate/argus.js.map +1 -0
- package/dist/delegate/vsix.d.ts +26 -0
- package/dist/delegate/vsix.d.ts.map +1 -1
- package/dist/delegate/vsix.js +22 -5
- package/dist/delegate/vsix.js.map +1 -1
- package/package.json +3 -3
- package/skill/SKILL.md +44 -10
- package/vscode/pharos-bridge.json +1 -1
- package/vscode/pharos-bridge.vsix +0 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Argus board socket — the route to a coding agent running in Navarch.
|
|
3
|
+
*
|
|
4
|
+
* ## Why there is a fourth route at all
|
|
5
|
+
*
|
|
6
|
+
* Terminal takes an Apple Event and VS Code takes a URI, because in both the
|
|
7
|
+
* thing that owns the terminal is the application. Navarch owns neither: a
|
|
8
|
+
* worker's PTY belongs to `argusd`, a daemon that outlives the app, and the
|
|
9
|
+
* app is what watches a screen settle before typing into it. So the delegation
|
|
10
|
+
* goes over `argusd`'s own socket as one verb — `delegate` — and the two
|
|
11
|
+
* halves split where the knowledge is: the daemon validates and does the find,
|
|
12
|
+
* the app starts a worker if there is none, waits for a screen that can take
|
|
13
|
+
* text, types, and reports back.
|
|
14
|
+
*
|
|
15
|
+
* The contract is `docs/delegation-plan.md` in the argus repo (board #1378).
|
|
16
|
+
* Everything below was measured against an isolated `argusd` built from argus
|
|
17
|
+
* master `2aaefd3` on 2026-09-11; the fixtures in `test/argus.test.ts` are that
|
|
18
|
+
* daemon's replies verbatim.
|
|
19
|
+
*
|
|
20
|
+
* ## Spoken directly, not through `argus-board`
|
|
21
|
+
*
|
|
22
|
+
* `~/.config/argus/bin/argus-board` frames exactly this — one newline-
|
|
23
|
+
* terminated JSON object in, one line back — and shelling out to it would have
|
|
24
|
+
* been half the code. It is wrong here for one measured reason: **that script
|
|
25
|
+
* stamps the CALLER'S identity onto every request**, from the environment.
|
|
26
|
+
* `_agent` from `$ARGUS_AGENT`, `_worker` from `$ARGUS_WORKER`, plus `_sub`,
|
|
27
|
+
* `_persona` and `_mission`. A `pharos delegate` run inside an Argus worker —
|
|
28
|
+
* which is precisely where Pharos.app's Ask Agent runs it — would therefore
|
|
29
|
+
* raise an approval card naming that worker, and file the ledger entry and the
|
|
30
|
+
* outcome note under it. The card is the whole point of the dial: it has to
|
|
31
|
+
* read *Pharos wants to hand work to a claude worker in …*, which is a
|
|
32
|
+
* question a person can answer.
|
|
33
|
+
*
|
|
34
|
+
* Speaking the socket means exactly the keys below travel, and nothing this
|
|
35
|
+
* process happens to have been started with. It also lets a park hold for the
|
|
36
|
+
* daemon's full wait (the script's own deadline is `wait + 5`, tuned for the
|
|
37
|
+
* board's reads) and keeps a transport failure distinguishable from a refusal,
|
|
38
|
+
* which a script that prints one line for both cannot be.
|
|
39
|
+
*
|
|
40
|
+
* ## `ARGUS_BOARD_SOCK` is honoured
|
|
41
|
+
*
|
|
42
|
+
* The same variable `argus-board` reads. It is how an isolated daemon is
|
|
43
|
+
* reached, and a session pointed at one should not have this verb quietly
|
|
44
|
+
* talking to the live fleet instead.
|
|
45
|
+
*/
|
|
46
|
+
/** Where `argusd` binds its board socket, unless the environment says otherwise. */
|
|
47
|
+
export declare function argusSocketPath(env?: NodeJS.ProcessEnv): string;
|
|
48
|
+
/**
|
|
49
|
+
* The kinds `delegate` will type a prompt at, as the wire spells them.
|
|
50
|
+
*
|
|
51
|
+
* A shell is deliberately not one: a delegation is a prompt, and typed at a
|
|
52
|
+
* bare shell it is a command. `claude` and `codex` are the two this CLI's
|
|
53
|
+
* `--agent` offers; `antigravity` exists on the wire and has no `--agent` yet.
|
|
54
|
+
*/
|
|
55
|
+
export type ArgusKind = "claude" | "codex" | "antigravity";
|
|
56
|
+
/** The one-line limit the daemon holds `text` to (`BoardStore.sendTextLimit`). */
|
|
57
|
+
export declare const ARGUS_TEXT_LIMIT = 4000;
|
|
58
|
+
/**
|
|
59
|
+
* How long to ask the daemon to park, in seconds.
|
|
60
|
+
*
|
|
61
|
+
* **60, always, and never the default 10.** Two measured reasons. A delegation
|
|
62
|
+
* onto an empty folder has to start a worker and wait out a cold agent's first
|
|
63
|
+
* screen — `FleetControl.delegateSpawnWindow` is 45s — so a ten-second answer
|
|
64
|
+
* is `pending` with the real outcome landing half a minute later in a reply
|
|
65
|
+
* nobody is reading. And on the default autonomy dial the first hand-off on a
|
|
66
|
+
* machine raises an approval card, which answers `pending` the instant it goes
|
|
67
|
+
* up whatever the wait is; the wait is what catches the person who clicks
|
|
68
|
+
* *Allow* straight away, and ten seconds does not.
|
|
69
|
+
*
|
|
70
|
+
* 60 is also the daemon's ceiling (`maxFleetWait`), so this is "as long as it
|
|
71
|
+
* will hold", not a number picked here.
|
|
72
|
+
*/
|
|
73
|
+
export declare const ARGUS_WAIT_SECONDS = 60;
|
|
74
|
+
/** What the request is stamped with. The card names this; an anonymous one reads "A program outside the fleet". */
|
|
75
|
+
export declare const ARGUS_AGENT = "Pharos";
|
|
76
|
+
/**
|
|
77
|
+
* One reply off the socket, decoded no further than `ok`.
|
|
78
|
+
*
|
|
79
|
+
* `reason` is `null` rather than absent when the key was not there, because
|
|
80
|
+
* **that absence is the single most important fact on this wire** — see
|
|
81
|
+
* {@link mapRefusal}.
|
|
82
|
+
*/
|
|
83
|
+
export interface ArgusSuccess {
|
|
84
|
+
ok: true;
|
|
85
|
+
data: Record<string, unknown>;
|
|
86
|
+
}
|
|
87
|
+
export interface ArgusRefusal {
|
|
88
|
+
ok: false;
|
|
89
|
+
reason: string | null;
|
|
90
|
+
error: string;
|
|
91
|
+
data: Record<string, unknown> | null;
|
|
92
|
+
}
|
|
93
|
+
export type ArgusReply = ArgusSuccess | ArgusRefusal;
|
|
94
|
+
/**
|
|
95
|
+
* Decode one line. Anything that is not a JSON object with a boolean-ish `ok`
|
|
96
|
+
* is a transport fault rather than an answer, and is reported as one.
|
|
97
|
+
*/
|
|
98
|
+
export declare function parseArgusReply(line: string): ArgusReply | null;
|
|
99
|
+
/**
|
|
100
|
+
* The socket was there and the conversation still failed — a park that outlived
|
|
101
|
+
* its own deadline, a daemon that closed mid-answer, a line that is not JSON.
|
|
102
|
+
*
|
|
103
|
+
* Separate from a refusal on purpose: a refusal is a fact about this machine
|
|
104
|
+
* with a fix on it, and this is the CLI's ordinary failure.
|
|
105
|
+
*/
|
|
106
|
+
export declare class ArgusTransportError extends Error {
|
|
107
|
+
readonly code: string;
|
|
108
|
+
constructor(message: string, code: string);
|
|
109
|
+
}
|
|
110
|
+
/** Nothing is listening: the socket file is absent, or the connect was refused. */
|
|
111
|
+
export declare class ArgusUnreachableError extends Error {
|
|
112
|
+
readonly code: string;
|
|
113
|
+
readonly socketPath: string;
|
|
114
|
+
constructor(message: string, code: string, socketPath: string);
|
|
115
|
+
}
|
|
116
|
+
/** The machine-facing half, injectable so every shape below is testable without a daemon. */
|
|
117
|
+
export interface ArgusDeps {
|
|
118
|
+
/** One request, one reply line. Throws {@link ArgusUnreachableError} or {@link ArgusTransportError}. */
|
|
119
|
+
ask: (request: Record<string, unknown>, timeoutMs: number) => Promise<string>;
|
|
120
|
+
}
|
|
121
|
+
export declare function systemArgusDeps(env?: NodeJS.ProcessEnv): ArgusDeps;
|
|
122
|
+
/**
|
|
123
|
+
* The refusal ids this route adds to `delegate`'s closed set.
|
|
124
|
+
*
|
|
125
|
+
* Every one names a DIFFERENT fix, which is the whole reason they are told
|
|
126
|
+
* apart — the app renders a fact and the fix beside it, and two states that
|
|
127
|
+
* share a word send somebody to the wrong Settings pane. `unsupported` and
|
|
128
|
+
* `folder-missing` are not here because the verb already has them and they
|
|
129
|
+
* mean the same thing on this route.
|
|
130
|
+
*/
|
|
131
|
+
export declare const ARGUS_REASONS: readonly ["argusd-not-running", "argusd-outdated", "navarch-not-running", "not-an-operator", "rate-limited", "declined", "delivery-failed", "request-unknown", "gh-account-unknown", "argus-refused"];
|
|
132
|
+
export type ArgusReason = (typeof ARGUS_REASONS)[number];
|
|
133
|
+
/** What a delegation is, at whatever point it has got to. */
|
|
134
|
+
export interface ArgusDelegation {
|
|
135
|
+
/** `pending` is a real answer: a card is up, or the app has not reported yet. */
|
|
136
|
+
action: "sent" | "launched" | "pending";
|
|
137
|
+
/** The id `--status` asks about. */
|
|
138
|
+
request: string;
|
|
139
|
+
/** **Absent until there is one.** `null` means "we have not got a worker yet", never "the empty string". */
|
|
140
|
+
worker: string | null;
|
|
141
|
+
name: string | null;
|
|
142
|
+
created: boolean;
|
|
143
|
+
kind: string;
|
|
144
|
+
directory: string;
|
|
145
|
+
/** The remote host a worker lives on; empty for this Mac. */
|
|
146
|
+
host: string;
|
|
147
|
+
/** The hidden scratch pad the delegation is recorded on. */
|
|
148
|
+
todo: number | null;
|
|
149
|
+
/** Prose for a person. The app renders this. */
|
|
150
|
+
detail: string;
|
|
151
|
+
}
|
|
152
|
+
export interface ArgusFailure {
|
|
153
|
+
/**
|
|
154
|
+
* `session-gone` is here and not in {@link ARGUS_REASONS} because it is
|
|
155
|
+
* `delegate`'s own word, shared with every other host: the daemon's
|
|
156
|
+
* `worker-not-eligible` means to a caller exactly what a vanished pid means
|
|
157
|
+
* on Terminal — *the row you picked is not one this machine will deliver
|
|
158
|
+
* to any more*. One word, one fix (re-read the list and pick again), one
|
|
159
|
+
* branch in the app.
|
|
160
|
+
*/
|
|
161
|
+
reason: ArgusReason | "unsupported" | "folder-missing" | "session-gone";
|
|
162
|
+
detail: string;
|
|
163
|
+
/** What the daemon actually said. Kept so a reason this pharos does not know is still diagnosable. */
|
|
164
|
+
argus: {
|
|
165
|
+
reason: string | null;
|
|
166
|
+
error: string;
|
|
167
|
+
};
|
|
168
|
+
/** The delegation row, on the refusals that carry one — `declined` and `failed` both do. */
|
|
169
|
+
delegation?: ArgusDelegation;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Generic over what it is paired with, because three different reads return
|
|
173
|
+
* "the thing, or the refusal that stopped it": a delegation, a fleet, a list.
|
|
174
|
+
*/
|
|
175
|
+
export declare function isFailure<T extends object>(value: T | ArgusFailure): value is ArgusFailure;
|
|
176
|
+
/**
|
|
177
|
+
* The delegation inside a reply, or the refusal it is instead.
|
|
178
|
+
*
|
|
179
|
+
* One function for all three answers — `delegate`, the end of its park and
|
|
180
|
+
* `delegate_status` — because the daemon builds all three from one builder and
|
|
181
|
+
* a caller that parsed them separately would be inventing a difference.
|
|
182
|
+
*/
|
|
183
|
+
export declare function readDelegation(reply: ArgusReply): ArgusDelegation | ArgusFailure;
|
|
184
|
+
/**
|
|
185
|
+
* A refusal, as an id this CLI's caller already renders.
|
|
186
|
+
*
|
|
187
|
+
* ## The rule that matters: **no `reason` key is an OLD DAEMON**
|
|
188
|
+
*
|
|
189
|
+
* `reason` arrived with `delegate` itself, so an `argusd` too old to serve the
|
|
190
|
+
* verb is also too old to stamp one. That is not a corner — it is the first
|
|
191
|
+
* thing this route meets on any machine whose daemon has not been reloaded,
|
|
192
|
+
* which on the machine this was written on was every machine the day it
|
|
193
|
+
* landed. And an old daemon says three different things, two of which accuse
|
|
194
|
+
* this CLI of a bug it does not have (measured against argus `2fa7bf0`, the
|
|
195
|
+
* commit before the verb):
|
|
196
|
+
*
|
|
197
|
+
* | what is attached | what comes back, with no `reason` |
|
|
198
|
+
* |---|---|
|
|
199
|
+
* | old daemon, old app or none | `unknown op 'delegate' — see argus-board help …` |
|
|
200
|
+
* | old daemon, **new Navarch publishing `delegate`** | `delegate requires a "todo" (id) — the work it serves` |
|
|
201
|
+
* | …the same, unstamped | `'delegate' is an Argus Agent action — this session was not started as one. …` |
|
|
202
|
+
*
|
|
203
|
+
* The middle row is the trap: an old daemon forwards any verb the app claims
|
|
204
|
+
* it can run, and that forwarder demands the `todo` this verb exists to
|
|
205
|
+
* remove. A caller that believed the prose would go and add one. So the test
|
|
206
|
+
* is the MISSING KEY and never the wording — the wording only chooses how
|
|
207
|
+
* sharply the detail can put it. A current daemon stamps a reason on every
|
|
208
|
+
* refusal, and argus asserts that in `Tests/delegate_test.py` precisely so this
|
|
209
|
+
* inference stays true.
|
|
210
|
+
*/
|
|
211
|
+
export declare function mapRefusal(reply: ArgusRefusal): ArgusFailure;
|
|
212
|
+
/**
|
|
213
|
+
* The word that means "start one anyway", beside the uuids `worker` also takes
|
|
214
|
+
* (`BoardStore.delegateFreshWorker`).
|
|
215
|
+
*
|
|
216
|
+
* It is the same spelling as this CLI's own reserved `--session new`, and that
|
|
217
|
+
* is a coincidence worth keeping rather than a shared constant: one is a value
|
|
218
|
+
* a person types at a flag, the other is a value on argus's wire, and the day
|
|
219
|
+
* either side renames its own the other must not silently follow.
|
|
220
|
+
*/
|
|
221
|
+
export declare const ARGUS_NEW_WORKER = "new";
|
|
222
|
+
/** What a delegation asks for. Nothing else reaches the wire. */
|
|
223
|
+
export interface DelegateJob {
|
|
224
|
+
/** Absolute, and already canonicalised — the daemon's compare resolves system symlinks only. */
|
|
225
|
+
directory: string;
|
|
226
|
+
kind: ArgusKind;
|
|
227
|
+
/** ONE line. */
|
|
228
|
+
text: string;
|
|
229
|
+
/** Seconds to park. Defaults to {@link ARGUS_WAIT_SECONDS}. */
|
|
230
|
+
wait?: number;
|
|
231
|
+
/**
|
|
232
|
+
* Who to aim at: a worker uuid out of `delegate_candidates`, or
|
|
233
|
+
* {@link ARGUS_NEW_WORKER} to start a fresh one regardless (#1402).
|
|
234
|
+
*
|
|
235
|
+
* **Omitted, not sent empty, when the caller has no opinion** — that is the
|
|
236
|
+
* find, which is every delegation before #1402 and still the common one.
|
|
237
|
+
*/
|
|
238
|
+
worker?: string;
|
|
239
|
+
/**
|
|
240
|
+
* The GitHub identity a worker this delegation STARTS should run as: a
|
|
241
|
+
* Navarch account label, or a GitHub login (#1402).
|
|
242
|
+
*
|
|
243
|
+
* The daemon resolves it against this core's own `accounts.json`, label then
|
|
244
|
+
* login, and refuses `gh-account-unknown` rather than falling back. It is
|
|
245
|
+
* ignored — out loud, in the reply's detail — when the text lands in a
|
|
246
|
+
* worker that is already running, because a session already on the project
|
|
247
|
+
* is already running as somebody.
|
|
248
|
+
*/
|
|
249
|
+
ghAccount?: string;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* The request, built in one place.
|
|
253
|
+
*
|
|
254
|
+
* `host`, `name`, `stage` and `project` are deliberately never sent. `host`
|
|
255
|
+
* would name a remote machine and this CLI's `--host` means the application, so
|
|
256
|
+
* spelling one here would be a collision waiting to pick the wrong worker;
|
|
257
|
+
* `name` names a NEW worker, which Navarch derives better than a caller can;
|
|
258
|
+
* `project` and `stage` belong to a board this delegation does not have.
|
|
259
|
+
*
|
|
260
|
+
* **`worker` and `gh_account` are omitted when absent rather than sent null.**
|
|
261
|
+
* The daemon reads a JSON null as absent, so either would work — but a daemon
|
|
262
|
+
* that predates #1402 IGNORES both keys silently, and an omitted key keeps the
|
|
263
|
+
* two requests byte-identical to what that daemon has always been sent. The
|
|
264
|
+
* capability check that stops us sending them to a daemon that would ignore
|
|
265
|
+
* them is the caller's; see `delegate.ts`.
|
|
266
|
+
*/
|
|
267
|
+
export declare function delegateRequest(job: DelegateJob): Record<string, unknown>;
|
|
268
|
+
/**
|
|
269
|
+
* `delegate_candidates` — **the find, asked instead of performed** (#1402).
|
|
270
|
+
*
|
|
271
|
+
* A read: ungated, not rate-limited, and answered from the same fleet snapshot
|
|
272
|
+
* `fleet_status` is served from, so it says strictly less than this socket
|
|
273
|
+
* already tells everyone on it. It is stamped like every other request from
|
|
274
|
+
* here all the same, so a refusal cannot be about the stamp.
|
|
275
|
+
*
|
|
276
|
+
* `host` is deliberately not sent. It would name a remote machine, and this
|
|
277
|
+
* CLI's `--host` means the application — the daemon defaults it to empty,
|
|
278
|
+
* which is this Mac, and that is the only fleet this verb can reach.
|
|
279
|
+
*/
|
|
280
|
+
export declare function delegateCandidatesRequest(directory: string, kind: ArgusKind): Record<string, unknown>;
|
|
281
|
+
export declare function delegateStatusRequest(request: string, wait?: number): Record<string, unknown>;
|
|
282
|
+
export declare function fleetStatusRequest(): Record<string, unknown>;
|
|
283
|
+
/**
|
|
284
|
+
* How long to wait on the socket for a park of `wait` seconds.
|
|
285
|
+
*
|
|
286
|
+
* The daemon has to notice its own deadline and write a reply after it, so the
|
|
287
|
+
* read has to outlast the park or every timed-out delegation reads as a broken
|
|
288
|
+
* socket. Ten seconds of margin, the same shape `argus-board` uses (it allows
|
|
289
|
+
* five, for reads that are not parked on a person).
|
|
290
|
+
*/
|
|
291
|
+
export declare function readTimeoutMs(waitSeconds: number): number;
|
|
292
|
+
export declare function askArgus(deps: ArgusDeps, request: Record<string, unknown>, timeoutMs: number): Promise<ArgusReply>;
|
|
293
|
+
/** The refusal for a socket nothing is listening on. */
|
|
294
|
+
export declare function unreachable(error: ArgusUnreachableError): ArgusFailure;
|
|
295
|
+
/**
|
|
296
|
+
* One worker as `fleet_status` reports it (`FleetWorkerStatus.boardRow`).
|
|
297
|
+
*
|
|
298
|
+
* Only the fields the find and a menu row need. `todo` is the mission a worker
|
|
299
|
+
* is holding — see {@link eligible} for why it is a weaker signal here than it
|
|
300
|
+
* is inside the daemon.
|
|
301
|
+
*/
|
|
302
|
+
export interface ArgusWorker {
|
|
303
|
+
id: string;
|
|
304
|
+
name: string;
|
|
305
|
+
kind: string;
|
|
306
|
+
/** `waiting`, `working`, `starting`, `exited`, … — the daemon's own words. */
|
|
307
|
+
status: string;
|
|
308
|
+
/** What it is doing, in its own words. Often empty. */
|
|
309
|
+
stage: string;
|
|
310
|
+
directory: string;
|
|
311
|
+
/** The remote machine it runs on; empty for this Mac. */
|
|
312
|
+
host: string;
|
|
313
|
+
/** The mission todo it is holding, when the board still has that row. */
|
|
314
|
+
todo: number | null;
|
|
315
|
+
/** True for an Argus Agent — an operator, which a delegation must never land in. */
|
|
316
|
+
fleet: boolean;
|
|
317
|
+
}
|
|
318
|
+
export declare function parseFleet(reply: ArgusSuccess): ArgusWorker[];
|
|
319
|
+
/**
|
|
320
|
+
* What `delegate_candidates` answered: the rows this core would accept, in the
|
|
321
|
+
* order its own find ranks them, and the one it would pick.
|
|
322
|
+
*
|
|
323
|
+
* **Already filtered and already ranked**, so nothing here re-applies
|
|
324
|
+
* {@link eligible} or {@link rankWorkers}. That is the entire point of the
|
|
325
|
+
* read: this CLI's own predicate is a PREDICTION of the daemon's, and a good
|
|
326
|
+
* one, but it is weaker in a way that matters — `fleet_status` writes `todo`
|
|
327
|
+
* onto a row only while the board still holds that todo, so a mission whose
|
|
328
|
+
* todo was deleted reads free here and is excluded there. Re-filtering the
|
|
329
|
+
* daemon's own list could only subtract a row the daemon has just said it
|
|
330
|
+
* accepts.
|
|
331
|
+
*
|
|
332
|
+
* `target` is **absent when there is none**, exactly like `worker` on a
|
|
333
|
+
* delegation that has not landed — so it is null here rather than `""`. It is
|
|
334
|
+
* the head of `candidates` by construction (both come from one predicate and
|
|
335
|
+
* one sort), which is why {@link ArgusCandidates.target} is read rather than
|
|
336
|
+
* inferred: it is the daemon's own statement of what a plain delegate takes.
|
|
337
|
+
*/
|
|
338
|
+
export interface ArgusCandidates {
|
|
339
|
+
workers: ArgusWorker[];
|
|
340
|
+
target: string | null;
|
|
341
|
+
}
|
|
342
|
+
export declare function parseCandidates(reply: ArgusSuccess): ArgusCandidates;
|
|
343
|
+
/**
|
|
344
|
+
* Is this worker a candidate for a delegation onto `directory`?
|
|
345
|
+
*
|
|
346
|
+
* `BoardStore.delegateTarget`, rule for rule. Two of the five exclusions are
|
|
347
|
+
* the interesting ones, and both look like perfectly good targets from here:
|
|
348
|
+
*
|
|
349
|
+
* - **a mission worker** runs in a shared base checkout and would match, and
|
|
350
|
+
* typing an unrelated work item into an agent mid-branch derails the todo it
|
|
351
|
+
* is holding;
|
|
352
|
+
* - **an Argus Agent** is a claude worker with no mission sitting in a base
|
|
353
|
+
* checkout — which is exactly the folder a person links in Pharos. A
|
|
354
|
+
* delegation landing there hands the work item to the thing that *drives* the
|
|
355
|
+
* fleet, in the session whose next turn can start missions and type into
|
|
356
|
+
* every other worker.
|
|
357
|
+
*
|
|
358
|
+
* **Mission-hood is weaker here than it is inside the daemon**, and the
|
|
359
|
+
* difference is worth knowing. The daemon tests `missionTodo` on the worker
|
|
360
|
+
* itself; `fleet_status` only writes `todo` onto the row when the board still
|
|
361
|
+
* holds that todo, so a mission whose todo was deleted reads as free here and
|
|
362
|
+
* is excluded there. The direction of the error is the safe one — this can
|
|
363
|
+
* only list or predict a worker the daemon would decline to use, never hide
|
|
364
|
+
* one it would pick — but it is why a prediction is all this is, and why the
|
|
365
|
+
* send itself never names a worker: the daemon does the find that counts.
|
|
366
|
+
*/
|
|
367
|
+
export declare function eligible(worker: ArgusWorker, kind: ArgusKind, directory: string): boolean;
|
|
368
|
+
/**
|
|
369
|
+
* Two spellings of one folder.
|
|
370
|
+
*
|
|
371
|
+
* The daemon compares `standardizingPath` on both sides, which expands `~`,
|
|
372
|
+
* drops `.`/`..` and a trailing slash and resolves the symlinked prefixes
|
|
373
|
+
* macOS ships (`/tmp` → `/private/tmp`) — but NOT an arbitrary symlink
|
|
374
|
+
* somebody made. That is why the caller canonicalises the folder with
|
|
375
|
+
* `realpath` before it gets here, the same way the Terminal route does; this
|
|
376
|
+
* is the rest of the daemon's normalisation, and it is case-insensitive
|
|
377
|
+
* because `caseInsensitiveCompare` is what the daemon uses.
|
|
378
|
+
*/
|
|
379
|
+
export declare function sameFolder(a: string, b: string): boolean;
|
|
380
|
+
/**
|
|
381
|
+
* The candidates for a delegation onto `directory`, in the order the daemon
|
|
382
|
+
* would pick them. `[0]` is the worker a plain delegate takes.
|
|
383
|
+
*
|
|
384
|
+
* **The tie-break is the id and never the status**, because two calls a second
|
|
385
|
+
* apart must pick the same pane. A worker that has not painted yet is worst —
|
|
386
|
+
* there is no box to type into — and everything else is equal, so `starting`
|
|
387
|
+
* sinks and the rest sort on a uuid that never changes.
|
|
388
|
+
*/
|
|
389
|
+
export declare function rankWorkers(workers: readonly ArgusWorker[], kind: ArgusKind, directory: string): ArgusWorker[];
|
|
390
|
+
/**
|
|
391
|
+
* The read that answers "has this argusd been reloaded since `delegate`
|
|
392
|
+
* landed?" without delegating anything.
|
|
393
|
+
*
|
|
394
|
+
* `delegate_status` is a pure read of the daemon's own table — not gated, not
|
|
395
|
+
* rate-limited, and about an id it minted — so asking it about one that cannot
|
|
396
|
+
* exist costs nothing and changes nothing. A current daemon answers
|
|
397
|
+
* `unknown-request`; one that predates the verb answers `unknown op
|
|
398
|
+
* 'delegate_status'` with no `reason` at all, which is the same tell the send
|
|
399
|
+
* path uses.
|
|
400
|
+
*
|
|
401
|
+
* It earns its round trip on `--list` and `--dry-run`, which otherwise read
|
|
402
|
+
* `fleet_status` — a verb every generation of the daemon serves — and would
|
|
403
|
+
* cheerfully list workers that a send is about to refuse to deliver to.
|
|
404
|
+
*/
|
|
405
|
+
export declare const PROBE_REQUEST = "00000000-0000-0000-0000-000000000000";
|
|
406
|
+
/** True when the reply says this daemon knows the delegate family. */
|
|
407
|
+
export declare function servesDelegate(reply: ArgusReply): boolean;
|
|
408
|
+
/**
|
|
409
|
+
* What one `delegate_candidates` reply says about the daemon that sent it.
|
|
410
|
+
*
|
|
411
|
+
* **Three generations of argusd are live at once on a real machine**, and they
|
|
412
|
+
* answer this one read three different ways. Telling them apart is what lets
|
|
413
|
+
* `--list` fall back instead of refusing, and — far more important — what
|
|
414
|
+
* stops `--session` and `--gh-account` being sent to a daemon that would
|
|
415
|
+
* SILENTLY IGNORE them:
|
|
416
|
+
*
|
|
417
|
+
* | daemon | what it answers | {@link candidatesSupport} |
|
|
418
|
+
* |---|---|---|
|
|
419
|
+
* | predates `delegate` (before argus #1378) | a refusal with **no `reason` key at all** | `pre-delegate` |
|
|
420
|
+
* | serves `delegate`, predates #1402 (kit 57) | `reason: "unknown-op"` | `no-op` |
|
|
421
|
+
* | #1402 or later (kit 58) | the list — or `bad-directory`/`bad-kind`, which only an op that EXISTS can say | `yes` |
|
|
422
|
+
*
|
|
423
|
+
* The middle row is the one that costs something. `delegate` reads the keys it
|
|
424
|
+
* knows and ignores the rest, so a kit-57 daemon handed `worker` does its own
|
|
425
|
+
* find and answers `sent` about a worker the person did not choose — the exact
|
|
426
|
+
* substitution `--session` exists to prevent, and nothing in the reply says it
|
|
427
|
+
* happened. Nothing else on the wire reports the gap either, so this read is
|
|
428
|
+
* the only way to know, and it has to be taken BEFORE the send.
|
|
429
|
+
*
|
|
430
|
+
* A refusal that is neither shape counts as `yes` on purpose: only an op the
|
|
431
|
+
* daemon dispatches can refuse for a reason of its own, and the same rule the
|
|
432
|
+
* whole route follows applies — **test the key, never the prose**.
|
|
433
|
+
*/
|
|
434
|
+
export type CandidatesSupport = "yes" | "no-op" | "pre-delegate";
|
|
435
|
+
export declare function candidatesSupport(reply: ArgusReply): CandidatesSupport;
|
|
436
|
+
//# sourceMappingURL=argus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"argus.d.ts","sourceRoot":"","sources":["../../src/delegate/argus.ts"],"names":[],"mappings":"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"}
|