@detergent-software/conductor 1.0.0-dev.1 → 1.0.0-dev.11

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.
Files changed (80) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +210 -9
  3. package/build/cli.js +456 -21
  4. package/build/cli.js.map +1 -1
  5. package/build/clock.js +17 -0
  6. package/build/clock.js.map +1 -0
  7. package/build/conditions.js +5 -6
  8. package/build/conditions.js.map +1 -1
  9. package/build/config.js +92 -1
  10. package/build/config.js.map +1 -1
  11. package/build/credential.js +52 -0
  12. package/build/credential.js.map +1 -0
  13. package/build/daemon.js +96 -2
  14. package/build/daemon.js.map +1 -1
  15. package/build/events.js +106 -0
  16. package/build/events.js.map +1 -0
  17. package/build/inbox.js +385 -0
  18. package/build/inbox.js.map +1 -0
  19. package/build/manager.js +56 -12
  20. package/build/manager.js.map +1 -1
  21. package/build/mod.js +51 -0
  22. package/build/mod.js.map +1 -0
  23. package/build/note.js +71 -0
  24. package/build/note.js.map +1 -0
  25. package/build/notes.js +188 -0
  26. package/build/notes.js.map +1 -0
  27. package/build/notify.js +393 -0
  28. package/build/notify.js.map +1 -0
  29. package/build/overrides.js +82 -0
  30. package/build/overrides.js.map +1 -0
  31. package/build/paths.js +1 -0
  32. package/build/paths.js.map +1 -1
  33. package/build/profile.js +7 -0
  34. package/build/profile.js.map +1 -1
  35. package/build/pushover.js +67 -0
  36. package/build/pushover.js.map +1 -0
  37. package/build/queue.js +178 -0
  38. package/build/queue.js.map +1 -0
  39. package/build/registry.js +3 -1
  40. package/build/registry.js.map +1 -1
  41. package/build/rule-input.js +17 -0
  42. package/build/rule-input.js.map +1 -0
  43. package/build/rules-service.js +402 -0
  44. package/build/rules-service.js.map +1 -0
  45. package/build/rules.js +842 -0
  46. package/build/rules.js.map +1 -0
  47. package/build/scheduler.js +274 -0
  48. package/build/scheduler.js.map +1 -0
  49. package/build/server.js +204 -0
  50. package/build/server.js.map +1 -1
  51. package/build/spend.js +8 -0
  52. package/build/spend.js.map +1 -1
  53. package/build/startup.js +30 -0
  54. package/build/startup.js.map +1 -1
  55. package/build/store.js +271 -0
  56. package/build/store.js.map +1 -1
  57. package/build/token.js +3 -3
  58. package/build/token.js.map +1 -1
  59. package/build/upgrade.js +105 -0
  60. package/build/upgrade.js.map +1 -0
  61. package/build/wait.js +32 -32
  62. package/build/wait.js.map +1 -1
  63. package/build/watchers/index.js +1 -0
  64. package/build/watchers/index.js.map +1 -1
  65. package/build/watchers/linear-key.js +6 -45
  66. package/build/watchers/linear-key.js.map +1 -1
  67. package/build/watchers/linear-queue.js +124 -0
  68. package/build/watchers/linear-queue.js.map +1 -0
  69. package/build/watchers/linear.js +16 -7
  70. package/build/watchers/linear.js.map +1 -1
  71. package/build/why.js +78 -0
  72. package/build/why.js.map +1 -0
  73. package/mod/.claude-plugin/marketplace.json +6 -0
  74. package/mod/.claude-plugin/plugin.json +7 -0
  75. package/mod/README.md +17 -0
  76. package/mod/hooks/hooks.json +1 -0
  77. package/mod/hooks/model.ts +395 -0
  78. package/mod/hooks/register.tsx +505 -0
  79. package/mod/types/index.d.ts +57 -0
  80. package/package.json +6 -1
