@rulvar/cli 1.3.0 → 1.3.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.
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # @rulvar/cli
2
+
3
+ The rulvar ops shell: the `rulvar` binary (`run`, `resume`, `runs`,
4
+ `inspect`, `plan`, `kb`), TUI progress, the embeddable HTTP server with
5
+ SSE events and external-input resolution (`createServer`), the queue
6
+ worker over any leasable store (`createWorker`), and the OpenTelemetry
7
+ exporter (`toOtel`).
8
+
9
+ Part of [rulvar](https://rulvar.com), an embeddable TypeScript engine
10
+ for durable, budget-bounded multi-agent LLM workflows, where a completed
11
+ LLM call is never paid for twice. Full documentation:
12
+ [docs.rulvar.com](https://docs.rulvar.com).
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ pnpm add @rulvar/cli
18
+ pnpm exec rulvar --help
19
+ ```
20
+
21
+ ## Documentation
22
+
23
+ - [CLI](https://docs.rulvar.com/guide/cli)
24
+ - [Observability](https://docs.rulvar.com/guide/observability)
25
+ - [API reference](https://docs.rulvar.com/api/%40rulvar/cli/)
26
+
27
+ ## License
28
+
29
+ [Apache-2.0](https://github.com/o-stepper/rulvar/blob/main/LICENSE)
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { r as runCli, t as processIo } from "./io-DSpNsEKg.js";
2
+ import { r as runCli, t as processIo } from "./io-nATg3Bhx.js";
3
3
  //#region src/cli.ts
4
4
  /**
5
5
  * The `rulvar` bin entry: thin wrapper over runCli with process io.
@@ -60,7 +60,7 @@ function isTerminalPlanStatus(status) {
60
60
  * (never a silent brick).
61
61
  */
62
62
  function assertPlanTransition(node, to) {
63
- if (isTerminalPlanStatus(node.status)) throw new PlanInvariantError(`plan node ${node.nodeId} is terminal '${node.status}' and cannot become '${to}' (docs/07, 3.1: the status machine is closed and 'done' is immutable)`, { data: {
63
+ if (isTerminalPlanStatus(node.status)) throw new PlanInvariantError(`plan node ${node.nodeId} is terminal '${node.status}' and cannot become '${to}' (the status machine is closed and 'done' is immutable)`, { data: {
64
64
  nodeId: node.nodeId,
65
65
  from: node.status,
66
66
  to
@@ -70,7 +70,7 @@ function assertPlanTransition(node, to) {
70
70
  from: node.status,
71
71
  to
72
72
  } });
73
- if (to === "running" && node.status !== "ready") throw new PlanInvariantError(`plan node ${node.nodeId} cannot start running from '${node.status}' (the engine schedules ready nodes only; docs/07, 3.1)`, { data: {
73
+ if (to === "running" && node.status !== "ready") throw new PlanInvariantError(`plan node ${node.nodeId} cannot start running from '${node.status}' (the engine schedules ready nodes only)`, { data: {
74
74
  nodeId: node.nodeId,
75
75
  from: node.status,
76
76
  to
@@ -327,7 +327,7 @@ function effectiveDroppedStreak(state) {
327
327
  }
328
328
  function verifyHash(entry, which, expected, plan, deriverFor) {
329
329
  const actual = planHash(plan, deriverFor?.(entry.hashVersion) ?? deriverV2);
330
- if (actual !== expected) throw new ReplayPlanHashMismatch(`plan fold ${which} mismatch at seq ${String(entry.seq)}: recomputed ${actual}, entry carries ${expected} (hashVersion ${String(entry.hashVersion)}); the resume is rejected without corrupting the journal (docs/07, 3.4)`, { data: {
330
+ if (actual !== expected) throw new ReplayPlanHashMismatch(`plan fold ${which} mismatch at seq ${String(entry.seq)}: recomputed ${actual}, entry carries ${expected} (hashVersion ${String(entry.hashVersion)}); the resume is rejected without corrupting the journal`, { data: {
331
331
  entryRef: entry.seq,
332
332
  expected,
333
333
  actual,
@@ -1251,11 +1251,11 @@ function boundLedgerRender(view, budgetChars = LEDGER_RENDER_BUDGET_CHARS) {
1251
1251
  bounded[section].shift();
1252
1252
  droppedRows += 1;
1253
1253
  }
1254
- if (droppedRows > 0) bounded.discrepancies.push(`renderBudget: dropped the ${String(droppedRows)} oldest ${section} rows (docs/06, Appendix A)`);
1254
+ if (droppedRows > 0) bounded.discrepancies.push(`renderBudget: dropped the ${String(droppedRows)} oldest ${section} rows `);
1255
1255
  if (size(bounded) <= budgetChars) return bounded;
1256
1256
  }
1257
1257
  if (bounded.brief !== void 0 && size(bounded) > budgetChars) {
1258
- bounded.discrepancies.push("renderBudget: the mission brief was sliced (docs/06, Appendix A)");
1258
+ bounded.discrepancies.push("renderBudget: the mission brief was sliced");
1259
1259
  const over = size(bounded) - budgetChars;
1260
1260
  const keep = Math.max(0, bounded.brief.text.length - over);
1261
1261
  bounded.brief = {
@@ -2115,7 +2115,7 @@ function planRunner(options) {
2115
2115
  logicalTaskId,
2116
2116
  isNew: false
2117
2117
  });
2118
- if (!debited.ok) throw new ConfigError("termination_exhausted: maxTotalSpawns reached at a reuse link (docs/07, 11.3)");
2118
+ if (!debited.ok) throw new ConfigError("termination_exhausted: maxTotalSpawns reached at a reuse link");
2119
2119
  decision = {
2120
2120
  verdict: {
2121
2121
  kind: "reuse_full",
@@ -2312,7 +2312,7 @@ function planRunner(options) {
2312
2312
  * against the per-engine registry BEFORE paying for the attempt.
2313
2313
  */
2314
2314
  const ladderDispatchFields = (node, spec, ladder) => {
2315
- for (const gate of ladder.acceptance ?? []) if (gate.kind === "mechanical" && io.gates[gate.profile] === void 0) throw new ConfigError(`mechanical gate profile '${gate.profile}' is not registered under defaults.gates (docs/07, section 10)`);
2315
+ for (const gate of ladder.acceptance ?? []) if (gate.kind === "mechanical" && io.gates[gate.profile] === void 0) throw new ConfigError(`mechanical gate profile '${gate.profile}' is not registered under defaults.gates `);
2316
2316
  const rungIndex = executingRungOf(ladder, clampStartTier(ladder, spec.model_hint?.startTier), requireAccount().rungIndexOf(node.logicalTaskId));
2317
2317
  const rung = ladder.rungs[rungIndex];
2318
2318
  if (rung === void 0) throw new ConfigError(`ladder rung ${String(rungIndex)} is undeclared`);
@@ -3154,10 +3154,10 @@ function planRunner(options) {
3154
3154
  ledgerScope: rootScope,
3155
3155
  planScope
3156
3156
  }), op);
3157
- if (violation !== void 0) throw new ConfigError(`ledger_append rejected: ${violation} (docs/06, Appendix A)`);
3157
+ if (violation !== void 0) throw new ConfigError(`ledger_append rejected: ${violation}`);
3158
3158
  if (op.op === "lesson_add") {
3159
3159
  const stats = io.admission.lineage()?.statsOf(op.key.logicalTaskId);
3160
- if (!(stats !== void 0 && stats.attemptsUsed > 0 && stats.approaches.some((approach) => approach.approachSig === op.key.approachSig))) throw new ConfigError("lesson_add rejected: the key matches no journaled attempt of that logical task (docs/07, 9.2)");
3160
+ if (!(stats !== void 0 && stats.attemptsUsed > 0 && stats.approaches.some((approach) => approach.approachSig === op.key.approachSig))) throw new ConfigError("lesson_add rejected: the key matches no journaled attempt of that logical task ");
3161
3161
  }
3162
3162
  const entry = await io.append({
3163
3163
  scope: rootScope,
@@ -86992,7 +86992,7 @@ var require_eslint_helpers = /* @__PURE__ */ __commonJSMin(((exports, module) =>
86992
86992
  */
86993
86993
  async function globMatch({ basePath, pattern }) {
86994
86994
  let found = false;
86995
- const { hfs } = await import("./src-BA7JP7vn.js");
86995
+ const { hfs } = await import("./src-pbHnkjmy.js");
86996
86996
  const patternToUse = normalizeToPosix(path$9.relative(basePath, pattern));
86997
86997
  const matcher = new Minimatch(patternToUse, MINIMATCH_OPTIONS);
86998
86998
  const walkSettings = {
@@ -87040,7 +87040,7 @@ var require_eslint_helpers = /* @__PURE__ */ __commonJSMin(((exports, module) =>
87040
87040
  return new Minimatch(patternToUse, MINIMATCH_OPTIONS);
87041
87041
  });
87042
87042
  const unmatchedPatterns = /* @__PURE__ */ new Set([...relativeToPatterns.keys()]);
87043
- const { hfs } = await import("./src-BA7JP7vn.js");
87043
+ const { hfs } = await import("./src-pbHnkjmy.js");
87044
87044
  const walk = hfs.walk(basePath, {
87045
87045
  async directoryFilter(entry) {
87046
87046
  if (!matchers.some((matcher) => matcher.match(entry.path, true))) return false;
@@ -94921,7 +94921,7 @@ const duplicateIdenticalCall = {
94921
94921
  meta: {
94922
94922
  type: "suggestion",
94923
94923
  docs: { description: "advisory: byte-identical ctx.agent/ctx.workflow calls in one function forward-match to ONE journal entry; pass opts.key to distinguish deliberate repeats" },
94924
- messages: { duplicateCall: "this call is byte-identical to an earlier one in the same function; identical calls share one journal entry via forward-matching, so a deliberate repeat needs a distinguishing opts.key (docs/03, section 7.3)" },
94924
+ messages: { duplicateCall: "this call is byte-identical to an earlier one in the same function; identical calls share one journal entry via forward-matching, so a deliberate repeat needs a distinguishing opts.key" },
94925
94925
  schema: []
94926
94926
  },
94927
94927
  create(context) {
@@ -95229,7 +95229,7 @@ var WorkerSandboxRunner = class {
95229
95229
  this.workerUrl = options?.workerUrl ?? new URL("./sandbox-worker.js", import.meta.url);
95230
95230
  }
95231
95231
  async execute(wf, ctx, args) {
95232
- if (wf.kind !== "compiled-workflow") throw new ConfigError("WorkerSandboxRunner executes CompiledWorkflow values only; closures run in process (docs/06, section \"Script runners\")");
95232
+ if (wf.kind !== "compiled-workflow") throw new ConfigError("WorkerSandboxRunner executes CompiledWorkflow values only; closures run in process ");
95233
95233
  const argsJson = toJournalValue(args ?? null, "sandbox workflow args");
95234
95234
  const channel = new MessageChannel();
95235
95235
  const worker = new Worker(this.workerUrl, { resourceLimits: { maxOldGenerationSizeMb: this.memoryMb } });
package/dist/index.d.ts CHANGED
@@ -16,7 +16,7 @@ interface CliIo {
16
16
  declare function processIo(): CliIo;
17
17
  //#endregion
18
18
  //#region src/cli-main.d.ts
19
- declare const HELP = "rulvar: durable multi-agent workflows (docs/06, section 10.5)\n\n rulvar run <file|name> [--args JSON] [--store PATH] [--budget-usd N]\n rulvar resume <runId> [--store PATH]\n rulvar runs ls [--store PATH]\n rulvar inspect <runId> [--store PATH]\n rulvar plan \"<goal>\" [--dry-run]\n rulvar kb <list | inbox | sweep>\n\nEngine assembly: adapters, defaults, and the workflow registry come from\nrulvar.config.mjs in the working directory (default export\n{ engineOptions?, workflows? }) or from the workflow module's named\nexports. --store selects the JsonlFileStore directory (default .rulvar).\nplan asks the planner model (role plan) to write a workflow script,\nlints and self-repairs it, then runs it in the worker sandbox; --dry-run\nprints the accepted script without running. Requires @rulvar/planner\ninstalled. kb list shows the per-project claim store\n(./rulvar.models.json) with full provenance. kb sweep runs the\nfalsification matrix from the kbSweep section of rulvar.config.mjs\n(fixed pool UNIONED with every model carrying an active negative claim\nplus the re-measure queue; optional canary probes flip drifted claims\nstale first; requires @rulvar/evals installed). kb inbox arrives with\nModelKnowledge phase 3.";
19
+ declare const HELP = "rulvar: durable multi-agent workflows (https://docs.rulvar.com)\n\n rulvar run <file|name> [--args JSON] [--store PATH] [--budget-usd N]\n rulvar resume <runId> [--store PATH]\n rulvar runs ls [--store PATH]\n rulvar inspect <runId> [--store PATH]\n rulvar plan \"<goal>\" [--dry-run]\n rulvar kb <list | inbox | sweep>\n\nEngine assembly: adapters, defaults, and the workflow registry come from\nrulvar.config.mjs in the working directory (default export\n{ engineOptions?, workflows? }) or from the workflow module's named\nexports. --store selects the JsonlFileStore directory (default .rulvar).\nplan asks the planner model (role plan) to write a workflow script,\nlints and self-repairs it, then runs it in the worker sandbox; --dry-run\nprints the accepted script without running. Requires @rulvar/planner\ninstalled. kb list shows the per-project claim store\n(./rulvar.models.json) with full provenance. kb sweep runs the\nfalsification matrix from the kbSweep section of rulvar.config.mjs\n(fixed pool UNIONED with every model carrying an active negative claim\nplus the re-measure queue; optional canary probes flip drifted claims\nstale first; requires @rulvar/evals installed). kb inbox arrives with\nModelKnowledge phase 3.";
20
20
  declare function runCli(argv: string[], options: {
21
21
  cwd: string;
22
22
  io: CliIo;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as resumeCommand, c as driveRun, d as renderEventLine, f as DEFAULT_STORE_DIR, g as looksLikeFile, h as loadWorkflowModule, i as inspectCommand, l as reportOutcome, m as loadCliConfig, n as HELP, o as runCommand, p as assembleEngine, r as runCli, s as runsLsCommand, t as processIo, u as attachProgress } from "./io-DSpNsEKg.js";
1
+ import { a as resumeCommand, c as driveRun, d as renderEventLine, f as DEFAULT_STORE_DIR, g as looksLikeFile, h as loadWorkflowModule, i as inspectCommand, l as reportOutcome, m as loadCliConfig, n as HELP, o as runCommand, p as assembleEngine, r as runCli, s as runsLsCommand, t as processIo, u as attachProgress } from "./io-nATg3Bhx.js";
2
2
  import { ConfigError, InvalidResolutionError, JournalCompatibilityError, LeaseHeldError, Replayer, RulvarError, buildDeriverRegistry, costReportFromJournal, maskSecrets, normalizeEntry, scanJournalCompatibility, validateSchemaSpec } from "@rulvar/core";
3
3
  //#region src/server.ts
4
4
  /**
@@ -139,7 +139,7 @@ function createServer(options) {
139
139
  const workflow = workflows[name];
140
140
  if (workflow === void 0) return json(400, { error: {
141
141
  code: "config",
142
- message: `no workflow named '${name}' in the registry (docs/06, section 10.4)`
142
+ message: `no workflow named '${name}' in the registry`
143
143
  } });
144
144
  const runOptions = {
145
145
  ...body.options?.runId === void 0 ? {} : { runId: body.options.runId },
@@ -477,8 +477,8 @@ function workerIdentity() {
477
477
  }
478
478
  function createWorker(engine, options) {
479
479
  const store = options.store;
480
- if (!(typeof store.acquire === "function" && typeof store.renew === "function" && typeof store.release === "function")) throw new ConfigError("createWorker requires a LeasableStore (acquire/renew/release with fencing epochs); the supplied store has no lease capability (docs/03, section 12.3). Use @rulvar/store-sqlite or another conformant LeasableStore.");
481
- if (engine.stores.journal !== store) throw new ConfigError("createWorker must lease the SAME journal store the engine writes (engine.stores.journal); leasing a different store would fence nothing (docs/02, section 8.3; docs/06, 10.2)");
480
+ if (!(typeof store.acquire === "function" && typeof store.renew === "function" && typeof store.release === "function")) throw new ConfigError("createWorker requires a LeasableStore (acquire/renew/release with fencing epochs); the supplied store has no lease capability. Use @rulvar/store-sqlite or another conformant LeasableStore.");
481
+ if (engine.stores.journal !== store) throw new ConfigError("createWorker must lease the SAME journal store the engine writes (engine.stores.journal); leasing a different store would fence nothing");
482
482
  const concurrency = options.concurrency ?? 1;
483
483
  if (!Number.isInteger(concurrency) || concurrency < 1) throw new ConfigError(`createWorker concurrency must be a positive integer, got ${concurrency}`);
484
484
  const owner = options.owner ?? workerIdentity();
@@ -373,7 +373,7 @@ async function resumeCommand(argv, context) {
373
373
  if (meta === void 0) throw new ConfigError(`run '${runId}' not found in the store`);
374
374
  const name = meta.workflowName;
375
375
  const workflow = name === void 0 ? void 0 : assembled.workflows[name];
376
- if (workflow === void 0) throw new ConfigError(`run '${runId}' was started from workflow '${name ?? "(unknown)"}'; register it under that name in rulvar.config.mjs workflows to resume (docs/06, section 10.2: resume requires the in-process workflow value)`);
376
+ if (workflow === void 0) throw new ConfigError(`run '${runId}' was started from workflow '${name ?? "(unknown)"}'; register it under that name in rulvar.config.mjs workflows to resume (resume requires the in-process workflow value)`);
377
377
  const first = assembled.engine.resume(runId, workflow, { args });
378
378
  return reportOutcome(await driveRun({
379
379
  engine: assembled.engine,
@@ -456,7 +456,7 @@ async function planCommand(argv, context) {
456
456
  if (goal === void 0 || parsed.positionals.length > 1) throw new ConfigError("usage: rulvar plan \"<goal>\" [--dry-run]");
457
457
  let plannerModule;
458
458
  try {
459
- plannerModule = await import("./dist-Cdj5YBRG.js");
459
+ plannerModule = await import("./dist-hv4J07hq.js");
460
460
  } catch {
461
461
  throw new ConfigError("rulvar plan requires @rulvar/planner (the plan agent, compileScript, and the worker sandbox live there); install it next to the CLI");
462
462
  }
@@ -532,7 +532,7 @@ async function kbInboxCommand(argv, context) {
532
532
  if (flags.positionals.length > 0) throw new ConfigError("usage: rulvar kb inbox [--store PATH]");
533
533
  let plan;
534
534
  try {
535
- plan = await import("./dist-Clz0iBp5.js");
535
+ plan = await import("./dist-DIqBj4U-.js");
536
536
  } catch {
537
537
  throw new ConfigError("rulvar kb inbox requires @rulvar/plan (the RunLedger fold behind the LedgerExport seam)");
538
538
  }
@@ -675,7 +675,7 @@ async function kbGateCommand(argv, context) {
675
675
  ].includes(confidence)) throw new ConfigError(`--confidence must be high, medium or low, got '${String(values.confidence)}'`);
676
676
  let plan;
677
677
  try {
678
- plan = await import("./dist-Clz0iBp5.js");
678
+ plan = await import("./dist-DIqBj4U-.js");
679
679
  } catch {
680
680
  throw new ConfigError("rulvar kb gate requires @rulvar/plan (the RunLedger fold behind the LedgerExport seam)");
681
681
  }
@@ -771,7 +771,7 @@ async function kbSweepCommand(argv, context) {
771
771
  if (argv.length > 0) throw new ConfigError("usage: rulvar kb sweep (configuration lives in rulvar.config.mjs)");
772
772
  const config = await loadCliConfig(context.cwd);
773
773
  const sweep = config.kbSweep;
774
- if (sweep === void 0) throw new ConfigError("rulvar kb sweep requires a kbSweep section in rulvar.config.mjs ({ committerId, models, cases }; docs/05, section 'Grounding and decay')");
774
+ if (sweep === void 0) throw new ConfigError("rulvar kb sweep requires a kbSweep section in rulvar.config.mjs ({ committerId, models, cases })");
775
775
  let evals;
776
776
  try {
777
777
  evals = await import("./dist-M-vPRtBM.js");
@@ -850,7 +850,7 @@ async function kbSweepCommand(argv, context) {
850
850
  * Command dispatch for the canonical grammar (https://docs.rulvar.com/guide/cli):
851
851
  * no aliases in v1; unknown commands and flags fail loudly with usage.
852
852
  */
853
- const HELP = `rulvar: durable multi-agent workflows (docs/06, section 10.5)
853
+ const HELP = `rulvar: durable multi-agent workflows (https://docs.rulvar.com)
854
854
 
855
855
  rulvar run <file|name> [--args JSON] [--store PATH] [--budget-usd N]
856
856
  rulvar resume <runId> [--store PATH]
@@ -1,4 +1,4 @@
1
- import { t as __esmMin } from "./dist-Cdj5YBRG.js";
1
+ import { t as __esmMin } from "./dist-hv4J07hq.js";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import nativeFsp from "node:fs/promises";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/cli",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "rulvar shell: run/resume/runs/inspect/plan/kb commands, TUI progress, createServer, createWorker, OTel exporter.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -22,17 +22,17 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@rulvar/core": "1.3.0"
25
+ "@rulvar/core": "1.3.2"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.20.0",
29
29
  "tsdown": "^0.22.3",
30
30
  "typescript": "~6.0.3",
31
- "@rulvar/testing": "1.3.0",
32
- "@rulvar/store-sqlite": "1.3.0",
33
- "@rulvar/planner": "1.3.0",
34
- "@rulvar/plan": "1.3.0",
35
- "@rulvar/evals": "1.3.0"
31
+ "@rulvar/testing": "1.3.2",
32
+ "@rulvar/planner": "1.3.2",
33
+ "@rulvar/plan": "1.3.2",
34
+ "@rulvar/evals": "1.3.2",
35
+ "@rulvar/store-sqlite": "1.3.2"
36
36
  },
37
37
  "bin": {
38
38
  "rulvar": "./dist/cli.js"