omp-conductor 0.13.0 → 0.15.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.
Files changed (44) hide show
  1. package/README.md +549 -234
  2. package/package.json +8 -5
  3. package/schema/config.schema.json +609 -0
  4. package/src/availability.ts +165 -0
  5. package/src/board.ts +19 -32
  6. package/src/brief-upgrade.ts +1 -1
  7. package/src/briefs/orchestrator.md +72 -31
  8. package/src/briefs/policy.md +48 -36
  9. package/src/briefs/probes/gates.md +51 -0
  10. package/src/briefs/probes/project-context.md +59 -0
  11. package/src/briefs/probes/release-procedure.md +81 -0
  12. package/src/cli.ts +356 -212
  13. package/src/config-schema.ts +352 -0
  14. package/src/config.ts +1037 -679
  15. package/src/confinement.ts +54 -0
  16. package/src/daemon.ts +644 -390
  17. package/src/diff-flags.ts +73 -4
  18. package/src/digest-schedule.ts +92 -24
  19. package/src/escalate.ts +89 -22
  20. package/src/fleet.ts +351 -46
  21. package/src/generate-schema.ts +21 -0
  22. package/src/graph.ts +3 -3
  23. package/src/host.ts +16 -0
  24. package/src/omp.ts +21 -1
  25. package/src/orchestrator-tick.ts +732 -56
  26. package/src/privileged.ts +264 -0
  27. package/src/reports.ts +203 -6
  28. package/src/session-host.ts +3 -0
  29. package/src/setup-host.ts +209 -24
  30. package/src/setup-install.ts +320 -0
  31. package/src/setup-probe.ts +412 -0
  32. package/src/setup-wizard.ts +1946 -0
  33. package/src/setup.ts +457 -53
  34. package/src/store.ts +610 -98
  35. package/src/tracker/github.ts +43 -5
  36. package/src/types.ts +153 -14
  37. package/src/upgrade.ts +44 -10
  38. package/src/verbs/actions.ts +131 -13
  39. package/src/verbs/server.ts +40 -18
  40. package/src/wizard-ui.ts +249 -0
  41. package/src/worker.ts +24 -7
  42. package/skills/conductor-onboarding/SKILL.md +0 -748
  43. package/skills/conductor-update/SKILL.md +0 -51
  44. package/src/plugin.ts +0 -1495