@@ -1 +1 @@
1
- {"version":3,"file":"linear.js","sourceRoot":"","sources":["../../src/watchers/linear.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"linear.js","sourceRoot":"","sources":["../../src/watchers/linear.ts"],"names":[],"mappings":"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"}
package/build/why.js ADDED
@@ -0,0 +1,78 @@
1
+ import { z } from 'zod';
2
+ import {} from "./store.js";
3
+ // `conduct why` (design note, section 9): every action is an event that names the rule behind it,
4
+ // directly (`rule`) or through the event that caused it (`data.cause`). This follows that chain
5
+ // back to the rule, and gives its text as it was when it fired.
6
+ const eventSchema = z.object({
7
+ at: z.string(),
8
+ data: z.record(z.string(), z.unknown()),
9
+ id: z.number(),
10
+ kind: z.string(),
11
+ project: z.string().nullable(),
12
+ rule: z.string().nullable(),
13
+ subject: z.string().nullable(),
14
+ });
15
+ export const whySchema = z.object({
16
+ // The event asked about, then each cause before it.
17
+ chain: z.array(eventSchema),
18
+ // The rule behind it: its ref, and its text as it fired (or as it is now, when the event didn't
19
+ // record it). Null when no rule caused it: a worker's own note, Jason's command.
20
+ rule: z
21
+ .object({
22
+ do: z.array(z.string()).nullable(),
23
+ from: z.enum(['a command', 'the event', 'the rules in force', 'not in force any more']),
24
+ ref: z.string(),
25
+ when: z.string().nullable(),
26
+ })
27
+ .nullable(),
28
+ });
29
+ const MAX_CHAIN = 10;
30
+ const recorded = z.looseObject({ do: z.array(z.string()).optional(), when: z.string().nullable().optional() });
31
+ export function explain(store, id, rules) {
32
+ const first = store.getEvent(id);
33
+ if (!first)
34
+ return null;
35
+ const chain = [first];
36
+ for (let at = first; chain.length < MAX_CHAIN;) {
37
+ const cause = at.data.cause;
38
+ const next = typeof cause === 'number' ? store.getEvent(cause) : null;
39
+ if (!next || chain.some((e) => e.id === next.id))
40
+ break;
41
+ chain.push(next);
42
+ at = next;
43
+ }
44
+ const source = chain.find((e) => e.rule !== null);
45
+ if (!source?.rule)
46
+ return { chain, rule: null };
47
+ // An override set by a command names it (`conduct pause`); a rule's ref has a source and a colon.
48
+ if (!source.rule.includes(':'))
49
+ return { chain, rule: { do: null, from: 'a command', ref: source.rule, when: null } };
50
+ // The text as it fired is on the `rule.fired` event, which a `rule.done` names as its cause.
51
+ for (const e of chain) {
52
+ const text = e.rule === source.rule ? recorded.safeParse(e.data).data : undefined;
53
+ if (text?.do !== undefined)
54
+ return { chain, rule: { do: text.do, from: 'the event', ref: source.rule, when: text.when ?? null } };
55
+ }
56
+ const now = rules.find((r) => r.ref === source.rule);
57
+ return {
58
+ chain,
59
+ rule: now
60
+ ? { do: now.text.do, from: 'the rules in force', ref: now.ref, when: now.text.when }
61
+ : { do: null, from: 'not in force any more', ref: source.rule, when: null },
62
+ };
63
+ }
64
+ // `conduct why`: the rule first, then the chain of events from the one asked about back to its cause.
65
+ export function whyLines(why) {
66
+ const { rule } = why;
67
+ const lines = rule === null ? ['no rule: nothing in its chain was caused by a rule (a worker, a command, an outside event)']
68
+ : rule.from === 'a command' ? [`set by \`${rule.ref}\``]
69
+ : [`${rule.ref}: ${rule.when === null ? '' : `when ${rule.when} → `}${rule.do?.join('; ') ?? '(its text is gone)'} (from ${rule.from})`];
70
+ for (const [i, e] of why.chain.entries()) {
71
+ const detail = ['outcome', 'action', 'error', 'reason', 'by']
72
+ .flatMap((k) => (typeof e.data[k] === 'string' ? [`${k}: ${String(e.data[k])}`] : []))
73
+ .join('; ');
74
+ lines.push(`${i === 0 ? ' ' : ' ← '}#${e.id} ${new Date(e.at).toLocaleString()} ${e.kind}${e.subject ? ` ${e.subject}` : ''}${e.project ? ` (${e.project})` : ''}${e.rule ? ` [${e.rule}]` : ''}${detail ? `: ${detail}` : ''}`);
75
+ }
76
+ return lines;
77
+ }
78
+ //# sourceMappingURL=why.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"why.js","sourceRoot":"","sources":["../src/why.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "conductor",
3
+ "description": "The conductor mod, shipped inside @detergent-software/conductor and installed by `conduct install-mod`.",
4
+ "owner": { "name": "Emergent Software" },
5
+ "plugins": [{ "name": "conductor", "source": "./" }]
6
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "conductor",
3
+ "version": "1.0.0",
4
+ "description": "The conductor console's plumbing: a status line in every session, and in the console the inbox band, the fleet pane, zero-token commands, Remote Control pushes and escalation wake-ups.",
5
+ "author": { "name": "Emergent Software" },
6
+ "types": "./types/index.d.ts"
7
+ }
package/mod/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # Conductor mod
2
+
3
+ A Claude Code plugin (a hooks module) that does the conductor console's plumbing in code, so it costs no tokens: a status line in every session and, in the console (`CONDUCTOR_CONSOLE=1`), the inbox band, the fleet pane, `/conductor` `/inbox` `/approve` `/revise` `/attach` `/notify`, toasts, Remote Control pushes (and the one warning when Remote Control is off), and the one model wake-up for an escalation. What it shows and does is in the conductor README's *Mod* section (`apps/conductor/README.md`).
4
+
5
+ Install it with the daemon's CLI, which ships this folder:
6
+
7
+ ```text
8
+ conduct install-mod
9
+ ```
10
+
11
+ | File | Holds |
12
+ |---|---|
13
+ | `hooks/register.tsx` | the hooks: session start, commands, the band, the pane, the event stream; only its top-level functions take `$` |
14
+ | `hooks/model.ts` | the logic without the engine: parsing the daemon's answers, what the status line, band and pane show, what each event asks for |
15
+ | `types/index.d.ts` | the `$.state` contract (`conductor.snapshot`, `confirming`, `expanded`) |
16
+ | `tests/conductor.test.tsx` | `claude plugin test`: the hooks against the engine, the daemon faked beneath them |
17
+ | `tests/model.spec.ts` | vitest (`pnpm -C apps/conductor test`, in CI): `model.ts` |
@@ -0,0 +1 @@
1
+ { "modules": ["./register.tsx"] }
@@ -0,0 +1,395 @@
1
+ // The conductor mod's logic, with nothing of the engine in it: what the daemon's answers mean, what
2
+ // the status line, band and pane show, and what each event asks the mod to do. register.tsx does
3
+ // the engine's part (only its top-level functions may take `$`); vitest tests this file in CI
4
+ // (apps/conductor/mod/tests/model.spec.ts).
5
+ import type { ConductorInboxItem, ConductorNotify, ConductorSnapshot, ConductorWorker } from '../types';
6
+
7
+ // A daemon API answer: its status and parsed JSON body.
8
+ export type ApiAnswer = { body: unknown; status: number };
9
+
10
+ // One line of `conduct events --follow`: an event of the log (with its id), or the stream's state.
11
+ export type StreamLine = { data: Record<string, unknown>; id: number | null; kind: string; subject: string | null };
12
+
13
+ // What an event asks of the mod. Only `escalate` wakes the console's model.
14
+ export type Reaction =
15
+ | { kind: 'disconnected' }
16
+ | { kind: 'escalate'; text: string }
17
+ | { kind: 'ignore' }
18
+ | { kind: 'push'; message: string }
19
+ | { kind: 'refresh'; toast: string | null }
20
+ | { kind: 'send'; text: string; to: string };
21
+
22
+ // What a Remote Control push came to: reached the phone (ok); not, as Remote Control is off
23
+ // (inactive) or pushes are off in Claude Code's config (disabled); not sent to the phone on
24
+ // purpose (skipped: Jason is at the terminal, or the answer says nothing about the phone); or the
25
+ // call failed (failed: it threw, was denied, or answered an error).
26
+ export type PushOutcome = { detail: string; state: 'disabled' | 'failed' | 'inactive' | 'ok' | 'skipped' };
27
+
28
+ // Said once in the console when pushes stop reaching the phone (ATK-255), by why.
29
+ export function pushWarning(outcome: PushOutcome): null | string {
30
+ switch (outcome.state) {
31
+ case 'disabled':
32
+ return "conductor: mobile pushes are off in Claude Code's config, so pushes reach this terminal only. Turn them on, or /notify away for Pushover.";
33
+ case 'failed':
34
+ return `conductor: a Remote Control push failed (${outcome.detail}). /notify away sends by Pushover instead.`;
35
+ case 'inactive':
36
+ return 'conductor: Remote Control is off, so pushes reach this terminal only. Connect Remote Control, or /notify away for Pushover.';
37
+ case 'ok':
38
+ case 'skipped':
39
+ return null;
40
+ }
41
+ }
42
+
43
+ // The state the daemon records for a push's outcome (POST /notify/report).
44
+ export function reportedState(outcome: PushOutcome): 'failing' | 'inactive' | 'ok' | 'skipped' {
45
+ if (outcome.state === 'disabled') return 'inactive';
46
+ return outcome.state === 'failed' ? 'failing' : outcome.state;
47
+ }
48
+
49
+ // A band entry and the act its press does.
50
+ export type BandEntry = { act: 'approve' | 'copy' | 'pane'; hotkey: string; id: number; label: string; text: string };
51
+
52
+ export type ProjectGroup = { project: string; rows: ConductorWorker[]; running: number };
53
+
54
+ // A lookup by the item key, or an inbox id written #12; a message when it doesn't resolve to one.
55
+ export type Found<T> = { error: string; found?: undefined } | { error?: undefined; found: T };
56
+
57
+ const BAND_LIMIT = 5;
58
+
59
+ // `conductor 3▶ 2⏸ ✉2`, or undefined (the line cleared) when no daemon answers.
60
+ export function statusText(snapshot: ConductorSnapshot | null): string | undefined {
61
+ if (snapshot === null || snapshot.error !== null) return undefined;
62
+ const running = snapshot.workers.filter((w) => w.status === 'running').length;
63
+ const parked = snapshot.workers.filter((w) => w.status === 'parked').length;
64
+ return `conductor ${running}▶ ${parked}⏸ ✉${snapshot.inbox.length}`;
65
+ }
66
+
67
+ // The band's buttons: a plan approves (behind a confirm), an npm OTP copies its command, the rest
68
+ // open the pane, where each item's commands and links are.
69
+ export function bandEntries(inbox: readonly ConductorInboxItem[]): BandEntry[] {
70
+ return inbox.slice(0, BAND_LIMIT).map((item, i) => {
71
+ const key = item.item ?? `#${item.id}`;
72
+ const hotkey = String(i + 1);
73
+ if (item.kind === 'plan' && item.item !== null) return { act: 'approve', hotkey, id: item.id, label: `approve ${key}`, text: item.text };
74
+ const command = item.commands[0];
75
+ if (item.kind === 'npm-otp' && command !== undefined) return { act: 'copy', hotkey, id: item.id, label: `copy OTP line ${key}`, text: command };
76
+ return { act: 'pane', hotkey, id: item.id, label: `${item.kind} ${key}`, text: item.text };
77
+ });
78
+ }
79
+
80
+ // The fleet by project, running workers first within each, projects by name.
81
+ export function projectGroups(workers: readonly ConductorWorker[]): ProjectGroup[] {
82
+ const byProject = new Map<string, ConductorWorker[]>();
83
+ for (const w of workers) byProject.set(w.project, [...(byProject.get(w.project) ?? []), w]);
84
+ return [...byProject.entries()]
85
+ .sort(([a], [b]) => a.localeCompare(b))
86
+ .map(([project, rows]) => ({
87
+ project,
88
+ rows: [...rows].sort((a, b) => Number(b.status === 'running') - Number(a.status === 'running') || a.name.localeCompare(b.name)),
89
+ running: rows.filter((w) => w.status === 'running').length,
90
+ }));
91
+ }
92
+
93
+ // A worker row's glyph: ▶ running, ⏸ parked, ✖ failed or stopped, · otherwise (launching, exited).
94
+ export function glyph(status: string): string {
95
+ if (status === 'running') return '▶';
96
+ if (status === 'parked') return '⏸';
97
+ if (status === 'failed' || status === 'stopped-unexpectedly') return '✖';
98
+ return '·';
99
+ }
100
+
101
+ // What a worker waits on or does: its open wait, else the session's activity.
102
+ export function workerDoing(w: ConductorWorker): string {
103
+ return w.waits[0] ?? w.activity;
104
+ }
105
+
106
+ // The open plan of `ref` (as `conduct approve` finds it): an item key, or an inbox id as #12.
107
+ export function findPlan(inbox: readonly ConductorInboxItem[], ref: string): Found<ConductorInboxItem> {
108
+ const byId = /^#(\d+)$/.exec(ref.trim());
109
+ if (byId) {
110
+ const item = inbox.find((i) => i.id === Number(byId[1]));
111
+ return item ? { found: item } : { error: `no open inbox item ${ref}` };
112
+ }
113
+ if (/^\d+$/.test(ref.trim())) return { error: `"${ref}" is ambiguous: name the item, such as ATK-${ref.trim()}, or the inbox id as #${ref.trim()}` };
114
+ const plans = inbox.filter((i) => i.kind === 'plan' && i.item?.toUpperCase() === ref.trim().toUpperCase());
115
+ if (plans.length === 1 && plans[0]) return { found: plans[0] };
116
+ if (plans.length === 0) return { error: `no plan of ${ref} waits in the inbox` };
117
+ return { error: `several plans of ${ref} wait: name one as ${plans.map((p) => `#${p.id}`).join(' or ')}` };
118
+ }
119
+
120
+ // A worker in flight by name or item; a name match wins, as `conduct attach` finds it.
121
+ export function findWorker(workers: readonly ConductorWorker[], ref: string): Found<ConductorWorker> {
122
+ const byName = workers.filter((w) => w.name === ref);
123
+ const matches = byName.length > 0 ? byName : workers.filter((w) => w.item.toUpperCase() === ref.toUpperCase());
124
+ if (matches.length === 1 && matches[0]) return { found: matches[0] };
125
+ if (matches.length === 0) return { error: `no worker "${ref}" in flight` };
126
+ return { error: `"${ref}" names several workers: ${matches.map((w) => `${w.name} in ${w.project}`).join(', ')}` };
127
+ }
128
+
129
+ // `/inbox`'s answer: one line per item, then its commands and links.
130
+ export function inboxText(inbox: readonly ConductorInboxItem[], now: number): string {
131
+ if (inbox.length === 0) return 'The inbox is empty.';
132
+ return inbox
133
+ .flatMap((i) => [
134
+ `#${i.id} ${i.kind} ${i.item ?? ''}${i.project ? ` (${i.project})` : ''} ${age(i.raisedAt, now)}`,
135
+ ` ${i.text}`,
136
+ ...i.commands.map((c) => ` $ ${c}`),
137
+ ...i.links.map((l) => ` ${l}`),
138
+ ])
139
+ .join('\n');
140
+ }
141
+
142
+ // "now", "12m", "3h", "2d".
143
+ export function age(iso: string, now: number): string {
144
+ const minutes = Math.floor((now - Date.parse(iso)) / 60_000);
145
+ if (!(minutes >= 1)) return 'now';
146
+ if (minutes < 60) return `${minutes}m`;
147
+ if (minutes < 24 * 60) return `${Math.floor(minutes / 60)}h`;
148
+ return `${Math.floor(minutes / (24 * 60))}d`;
149
+ }
150
+
151
+ // The time left until `iso`: "12m", "3h", "2d"; "<1m" when it is (almost) up.
152
+ export function remaining(iso: string, now: number): string {
153
+ const minutes = Math.floor((Date.parse(iso) - now) / 60_000);
154
+ if (!(minutes >= 1)) return '<1m';
155
+ if (minutes < 60) return `${minutes}m`;
156
+ if (minutes < 24 * 60) return `${Math.floor(minutes / 60)}h`;
157
+ return `${Math.floor(minutes / (24 * 60))}d`;
158
+ }
159
+
160
+ // 950, 42k, 6.1M.
161
+ export function tokens(n: number): string {
162
+ if (n < 1000) return String(n);
163
+ if (n < 1_000_000) return `${Math.round(n / 1000)}k`;
164
+ return `${(n / 1_000_000).toFixed(1)}M`;
165
+ }
166
+
167
+ export function spendToday(workers: readonly ConductorWorker[]): number {
168
+ return workers.reduce((sum, w) => sum + w.spendToday, 0);
169
+ }
170
+
171
+ // One line of the follow stream, or null for anything that isn't an event object.
172
+ export function parseLine(line: string): null | StreamLine {
173
+ let value: unknown;
174
+ try {
175
+ value = JSON.parse(line);
176
+ } catch {
177
+ return null;
178
+ }
179
+ if (!isRecord(value) || typeof value.kind !== 'string') return null;
180
+ return {
181
+ data: isRecord(value.data) ? value.data : {},
182
+ id: typeof value.id === 'number' ? value.id : null,
183
+ kind: value.kind,
184
+ subject: typeof value.subject === 'string' ? value.subject : null,
185
+ };
186
+ }
187
+
188
+ // What an event asks of the mod. Remote Control pushes, escalations and worker messages are
189
+ // contracts the daemon's notifier (ATK-313) and rules (ATK-315) emit; the mod only carries them out.
190
+ export function reaction(line: StreamLine): Reaction {
191
+ const text = (key: string): null | string => {
192
+ const value = line.data[key];
193
+ return typeof value === 'string' && value.trim() !== '' ? value : null;
194
+ };
195
+ switch (line.kind) {
196
+ case 'conduct.connected':
197
+ return { kind: 'refresh', toast: null };
198
+ case 'conduct.disconnected':
199
+ return { kind: 'disconnected' };
200
+ case 'console.escalated': {
201
+ const ask = text('text');
202
+ return ask === null ? { kind: 'ignore' } : { kind: 'escalate', text: `[conductor] escalation${line.subject ? ` on ${line.subject}` : ''}: ${ask}` };
203
+ }
204
+ case 'inbox.raised': {
205
+ const ask = text('text');
206
+ return { kind: 'refresh', toast: ask === null ? null : `conductor: ${line.subject ? `${line.subject} · ` : ''}${ask}` };
207
+ }
208
+ case 'notify.failed':
209
+ case 'notify.routed':
210
+ case 'notify.sent':
211
+ // Nothing the mod draws: only notify.profile and notify.channel change the pane.
212
+ return { kind: 'ignore' };
213
+ case 'notify.requested': {
214
+ const message = text('message');
215
+ return line.data.channel === 'remote-control' && message !== null ? { kind: 'push', message } : { kind: 'ignore' };
216
+ }
217
+ case 'watcher.stats':
218
+ return { kind: 'ignore' };
219
+ case 'worker.message-requested': {
220
+ const to = text('to');
221
+ const message = text('message');
222
+ return to === null || message === null ? { kind: 'ignore' } : { kind: 'send', text: message, to };
223
+ }
224
+ default:
225
+ return { kind: 'refresh', toast: null };
226
+ }
227
+ }
228
+
229
+ // GET /fleet's body, kept to the fields the mod draws; null when it isn't one.
230
+ export function parseFleet(body: unknown): ConductorWorker[] | null {
231
+ if (!isRecord(body) || !Array.isArray(body.workers)) return null;
232
+ return body.workers.flatMap((w): ConductorWorker[] => {
233
+ if (!isRecord(w) || typeof w.id !== 'number' || typeof w.name !== 'string' || typeof w.status !== 'string') return [];
234
+ const spend = isRecord(w.spend) && typeof w.spend.today === 'number' ? w.spend.today : 0;
235
+ const waits = Array.isArray(w.waits)
236
+ ? w.waits.flatMap((x) => (isRecord(x) && typeof x.condition === 'string' && x.resolvedAt === null ? [x.condition] : []))
237
+ : [];
238
+ return [
239
+ {
240
+ activity: typeof w.activity === 'string' ? w.activity : w.status,
241
+ id: w.id,
242
+ item: typeof w.item === 'string' ? w.item : w.name,
243
+ name: w.name,
244
+ phase: typeof w.phase === 'string' ? w.phase : null,
245
+ project: typeof w.project === 'string' ? w.project : '?',
246
+ spendToday: spend,
247
+ status: w.status,
248
+ updatedAt: typeof w.updatedAt === 'string' ? w.updatedAt : '',
249
+ waits,
250
+ },
251
+ ];
252
+ });
253
+ }
254
+
255
+ // GET /inbox's body; null when it isn't one.
256
+ export function parseInbox(body: unknown): ConductorInboxItem[] | null {
257
+ if (!isRecord(body) || !Array.isArray(body.items)) return null;
258
+ return body.items.flatMap((i): ConductorInboxItem[] => {
259
+ if (!isRecord(i) || typeof i.id !== 'number' || typeof i.kind !== 'string' || typeof i.text !== 'string') return [];
260
+ return [
261
+ {
262
+ commands: strings(i.commands),
263
+ id: i.id,
264
+ item: typeof i.item === 'string' ? i.item : null,
265
+ kind: i.kind,
266
+ links: strings(i.links),
267
+ project: typeof i.project === 'string' ? i.project : null,
268
+ raisedAt: typeof i.raisedAt === 'string' ? i.raisedAt : '',
269
+ text: i.text,
270
+ },
271
+ ];
272
+ });
273
+ }
274
+
275
+ // The error an API answer carries (`{ error, details }`), as one line.
276
+ export function errorOf(answer: ApiAnswer): string {
277
+ const { body } = answer;
278
+ if (isRecord(body) && typeof body.error === 'string') return [body.error, ...strings(body.details)].join('; ');
279
+ return `the conductor answered ${answer.status}`;
280
+ }
281
+
282
+ // POST /inbox/:id/resolve's answer as the line to show, as `conduct approve|revise|done` says it.
283
+ export function answerText(action: 'approve' | 'done' | 'revise', id: number, answer: ApiAnswer): string {
284
+ if (answer.status !== 200) return `not ${action === 'done' ? 'done' : `${action}d`}: ${errorOf(answer)}`;
285
+ const body = isRecord(answer.body) ? answer.body : {};
286
+ const key = isRecord(body.item) && typeof body.item.item === 'string' ? body.item.item : `#${id}`;
287
+ if (action === 'done') return `done: ${key}`;
288
+ const comment = isRecord(body.comment) ? body.comment : {};
289
+ const where = typeof comment.url === 'string' ? comment.url : typeof comment.id === 'string' ? comment.id : 'comment posted';
290
+ return `${action === 'approve' ? 'approved' : 'asked for a revision of'} ${key}: ${where}`;
291
+ }
292
+
293
+ // The daemon's home as the CLI finds it (apps/conductor/src/paths.ts): CONDUCTOR_HOME, else
294
+ // .conductor under USERPROFILE or HOME.
295
+ export function homeOf(env: { conductorHome?: string; home?: string; userProfile?: string }): null | string {
296
+ if (env.conductorHome) return env.conductorHome;
297
+ const user = env.userProfile || env.home;
298
+ return user ? `${user.replace(/[\\/]+$/, '')}/.conductor` : null;
299
+ }
300
+
301
+ // The port and token files' text as an endpoint; null unless both are whole.
302
+ export function endpointOf(portText: string, tokenText: string): { port: number; token: string } | null {
303
+ const port = Number(portText.trim());
304
+ const token = tokenText.trim();
305
+ return Number.isInteger(port) && port > 0 && /^[0-9a-f]{64}$/.test(token) ? { port, token } : null;
306
+ }
307
+
308
+ // GET /fleet, GET /inbox and GET /notify as one snapshot; `error` set when the daemon didn't answer
309
+ // the first two. A daemon older than the notifier answers /notify 404, which leaves `notify` null.
310
+ export function snapshotOf(fleet: ApiAnswer, inbox: ApiAnswer, readAt: number, notify?: ApiAnswer): ConductorSnapshot {
311
+ const workers = fleet.status === 200 ? parseFleet(fleet.body) : null;
312
+ if (workers === null) return { error: errorOf(fleet), inbox: [], notify: null, readAt, workers: [] };
313
+ const items = inbox.status === 200 ? parseInbox(inbox.body) : null;
314
+ if (items === null) return { error: errorOf(inbox), inbox: [], notify: null, readAt, workers: [] };
315
+ return { error: null, inbox: items, notify: notify?.status === 200 ? parseNotify(notify.body) : null, readAt, workers };
316
+ }
317
+
318
+ // GET /notify's body, kept to what the mod draws; null when it isn't one.
319
+ export function parseNotify(body: unknown): ConductorNotify | null {
320
+ if (!isRecord(body) || typeof body.profile !== 'string') return null;
321
+ const channels = isRecord(body.channels) ? body.channels : {};
322
+ const remote = isRecord(channels['remote-control']) ? channels['remote-control'] : {};
323
+ return {
324
+ held: typeof body.held === 'number' ? body.held : 0,
325
+ profile: body.profile,
326
+ profiles: strings(body.profiles),
327
+ profileUntil: typeof body.profileUntil === 'string' ? body.profileUntil : null,
328
+ quietNow: body.quietNow === true,
329
+ remoteControl: typeof remote.state === 'string' ? remote.state : 'unknown',
330
+ };
331
+ }
332
+
333
+ // What `$.tool.call` of PushNotification answered: `{ result: { pushSent, disabledReason }, text }`.
334
+ // Only a push that reached the phone is ok; Remote Control off (no_transport, or the text saying
335
+ // so) is inactive; pushes turned off in the config are disabled; the rest say nothing of the phone.
336
+ export function pushOutcome(answer: unknown): PushOutcome {
337
+ const call = isRecord(answer) ? answer : {};
338
+ if (typeof call.deny === 'string') return { detail: `refused: ${call.deny}`, state: 'failed' };
339
+ const result = isRecord(call.result) ? call.result : {};
340
+ const detail = typeof call.text === 'string' && call.text.trim() !== '' ? call.text.trim() : typeof result.message === 'string' ? result.message : '';
341
+ if (call.isError === true) return { detail: detail || 'PushNotification answered an error', state: 'failed' };
342
+ if (result.pushSent === true) return { detail, state: 'ok' };
343
+ if (result.disabledReason === 'config_off') return { detail: "Mobile push not sent (off in Claude Code's config)", state: 'disabled' };
344
+ if (result.disabledReason === 'no_transport' || /remote control inactive/i.test(detail)) {
345
+ return { detail: detail || 'Mobile push not sent (Remote Control inactive)', state: 'inactive' };
346
+ }
347
+ if (result.disabledReason === 'user_present') return { detail: 'Mobile push not sent: you were at the terminal (user_present)', state: 'skipped' };
348
+ return { detail: detail || 'PushNotification said nothing about the phone', state: 'skipped' };
349
+ }
350
+
351
+ // `/notify <profile> [--until <when>]`: --until is a local time (the next one), a date (local
352
+ // midnight) or a date and time, as `conduct notify profile` reads it.
353
+ export function notifyArgs(args: string, now: number): { error: string } | { name: string; until: null | string } {
354
+ const typed = /^(\S+)(?:\s+--until\s+(\S+))?$/.exec(args.trim());
355
+ if (!typed?.[1]) return { error: 'usage: /notify [<profile> [--until <when>]]' };
356
+ const when = typed[2];
357
+ if (when === undefined) return { name: typed[1], until: null };
358
+ const clock = /^([01]?\d|2[0-3]):([0-5]\d)$/.exec(when);
359
+ let at: Date;
360
+ if (clock) {
361
+ at = new Date(now);
362
+ at.setHours(Number(clock[1]), Number(clock[2]), 0, 0);
363
+ if (at.getTime() <= now) at.setDate(at.getDate() + 1);
364
+ } else {
365
+ at = new Date(/^\d{4}-\d{2}-\d{2}$/.test(when) ? `${when}T00:00` : when);
366
+ }
367
+ if (Number.isNaN(at.getTime())) return { error: `--until "${when}" is not a time: a local time such as 17:00, or a date and time such as 2026-10-12T09:00` };
368
+ return { name: typed[1], until: at.toISOString() };
369
+ }
370
+
371
+ // `/notify` with no profile: the profile, quiet hours, Remote Control.
372
+ export function notifyText(notify: ConductorNotify | null, now: number): string {
373
+ if (notify === null) return 'the running conductor has no notifier: restart it on this build (conduct upgrade)';
374
+ const until = notify.profileUntil === null ? '' : ` for ${remaining(notify.profileUntil, now)} more`;
375
+ return [
376
+ `notify profile: ${notify.profile}${until} (profiles: ${notify.profiles.join(', ')}; /notify <profile> switches)`,
377
+ `Remote Control: ${notify.remoteControl}${notify.quietNow ? ` · quiet hours now, ${notify.held} held for the summary` : ''}`,
378
+ ].join('\n');
379
+ }
380
+
381
+ // POST /notify/profile's answer as the line to show.
382
+ export function profileText(name: string, answer: ApiAnswer, now: number): string {
383
+ if (answer.status !== 200) return `notify profile not switched: ${errorOf(answer)}`;
384
+ const notify = parseNotify(answer.body);
385
+ const until = notify?.profileUntil ? ` for ${remaining(notify.profileUntil, now)}` : '';
386
+ return `notify profile: ${notify?.profile ?? name}${until}`;
387
+ }
388
+
389
+ function isRecord(value: unknown): value is Record<string, unknown> {
390
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
391
+ }
392
+
393
+ function strings(value: unknown): string[] {
394
+ return Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string') : [];
395
+ }