@ours.network/cli 2.0.4 → 2.1.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.
package/README.md CHANGED
@@ -102,11 +102,15 @@ and secret fields already in the file.
102
102
  ours config setup --port 3070 --state-dir /srv/ours-a \
103
103
  --broker-url wss://broker1.ours.network --api-visibility owner
104
104
  ours config setup --gc-interval-ms 3600000
105
+ ours config setup --history-max-bytes 104857600
105
106
  ours config setup --port 3070 --dry-run --json
106
107
  ```
107
108
 
108
- Supported setup fields are `brokerUrl`, `port`, `stateDir`, `gcIntervalMs`, and
109
- `apiVisibility`. Supply credentials through an operator-owned
109
+ Supported setup fields are `brokerUrl`, `port`, `stateDir`, `gcIntervalMs`,
110
+ `historyMaxBytes`, and `apiVisibility`. `historyMaxBytes` is one daemon-wide
111
+ physical cap across every identity's history DB/WAL/SHM and history blob tree;
112
+ it defaults to 104857600 bytes (100 MiB), and `0` disables rotation/unlimits
113
+ history. Supply credentials through an operator-owned
110
114
  secret mechanism or the existing SDK configuration, not CLI arguments.
111
115
 
112
116
  ## Operator commands
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  bootWrapper,
3
3
  wrapperBooted
4
- } from "./chunk-TSYICL3I.js";
5
- import "./chunk-FXKFSNKS.js";
4
+ } from "./chunk-YPDZQ4XD.js";
5
+ import "./chunk-DTWZF3ZG.js";
6
6
  export {
7
7
  bootWrapper,
8
8
  wrapperBooted
@@ -7,7 +7,14 @@ import {
7
7
  // src/config-command.ts
8
8
  import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
9
9
  import { dirname, resolve } from "node:path";
10
- var SAFE_KEYS = /* @__PURE__ */ new Set(["brokerUrl", "port", "stateDir", "gcIntervalMs", "apiVisibility"]);
10
+ var SAFE_KEYS = /* @__PURE__ */ new Set([
11
+ "brokerUrl",
12
+ "port",
13
+ "stateDir",
14
+ "gcIntervalMs",
15
+ "historyMaxBytes",
16
+ "apiVisibility"
17
+ ]);
11
18
  async function showConfig(selection) {
12
19
  const resolved = await resolveSelection(selection);
13
20
  let stored = {};
@@ -4,11 +4,13 @@ import { randomBytes } from "node:crypto";
4
4
  import { homedir } from "node:os";
5
5
  import { resolve, join, dirname, basename } from "node:path";
6
6
  var API_VISIBILITIES = ["owner", "shared", "open"];
7
+ var DEFAULT_HISTORY_MAX_BYTES = 100 * 1024 * 1024;
7
8
  var DEFAULT_CONFIG = {
8
9
  brokerUrl: "wss://broker1.ours.network",
9
10
  port: 3050,
10
11
  stateDir: resolve(homedir(), ".ours"),
11
12
  gcIntervalMs: 36e5,
13
+ historyMaxBytes: DEFAULT_HISTORY_MAX_BYTES,
12
14
  apiVisibility: "owner"
13
15
  };
14
16
  function configPath() {
@@ -34,6 +36,9 @@ function readFileConfig() {
34
36
  if (typeof parsed.gcIntervalMs === "number" && Number.isFinite(parsed.gcIntervalMs)) {
35
37
  out.gcIntervalMs = parsed.gcIntervalMs;
36
38
  }
39
+ if (Object.prototype.hasOwnProperty.call(parsed, "historyMaxBytes")) {
40
+ out.historyMaxBytes = validatedHistoryMaxBytes(parsed.historyMaxBytes, "config historyMaxBytes");
41
+ }
37
42
  if (typeof parsed.apiVisibility === "string" && API_VISIBILITIES.includes(parsed.apiVisibility)) {
38
43
  out.apiVisibility = parsed.apiVisibility;
39
44
  }
@@ -63,6 +68,20 @@ function envInt(name) {
63
68
  const n = parseInt(v, 10);
64
69
  return Number.isNaN(n) ? void 0 : n;
65
70
  }
71
+ function validatedHistoryMaxBytes(value, source) {
72
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
73
+ throw new Error(`${source} must be a non-negative safe integer (0 disables history rotation)`);
74
+ }
75
+ return value;
76
+ }
77
+ function envHistoryMaxBytes() {
78
+ const raw = process.env.OURS_HISTORY_MAX_BYTES;
79
+ if (raw === void 0) return void 0;
80
+ if (!/^[0-9]+$/.test(raw)) {
81
+ throw new Error("OURS_HISTORY_MAX_BYTES must be a non-negative safe integer (0 disables history rotation)");
82
+ }
83
+ return validatedHistoryMaxBytes(Number(raw), "OURS_HISTORY_MAX_BYTES");
84
+ }
66
85
  function loadConfig() {
67
86
  const file = readFileConfig();
68
87
  return {
@@ -70,6 +89,7 @@ function loadConfig() {
70
89
  port: envInt("OURS_PORT") ?? file.port ?? DEFAULT_CONFIG.port,
71
90
  stateDir: resolve(process.env.OURS_STATE_DIR ?? file.stateDir ?? DEFAULT_CONFIG.stateDir),
72
91
  gcIntervalMs: envInt("OURS_GC_INTERVAL_MS") ?? file.gcIntervalMs ?? DEFAULT_CONFIG.gcIntervalMs,
92
+ historyMaxBytes: envHistoryMaxBytes() ?? file.historyMaxBytes ?? DEFAULT_CONFIG.historyMaxBytes,
73
93
  apiVisibility: envVisibility() ?? file.apiVisibility ?? DEFAULT_CONFIG.apiVisibility,
74
94
  apiToken: process.env.OURS_API_TOKEN?.trim() || file.apiToken,
75
95
  stt: sttFromEnv(file.stt)
@@ -141,7 +161,14 @@ function writeIdentityFile(target, opts, overwrite = false) {
141
161
  }
142
162
 
143
163
  // ../../src/runtime/config-drift.ts
144
- var FROZEN_ENV = ["OURS_STATE_DIR", "OURS_BROKER_URL", "OURS_PORT", "OURS_API_VISIBILITY", "OURS_CONFIG"];
164
+ var FROZEN_ENV = [
165
+ "OURS_STATE_DIR",
166
+ "OURS_BROKER_URL",
167
+ "OURS_PORT",
168
+ "OURS_API_VISIBILITY",
169
+ "OURS_HISTORY_MAX_BYTES",
170
+ "OURS_CONFIG"
171
+ ];
145
172
  var envAtLoad = Object.fromEntries(
146
173
  FROZEN_ENV.map((k) => [k, process.env[k]])
147
174
  );
@@ -74,7 +74,7 @@ var COMMAND_GROUPS = {
74
74
  handler: "setup",
75
75
  summary: "Write one or more safe daemon settings noninteractively.",
76
76
  effects: "Writes a mode-0600 JSON config unless --dry-run is used. Unknown and secret fields already present are preserved and never printed.",
77
- example: "ours config setup --port 3070 --state-dir /srv/ours-a --api-visibility owner"
77
+ example: "ours config setup --port 3070 --state-dir /srv/ours-a --history-max-bytes 104857600 --api-visibility owner"
78
78
  }
79
79
  }
80
80
  },
@@ -13,7 +13,7 @@ import {
13
13
  IDENTITY_PREBIND_EXCEPTIONS,
14
14
  commandSpec,
15
15
  isCommandGroup
16
- } from "./chunk-QKDH6CJR.js";
16
+ } from "./chunk-GQHDQR6I.js";
17
17
 
18
18
  // src/help.ts
19
19
  var pad = (value, width = 32) => value.length >= width ? `${value} ` : value.padEnd(width);
@@ -127,6 +127,7 @@ function nativeConfigOptions(action) {
127
127
  ["--identity NAME", "Compatibility-only/ignored by config commands."],
128
128
  ["--broker-url URL", show ? "Compatibility-only/ignored by config show." : "Set the broker WebSocket URL."],
129
129
  ["--gc-interval-ms N", show ? "Compatibility-only/ignored by config show." : "Set a positive garbage-collection interval in milliseconds."],
130
+ ["--history-max-bytes N", show ? "Compatibility-only/ignored by config show." : "Set the daemon-wide physical history cap (default 104857600; 0 disables rotation)."],
130
131
  ["--api-visibility MODE", show ? "Compatibility-only/ignored by config show." : "Set owner, shared, or open API visibility."],
131
132
  ["--dry-run", show ? "Compatibility-only/ignored by config show." : "Return the merged redacted result without writing the file."],
132
133
  ["--json", "Write one JSON value to stdout."],
@@ -99,7 +99,7 @@ function childEnvironment(selection) {
99
99
  async function serveDaemon(selection, managed = false) {
100
100
  if (selection.endpoint !== void 0) throw new Error("--endpoint selects a running daemon and cannot be used with daemon serve");
101
101
  Object.assign(process.env, childEnvironment(selection));
102
- const { startDaemon } = await import("./daemon-LTJHJDWZ.js");
102
+ const { startDaemon } = await import("./daemon-5UZIR37V.js");
103
103
  const handle = await startDaemon();
104
104
  if (managed) {
105
105
  const response = await fetch(`http://127.0.0.1:${handle.port}/state-dir`);