package/src/graph.ts CHANGED
@@ -214,7 +214,7 @@ export function reindexScript(p: ProjectConfig): string {
214
214
  "#!/usr/bin/env bash",
215
215
  `# Refresh and reindex the code graphs for omp-conductor project "${p.name}".`,
216
216
  "#",
217
- "# Generated by \`omp-conductor graph-setup\`. Regenerate it rather than editing:",
217
+ "# Generated by \`omp-conductor setup graph\`. Regenerate it rather than editing:",
218
218
  "# the repo list, branches and paths all come from that project's config.json.",
219
219
  "#",
220
220
  "# Every clone below is conductor's own, index-only and never edited by a human,",
@@ -437,7 +437,7 @@ export function formatGraphSetup(
437
437
  const script = reindexScriptPath();
438
438
  const { service, timer } = unitPaths(stateDir());
439
439
  lines.push(
440
- ` \`graph-setup --write\` writes these three files for you, all under`,
440
+ ` \`omp-conductor setup graph\` writes these three files for you, all under`,
441
441
  ` ${stateDir()}. Run it as the account the fleet runs as — never under`,
442
442
  " sudo, which would resolve the config, the state directory and the unit's",
443
443
  " own User= as root and quietly build indexes no worker can read.",
@@ -453,7 +453,7 @@ export function formatGraphSetup(
453
453
  return lines.join("\n");
454
454
  }
455
455
 
456
- /** What `graph-setup --write` did, and the root-only steps it deliberately left. */
456
+ /** What staging wrote, and the root-only steps it deliberately left. */
457
457
  export interface GraphSetupWrite {
458
458
  written: string[];
459
459
  next: string;
package/src/host.ts CHANGED
@@ -62,6 +62,22 @@ export function recommendedMaxWorkers(ramBytes: number | undefined): number {
62
62
  return ramBytes < SMALL_HOST_RAM_BYTES ? 1 : DEFAULT_CAPS.maxConcurrentWorkers;
63
63
  }
64
64
 
65
+ /**
66
+ * Warning shown when all configured projects can outgrow this host together.
67
+ *
68
+ * Omitting `ram` probes the host. Passing `undefined` explicitly means "RAM is
69
+ * unknown" and must NOT fall through to a host probe — a default parameter would
70
+ * treat that `undefined` as "use the default", which is how CI on a small box
71
+ * made `workerOvercommit(2, undefined)` warn about capacity 1.
72
+ */
73
+ export function workerOvercommit(total: number, ram?: number | undefined): string | undefined {
74
+ const effective = arguments.length < 2 ? hostRamBytes() : ram;
75
+ const recommended = recommendedMaxWorkers(effective);
76
+ return total > recommended
77
+ ? `Configured worker capacity ${total} exceeds this host's recommended maximum of ${recommended}.`
78
+ : undefined;
79
+ }
80
+
65
81
  /** Compact binary units for status lines (`3.2 GB`, `430 MB`). */
66
82
  export function formatRss(bytes: number): string {
67
83
  if (!Number.isFinite(bytes) || bytes < 0) return "?";
package/src/omp.ts CHANGED
@@ -18,7 +18,7 @@ import { createServer, type Server, type Socket } from "node:net";
18
18
  import { tmpdir } from "node:os";
19
19
  import { dirname, join } from "node:path";
20
20
 
21
- import { worktreeConfinement } from "./confinement.ts";
21
+ import { readOnlySession, worktreeConfinement } from "./confinement.ts";
22
22
  import { releasePolicyTripwire, type ReleaseBlockContext } from "./release-policy.ts";
23
23
  import type {
24
24
  HostToParent,
@@ -168,6 +168,15 @@ export async function createLocalSession(opts: {
168
168
  * leave the model to improvise `git push` instead.
169
169
  */
170
170
  verbSocketPath?: string;
171
+ /**
172
+ * Deny every tool but reading and searching (#307).
173
+ *
174
+ * For sessions asked to *read* a repository and answer a question — the setup
175
+ * probes. Distinct from {@link worktreeConfinement}, which scopes where writes
176
+ * may land: this removes the shell, the editors and the verbs entirely, so the
177
+ * session has no route to a mutation to scope in the first place.
178
+ */
179
+ readOnly?: boolean;
171
180
  }): Promise<AgentSessionLike> {
172
181
  let loaded: unknown;
173
182
  try {
@@ -205,6 +214,9 @@ export async function createLocalSession(opts: {
205
214
  // transcript is the only record of what the worker actually did.
206
215
  const sessionManager = await openSessionManager(mod, opts);
207
216
  const extensions = [
217
+ // Read-only sessions get the deny-by-default gate *first*, so an unknown tool
218
+ // is refused before any later extension can form an opinion about it.
219
+ ...(opts.readOnly === true ? [readOnlySession()] : []),
208
220
  // Workers only. The orchestrator runs unconfined by operator ruling
209
221
  // (#143): the gate could only ever be installed in sessions this daemon
210
222
  // spawns, so an external orchestrator — the supported shape — never had it,
@@ -430,6 +442,13 @@ export interface CreateSessionOptions {
430
442
  * without a live harness or a model bill.
431
443
  */
432
444
  hostModule?: string;
445
+ /**
446
+ * Deny every tool but reading and searching (#307).
447
+ *
448
+ * Forwarded to the child, because that is where the session — and therefore the
449
+ * gate — actually lives.
450
+ */
451
+ readOnly?: boolean;
433
452
  }
434
453
 
435
454
  /**
@@ -499,6 +518,7 @@ export async function createSession(opts: CreateSessionOptions): Promise<AgentSe
499
518
  ...(opts.resume === undefined ? {} : { resume: opts.resume }),
500
519
  ...(opts.releaseGrants === undefined ? {} : { releaseGrants: opts.releaseGrants }),
501
520
  ...(opts.verbSocketPath === undefined ? {} : { verbSocketPath: opts.verbSocketPath }),
521
+ ...(opts.readOnly === undefined ? {} : { readOnly: opts.readOnly }),
502
522
  };
503
523
 
504
524
  const log = opts.onChildLog ?? ((line: string) => process.stderr.write(`${line}\n`));