omp-conductor 0.15.13 → 0.16.1

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 (50) hide show
  1. package/REFERENCE.md +72 -2
  2. package/package.json +2 -1
  3. package/schema/config.schema.json +7 -0
  4. package/src/admission.ts +849 -0
  5. package/src/ask.ts +47 -0
  6. package/src/backups.ts +19 -7
  7. package/src/board.ts +1 -2
  8. package/src/briefs/orchestrator.md +62 -4
  9. package/src/cli.ts +26 -0
  10. package/src/commands/context.ts +3 -0
  11. package/src/commands/decision.ts +10 -1
  12. package/src/commands/doctor.ts +2 -0
  13. package/src/commands/message.ts +8 -1
  14. package/src/commands/restart.ts +15 -3
  15. package/src/commands/restore-db.ts +146 -0
  16. package/src/commands/stop.ts +24 -15
  17. package/src/commands/tail.ts +204 -44
  18. package/src/commands/unfreeze.ts +56 -0
  19. package/src/commands/watch.ts +77 -0
  20. package/src/config-schema.ts +13 -0
  21. package/src/config.ts +54 -0
  22. package/src/daemon.ts +255 -530
  23. package/src/dashboard/server.ts +2 -1
  24. package/src/decisions.ts +32 -7
  25. package/src/depends-on.ts +122 -0
  26. package/src/doctor.ts +297 -5
  27. package/src/escalate.ts +191 -19
  28. package/src/failure-class.ts +47 -0
  29. package/src/fleet.ts +168 -452
  30. package/src/gitops.ts +86 -1
  31. package/src/log.ts +40 -0
  32. package/src/model-fallback.ts +3 -2
  33. package/src/omp-settings.ts +114 -0
  34. package/src/omp.ts +39 -0
  35. package/src/orchestrator-tick.ts +7 -1
  36. package/src/reports.ts +124 -12
  37. package/src/session-host.ts +6 -0
  38. package/src/setup-wizard.ts +36 -0
  39. package/src/setup.ts +58 -1
  40. package/src/status-render.ts +445 -0
  41. package/src/stop-provenance.ts +53 -0
  42. package/src/store.ts +352 -11
  43. package/src/transcript.ts +1 -1
  44. package/src/types.ts +187 -4
  45. package/src/unblock.ts +1 -1
  46. package/src/upgrade-verify.ts +1 -1
  47. package/src/upgrade.ts +1 -2
  48. package/src/verbs/server.ts +25 -0
  49. package/src/worker.ts +358 -10
  50. package/src/worktree.ts +13 -1
package/REFERENCE.md CHANGED
@@ -979,6 +979,41 @@ honour the pattern it says so, and the daemon logs that per run:
979
979
  Worth reading the log for. A run that quietly used a weaker model than you chose
980
980
  otherwise looks like a run that was merely unlucky.
981
981
 
982
+ ## Omp settings overlay
983
+
984
+ `ompSettings` on a project is the fleet-owned channel for saying "this project's
985
+ workers run with *these* omp settings" without editing the daemon account's
986
+ global `~/.omp/agent/config.yml`. The value is an opaque map serialised verbatim
987
+ to a YAML overlay file by the dispatcher, under the run's own session directory
988
+ (never inside the worktree), and threaded to the session through omp's own
989
+ `Settings.init({ configFiles: [<path>] })` seam. Conductor validates YAML shape
990
+ only — omp owns the schema; an unknown key or a wrong-typed value is omp's to
991
+ reject, never conductor's to understand.
992
+
993
+ ```json
994
+ "ompSettings": {
995
+ "retry": {
996
+ "modelFallback": true,
997
+ "fallbackChains": {
998
+ "default": ["openai/gpt-4o-mini", "google/gemini-x"]
999
+ }
1000
+ },
1001
+ "modelRoles": {
1002
+ "worker": "@slow"
1003
+ }
1004
+ }
1005
+ ```
1006
+
1007
+ The overlay is deep-merged **after** the daemon account's global config and any
1008
+ project `<cwd>/.omp/config.yml`, so it layers on top of both without erasing
1009
+ either. A config edit takes effect on the next dispatch (the overlay is
1010
+ rewritten on every attempt), and a project without the field dispatches
1011
+ byte-for-byte as it always has.
1012
+
1013
+ The retry keys derived from `modelFallbacks` are merged into the effective
1014
+ overlay (unless the map already names a `retry` mapping), which is where
1015
+ #539's within-run staging lives.
1016
+
982
1017
  ## Code-graph discovery
