omp-conductor 0.16.0 → 0.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,220 @@
1
+ import { AMEND_AREA_IDS } from "./setup.ts";
2
+
3
+ /** Long-form operator help preserved from the pre-manifest CLI. */
4
+ export const COMMAND_DETAILS = ` setup interview, then write config.json, the labels, the briefs and the
5
+ staged host files behind one confirm. Bare is a full run — or, when
6
+ the project already exists, a chooser of which area to amend. Naming
7
+ an area positionally skips that chooser and amends only that area:
8
+ ${AMEND_AREA_IDS.join(", ")}.
9
+ upgrade update the Bun-global CLI, omp plugin, Herdr recovery plugin, and
10
+ brief as one pinned release. Pauses only new claims, drains live
11
+ workers, reloads, verifies twice, and restores the prior dispatch
12
+ state. Run it from a shell outside the target Herdr session.
13
+ upgrade-install
14
+ the detached executor half of the fleet-installs-itself request:
15
+ the same transaction, journaled per surface, leaving verification
16
+ and dispatch restore to the first tick after the restart. Run by
17
+ the transient unit, never by hand in a Herdr session.
18
+ upgrade-rollback
19
+ the detached rollback unit: restore every surface the failed
20
+ upgrade-install touched, from the durable pre-install snapshot in
21
+ the upgrade journal, and report through the durable outbox.
22
+ start start the installed herdr-fleet.service when present, then run the
23
+ dispatch loop in the background and wait until it answers GET
24
+ /healthz on :8787 (override with --port). Refuses if one is running.
25
+ stop stop the conductor: pause claiming, disarm ticks, then stop the
26
+ dispatch daemon (systemctl-aware: an explicit stop is recorded by
27
+ systemd, so Restart=always does not undo it). Pane stays up unless
28
+ --pane is passed. To bounce the daemon without stopping the fleet,
29
+ use restart.
30
+ stop --pane
31
+ also stop the conductor agent's pane and pin herdr-conductor recovery
32
+ off for that agent only — it does NOT stop herdr-fleet.service or any
33
+ other herdr session. resume clears the pin.
34
+ restart drain the fleet by default: pause new claims, wait until live workers
35
+ reach 0/N (bounded by --timeout SECONDS, default 1800), restart keeping
36
+ the running daemon's port and project unless a flag overrides them,
37
+ then restore the prior dispatch state. --now skips the drain and
38
+ restarts immediately, orphaning any live runs (old behavior). A drain
39
+ that hits --timeout restarts nothing and leaves dispatch paused. On boot
40
+ the new process salvages dirty live worktrees before orphaning those
41
+ rows — see README "Deploying a new package onto a busy fleet". Goes
42
+ through systemctl when the unit owns the live pid; a failed
43
+ installed unit is reset and restarted through systemd, never
44
+ replaced by an unmanaged daemon.
45
+ status layered fleet report: dispatch (running|paused|stopped), ticks and
46
+ next due time, pane, herdr, Telegram bot/API health, daemon, caps
47
+ and active runs.
48
+ stats what the fleet accomplished and at what cost, read wholly from the
49
+ local store: issues merged, merge rate, queue-to-merge lead time
50
+ (median/p90), attempts per merged issue, metered spend per merged
51
+ issue, the failure-class breakdown of what did not merge, and
52
+ tracked gh calls over the window. Continuation chains collapse into
53
+ one journey; $0.00 runs are reported as unmetered, never averaged in
54
+ as free. --json prints the stable {project, window, ghCalls, empty,
55
+ total, repos} shape.
56
+ doctor read-only deployment health, one finding per past failure mode:
57
+ gh auth/scopes, exact-case configured labels, systemd unit drift
58
+ and runtime-dir ownership, config + backup freshness, sqlite
59
+ integrity, spend telemetry, reporting timezones, Telegram health.
60
+ The only write anywhere is the self-identified probe message that
61
+ --probe-telegram sends through the report transport. Exit code 0
62
+ only when nothing failed; --json prints the stable CI shape. Run
63
+ it after install and after every upgrade.
64
+ restore-db
65
+ put conductor.db back to a restorable snapshot, replacing the live
66
+ file and dropping stale -wal/-shm sidecars. Refuses while a daemon
67
+ is live — restoring under a running daemon is a corruption path.
68
+ The default source is the newest snapshot in the configured db
69
+ backup directory; an explicit snapshot path overrides it.
70
+ board open the live keyboard-driven fleet board. It renders queue holds,
71
+ every run lifecycle stage, recent merges, spend and health; Enter
72
+ follows a selected transcript without leaving the board. --json (or
73
+ a non-interactive stdin/stdout) prints a one-shot JSON snapshot of
74
+ the same lanes instead.
75
+ dashboard
76
+ serve the fleet dashboard in a browser: the UI shell and GET
77
+ /api/projects, bearer-authenticated with the token minted 0600 at
78
+ <state>/dashboard-token on first start. Binds 127.0.0.1:8788 by
79
+ default; a non-loopback --host still starts but prints a warning
80
+ naming the token file. A separate process — never a route on the
81
+ daemon port.
82
+ ledger every conductor-verb call and how the daemon decided it: the verb,
83
+ the arguments, allow or refuse, the named refusal reason, and the
84
+ resulting sha. Sessions cannot push, open, merge, label or release
85
+ except through those verbs, so this is the record of what they tried
86
+ as well as what they did. --issue narrows it to one issue's run.
87
+ hold soft stop: pause claiming AND disarm ticks. Daemon and pane stay up.
88
+ This is "stop the conductor overnight" without killing processes.
89
+ Use --all to target every configured project.
90
+ arm proof-gated: send a Telegram challenge and write the arm marker only
91
+ after your reply appears as a user turn in the orchestrator transcript.
92
+ Never auto-armed by resume/hold. Use --all for every project.
93
+ disarm remove the arm marker so ticks skip. Processes untouched. Use --all
94
+ to target every configured project.
95
+ tail follow the newest run for <issue>: the worker's assistant text and
96
+ the tools it calls, printed as they land. Workers are sessions inside
97
+ the daemon rather than terminals, so this is the only way to watch
98
+ one live. Runs until Ctrl-C, or until the run has finished and its
99
+ transcript has stopped growing.
100
+ extend raise a live run's turn ceiling, or set a bounded one-shot ceiling
101
+ after a failed, killed, orphaned or blocked run. Refuses values outside
102
+ configured bounds.
103
+ worker cooperatively pause one live worker at harness idle, then resume the
104
+ same session with a continuation prompt. Its wall clock is frozen
105
+ while parked. Distinct from fleet-level pause/resume.
106
+ unblock clear <issue>'s blocked and failed labels so the next tick can claim
107
+ it again — the supported way back for an escalation you answered,
108
+ and why the brief's "never hand-edit a state label" rule can stay
109
+ absolute. Run history is kept; answered blocks consume the separate
110
+ operational-continuation budget, not failed implementation attempts.
111
+ Refuses when the newest attempt's work could not be committed and
112
+ its worktree is the only copy: re-claiming removes that tree. Use
113
+ --force once you have recovered it or accepted the loss. Restores
114
+ the project queue label by default so the issue is actually
115
+ dispatchable; --no-requeue clears state labels only (the "about to
116
+ close it" case).
117
+ verb run one conductor_* verb as the orchestrator, from the CLI: the same
118
+ checks and the same ledger rows a session's call would get. This is
119
+ how an external orchestrator merges, labels, releases or reads PR
120
+ state without a raw gh call that skips every gate. Arguments are
121
+ strings, one per --arg (e.g. --arg prUrl=https://x --arg headSha=y).
122
+ A refusal exits 3. See conductor_pr_merge/conductor_label/
123
+ conductor_release/conductor_pr_update_branch in the brief.
124
+ event persist one ordinary material outcome without sending it. Category
125
+ is a short lowercase slug; summary and evidence name what happened
126
+ and where it can be verified. --occurred-at defaults to now.
127
+ report hand a rendered report to the daemon's durable outbox. The report is
128
+ persisted before anything is sent, delivered by the daemon with
129
+ bounded retries, and shown by status until it lands. Delivery is
130
+ at-least-once: a crash mid-send is retried and the retry says it may
131
+ be a repeat. --kind digest is accepted at most once per local day,
132
+ decided from the ledger rather than from what you remember sending.
133
+ A digest associates the comma-separated --events and --notices rows
134
+ atomically; omitted rows stay owed. The other --kind values (tier2,
135
+ decision-needed, fleet-stopped, confirmed-failure) declare the
136
+ report's interrupt category: the reporting policy decides between
137
+ sending now and holding, exactly as for a daemon escalation. An
138
+ identical retry is refused only while the earlier handoff is still
139
+ undelivered, and admitted again once it lands (#453).
140
+ message deliver one direct Telegram message to this project's own chat and
141
+ forum topic, resolved from config rather than from whichever chat
142
+ last wrote to the session. This is how a locally injected tick
143
+ answers or asks something directly: telegram_send keeps the active
144
+ topic only while it names no chat, and a tick has no active topic to
145
+ keep. A question — text beginning "QUESTION:", or a --category that
146
+ is not material — records an open decision row before delivery
147
+ (parked on silence: still pending in every tick until answered or
148
+ the seven-day expiry, so no one has to remember a separate
149
+ \`decision open\`), and --category carries the escalation category
150
+ directly instead of a text prefix. The operator's availability
151
+ policy still decides between sending now and holding a notice,
152
+ exactly as it does for an autonomous tick.
153
+ decision record, list and close the questions you have put to your operator.
154
+ A question that lives only in a session's context is lost to the next
155
+ compaction, so \`decision open\` writes it down and every tick's prompt
156
+ carries what is still owed. \`--resolves-when\` attaches a condition the
157
+ daemon checks for you (pr-merged:<url>, issue-closed:<n>,
158
+ npm-version:<pkg>@<version>); a met one is flagged in that digest.
159
+ Unanswered rows expire after seven days rather than accumulating.
160
+ decision open --question TEXT [--blocks TEXT] [--resolves-when COND]
161
+ decision resolve <id> --answer TEXT
162
+ decision withdraw <id> [--reason TEXT]
163
+ decision list
164
+ watch set a condition or carry note for the orchestrator itself, with no
165
+ human in the loop — the same no-sleep surface \`decision open
166
+ --resolves-when\` used to serve, given its own verb so it never renders
167
+ as a question put to the operator. \`--resolves-when\` attaches a
168
+ condition the daemon checks for you; a met watch wakes the next tick
169
+ with its note, exactly as a met question does, but it is listed under
170
+ its own heading and never under "Open operator decisions", and it has
171
+ no seven-day expiry. \`watch list\` shows open watches.
172
+ watch add --note TEXT [--blocks TEXT] [--resolves-when COND]
173
+ watch list
174
+ intake keep a raw idea durably before it becomes anything: record it now
175
+ with \`omp-conductor intake "<text>"\`, list what is still pending,
176
+ dismiss what turned out to be nothing. Backed by the sqlite store,
177
+ not a session, so ideas survive restarts; the orchestrator grooms
178
+ one into an issue as its #300 duty and records that provenance with
179
+ \`omp-conductor intake groomed <id> --issue <url>\`.
180
+ friction record a bounded observation the daemon cannot classify itself:
181
+ an escalation that belonged in a digest, or a tick report that was
182
+ noise/surprising. Repeated observations feed the existing Learning
183
+ loop; recording one never edits policy by itself.
184
+ daemon run the dispatch loop in the foreground; --once runs a single tick
185
+ and exits. This is what \`start\` launches.
186
+ resume clear pause and any pane-recovery pin. Does NOT re-arm: run arm after
187
+ an inbound Telegram proof to bring ticks back. Use --all for every project.
188
+ setup host [NAME]
189
+ re-stage the systemd unit and run the install behind one confirm.
190
+ The units are host-global; NAME (or --project NAME) says which
191
+ project's per-project tail (tick config, brief link) to write, and
192
+ is required on a host with several configured projects.
193
+ setup graph
194
+ set up the code-graph indexes workers query instead of grepping, end
195
+ to end: check prerequisites, clone any missing index-only clone as
196
+ you, install and enable the reindex timer as root, then seed one
197
+ indexing run and verify it. --no-seed enables without seeding;
198
+ --print changes nothing. Exits 1 when no repo has graphProject.
199
+ brief-upgrade
200
+ inspect the brief overlay (package floor + POLICY.md). Reports by
201
+ default. --migrate lifts a bannered ORCHESTRATOR.md owned half into
202
+ POLICY.md and recomposes. --retrofit proposes inserting the YOURS TO
203
+ EDIT banner before the first Releases/Project context/Reporting/
204
+ Amendments heading (#20); --retrofit --apply writes it. --apply only
205
+ ever confirms one of those two — the legacy single-file merge was
206
+ removed in 0.4.3. --file checks a brief that is not where the wizard
207
+ would have put it.
208
+ help print this text (also --help, -h).
209
+ --version
210
+ print the installed omp-conductor package version (also -V, version).`;
211
+
212
+ /** Cross-command lifecycle notes that follow the per-command help. */
213
+ export const COMMAND_HELP_TAIL = `Pause is a flag file under the state directory, so it applies to the selected
214
+ project (or every configured project with --all) and survives a daemon restart.
215
+ Hold also removes the arm marker the heartbeat reads, so both brains go quiet
216
+ without killing processes. A running daemon is tracked by a pidfile under
217
+ $OMP_CONDUCTOR_RUNTIME_DIR (default
218
+ ~/.omp/run/daemons/omp-conductor), written whether it was started in the
219
+ background or in the foreground, and probed for liveness on every read — a
220
+ stale one never blocks a start.`;