983
1018
 
984
1019
  Optional, off unless you answer yes in the wizard, and worth answering yes to for
@@ -1409,7 +1444,38 @@ refused rather than overwriting the first answer.
1409
1444
  anything is open: `decisions 2 open (oldest 26h)`, or `decisions none open`. A
1410
1445
  row that appeared only when something was outstanding would leave "it forgot to
1411
1446
  record the question" and "there genuinely is none" looking identical, which is
1412
- the ambiguity this table exists to remove.
1447
+ the ambiguity this table exists to remove. `decisions N open` counts only rows a
1448
+ human must answer (#459): watches the orchestrator set for itself are reported
1449
+ separately, as `· watches N`, so a fleet waiting on GitHub's checks is never
1450
+ mistaken for a fleet waiting on its operator.
1451
+
1452
+ ### Watches, and the split from questions (#459)
1453
+
1454
+ A front-row sharp edge: the floor's no-sleep rule said "anything that needs
1455
+ waiting for is a watch (`decision open --resolves-when …`)". So the orchestrator
1456
+ opened its own conditions as decision rows — "merge #576 once its checks are
1457
+ green" — and every one of them rendered, counted and expired exactly like a
1458
+ question put to you. `omp-conductor status` reported `decisions 3 open` and the
1459
+ tick prompt listed them under "Open operator decisions … resolve or withdraw",
1460
+ so you reasonably read a self-reminder as an ask aimed at you. The fix is a
1461
+ durable split at the row, never a heuristic over the wording or over whether a
1462
+ condition is attached (a real question may carry one too):
1463
+
1464
+ ```bash
1465
+ omp-conductor watch add --note "merge #576 once its checks are green on the rebased head" \
1466
+ --blocks "#576 merge" --resolves-when pr-checks-green:https://github.com/acme/api/pull/576
1467
+ omp-conductor watch list
1468
+ ```
1469
+
1470
+ A watch is a row `kind: watch` that the orchestrator opened for itself — either
1471
+ a `--resolves-when` condition (the daemon checks it and wakes the next tick when
1472
+ met, exactly as for a question), or a plain carry note the next tick should
1473
+ read. It renders under its own "Watches" heading, is never offered to you to
1474
+ resolve, and has **no seven-day expiry** — that deadline is for a question
1475
+ nobody answered; silently expiring a watch could drop a release the day its
1476
+ condition finally fires. A superseded watch is closed with the ordinary
1477
+ `decision withdraw <id>`. `decision open --resolves-when` still records an
1478
+ operator question: a condition governs *when* to ask, not *who* answers.
1413
1479
 
1414
1480
  ## Failure classes and recovery by class (#132)
1415
1481
 
@@ -2169,6 +2235,8 @@ omp-conductor decision open --question TEXT [--blocks TEXT] [--resolves-when CON
2169
2235
  omp-conductor decision resolve <id> --answer TEXT [--project NAME]
2170
2236
  omp-conductor decision withdraw <id> [--reason TEXT] [--project NAME]
2171
2237
  omp-conductor decision list [--project NAME]
2238
+ omp-conductor watch add --note TEXT [--blocks TEXT] [--resolves-when COND] [--project NAME]
2239
+ omp-conductor watch list [--project NAME]
2172
2240
  omp-conductor daemon [--once] [--port N] [--project NAME]
2173
2241
  omp-conductor resume [--project NAME]
2174
2242
  omp-conductor brief-upgrade [--migrate|--retrofit] [--apply] [--file PATH] [--project NAME]
@@ -2202,7 +2270,9 @@ omp-conductor help
2202
2270
  | `decision open --question TEXT [--blocks TEXT] [--resolves-when COND]` | project | Record a question the orchestrator has put to you, and print its id. A question that lives only in a session's context is lost at the next compaction — after which it is either asked twice or dropped silently. `--resolves-when` attaches a machine-checkable condition: `pr-merged:<https url>`, `pr-checks-green:<https url>`, `pr-mergeable:<https url>`, `issue-closed:<n>`, `npm-version:<pkg>@<version>`, or `rate-limit-reset:github`; anything else exits `2` listing the six forms. See [The decision ledger](#the-decision-ledger-136). |
2203
2271
  | `decision resolve <id> --answer TEXT` | project | Record what you decided. Exits `1` naming the id when it is unknown or no longer open, so a second answer cannot overwrite the first. |
2204
2272
  | `decision withdraw <id> [--reason TEXT]` | project | Close a question the session stopped needing, with why. Same guard as `resolve`. |
2205
- | `decision list` | project | Open questions, oldest first: id, age, what each blocks, whether its condition is met, and the question. Prints `no open decisions` when there are none. |
2273
+ | `decision list` | project | Open questions, oldest first: id, age, what each blocks, whether its condition is met, and the question. Prints `no open decisions` when there are none. Watches are not listed here — `watch list` shows those. |
2274
+ | `watch add --note TEXT [--blocks TEXT] [--resolves-when COND]` | project | Record a condition or carry note the orchestrator set for itself, with no human in the loop (#459). `--resolves-when` attaches a machine-checkable condition the daemon checks for you; a met watch wakes the next tick exactly as a met question does. Renders under its own "Watches" heading, is never counted in `decisions N open`, and has no seven-day expiry. |
2275
+ | `watch list` | project | Open watches, oldest first: id, age, what each blocks, whether its condition is met, and the note. Prints `no watches` when there are none. |
2206
2276
  | `daemon` | host | Run the loop in the **foreground**, ticking every 5 minutes and serving `/healthz`. Admitted workers run in a tracked background pool, so settlement and capacity checks remain periodic while they work; shutdown drains the pool before closing the store. This is what `start` launches and what a systemd unit should call. |
2207
2277
  | `daemon --once` | host | Run a single tick, wait for workers admitted by that tick, and exit. No HTTP server or pidfile — a drill must not register itself as the daemon, or the next reader believes it and the real daemon's in-flight runs get reconciled as orphans. |
2208
2278
  | `--port N` | — | Accepted by `start`, `restart` and `daemon`. Both `--port 9000` and `--port=9000` work; missing or out of range exits `2` rather than falling back to the default, because probing the wrong endpoint is worse than a hard failure. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omp-conductor",
3
- "version": "0.15.13",
3
+ "version": "0.16.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "A 24/7 dispatcher that takes ready GitHub issues to green, mergeable PRs using omp coding sessions, with tiered escalation first to an orchestrator session and then to a human.",
@@ -33,6 +33,7 @@
33
33
  "schema": "bun run src/generate-schema.ts"
34
34
  },
35
35
  "dependencies": {
36
+ "yaml": "^2.9.0",
36
37
  "zod": "^4"
37
38
  },
38
39
  "peerDependencies": {
@@ -94,6 +94,11 @@
94
94
  "additionalProperties": {},
95
95
  "description": "Per-fleet or per-project hard limits"
96
96
  },
97
+ "dbBackupDir": {
98
+ "description": "Absolute directory for restorable conductor.db snapshots; defaults to <stateDir>/backups/db",
99
+ "type": "string",
100
+ "minLength": 1
101
+ },
97
102
  "projects": {
98
103
  "minItems": 1,
99
104
  "type": "array",
@@ -299,6 +304,8 @@
299
304
  "workerModel": {},
300
305
  "modelFallbacks": {},
301
306
  "modelFallbackThreshold": {},
307
+ "ompSettings": {},
308
+ "workerAdvisor": {},
302
309
  "escalation": {
303
310
  "type": "object",
304
311
  "properties": {