brainjar 0.3.1220 → 0.3.1222

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 (2) hide show
  1. package/brainjar.js +173 -137
  2. package/package.json +1 -1
package/brainjar.js CHANGED
@@ -107,7 +107,7 @@ var CLI_VERSION, CACHE, DAY;
107
107
  var init_version_check = __esm({
108
108
  "packages/cli/src/version-check.ts"() {
109
109
  "use strict";
110
- CLI_VERSION = "0.3.1220";
110
+ CLI_VERSION = "0.3.1222";
111
111
  CACHE = path.join(os.homedir(), ".brainjar", "version-check.json");
112
112
  DAY = 864e5;
113
113
  }
@@ -558,9 +558,9 @@ var require_postgres_date = __commonJS({
558
558
  if (type === "Z") {
559
559
  return 0;
560
560
  }
561
- var sign = type === "-" ? -1 : 1;
561
+ var sign2 = type === "-" ? -1 : 1;
562
562
  var offset = parseInt(zone[2], 10) * 3600 + parseInt(zone[3] || 0, 10) * 60 + parseInt(zone[4] || 0, 10);
563
- return offset * sign * 1e3;
563
+ return offset * sign2 * 1e3;
564
564
  }
565
565
  function bcYearToNegativeYear(year) {
566
566
  return -(year - 1);
@@ -925,11 +925,11 @@ var require_pg_int8 = __commonJS({
925
925
  function readInt8(buffer) {
926
926
  var high = buffer.readInt32BE(0);
927
927
  var low = buffer.readUInt32BE(4);
928
- var sign = "";
928
+ var sign2 = "";
929
929
  if (high < 0) {
930
930
  high = ~high + (low === 0);
931
931
  low = ~low + 1 >>> 0;
932
- sign = "-";
932
+ sign2 = "-";
933
933
  }
934
934
  var result = "";
935
935
  var carry;
@@ -945,7 +945,7 @@ var require_pg_int8 = __commonJS({
945
945
  low = t / BASE >>> 0;
946
946
  digits = "" + (t - BASE * low);
947
947
  if (low === 0 && high === 0) {
948
- return sign + digits + result;
948
+ return sign2 + digits + result;
949
949
  }
950
950
  pad = "";
951
951
  l = 6 - digits.length;
@@ -961,7 +961,7 @@ var require_pg_int8 = __commonJS({
961
961
  low = t / BASE >>> 0;
962
962
  digits = "" + (t - BASE * low);
963
963
  if (low === 0 && high === 0) {
964
- return sign + digits + result;
964
+ return sign2 + digits + result;
965
965
  }
966
966
  pad = "";
967
967
  l = 6 - digits.length;
@@ -977,7 +977,7 @@ var require_pg_int8 = __commonJS({
977
977
  low = t / BASE >>> 0;
978
978
  digits = "" + (t - BASE * low);
979
979
  if (low === 0 && high === 0) {
980
- return sign + digits + result;
980
+ return sign2 + digits + result;
981
981
  }
982
982
  pad = "";
983
983
  l = 6 - digits.length;
@@ -990,7 +990,7 @@ var require_pg_int8 = __commonJS({
990
990
  carry = high % BASE;
991
991
  t = 4294967296 * carry + low;
992
992
  digits = "" + t % BASE;
993
- return sign + digits + result;
993
+ return sign2 + digits + result;
994
994
  }
995
995
  }
996
996
  module.exports = readInt8;
@@ -1039,7 +1039,7 @@ var require_binaryParsers = __commonJS({
1039
1039
  };
1040
1040
  var parseFloatFromBits = function(data, precisionBits, exponentBits) {
1041
1041
  var bias = Math.pow(2, exponentBits - 1) - 1;
1042
- var sign = parseBits(data, 1);
1042
+ var sign2 = parseBits(data, 1);
1043
1043
  var exponent = parseBits(data, exponentBits, 1);
1044
1044
  if (exponent === 0) {
1045
1045
  return 0;
@@ -1060,11 +1060,11 @@ var require_binaryParsers = __commonJS({
1060
1060
  var mantissa = parseBits(data, precisionBits, exponentBits + 1, false, parsePrecisionBits);
1061
1061
  if (exponent == Math.pow(2, exponentBits + 1) - 1) {
1062
1062
  if (mantissa === 0) {
1063
- return sign === 0 ? Infinity : -Infinity;
1063
+ return sign2 === 0 ? Infinity : -Infinity;
1064
1064
  }
1065
1065
  return NaN;
1066
1066
  }
1067
- return (sign === 0 ? 1 : -1) * Math.pow(2, exponent - bias) * mantissa;
1067
+ return (sign2 === 0 ? 1 : -1) * Math.pow(2, exponent - bias) * mantissa;
1068
1068
  };
1069
1069
  var parseInt16 = function(value) {
1070
1070
  if (parseBits(value, 1) == 1) {
@@ -1085,8 +1085,8 @@ var require_binaryParsers = __commonJS({
1085
1085
  return parseFloatFromBits(value, 52, 11);
1086
1086
  };
1087
1087
  var parseNumeric = function(value) {
1088
- var sign = parseBits(value, 16, 32);
1089
- if (sign == 49152) {
1088
+ var sign2 = parseBits(value, 16, 32);
1089
+ if (sign2 == 49152) {
1090
1090
  return NaN;
1091
1091
  }
1092
1092
  var weight = Math.pow(1e4, parseBits(value, 16, 16));
@@ -1098,12 +1098,12 @@ var require_binaryParsers = __commonJS({
1098
1098
  weight /= 1e4;
1099
1099
  }
1100
1100
  var scale = Math.pow(10, parseBits(value, 16, 48));
1101
- return (sign === 0 ? 1 : -1) * Math.round(result * scale) / scale;
1101
+ return (sign2 === 0 ? 1 : -1) * Math.round(result * scale) / scale;
1102
1102
  };
1103
1103
  var parseDate = function(isUTC, value) {
1104
- var sign = parseBits(value, 1);
1104
+ var sign2 = parseBits(value, 1);
1105
1105
  var rawValue = parseBits(value, 63, 1);
1106
- var result = new Date((sign === 0 ? 1 : -1) * rawValue / 1e3 + 9466848e5);
1106
+ var result = new Date((sign2 === 0 ? 1 : -1) * rawValue / 1e3 + 9466848e5);
1107
1107
  if (!isUTC) {
1108
1108
  result.setTime(result.getTime() + result.getTimezoneOffset() * 6e4);
1109
1109
  }
@@ -5895,6 +5895,9 @@ function loadEnv() {
5895
5895
  }
5896
5896
  return { ...cachedFileVars, ...process.env };
5897
5897
  }
5898
+ function environmentOf(env = loadEnv()) {
5899
+ return env.ENVIRONMENT?.trim().toLowerCase() === "saas" ? "saas" : "local";
5900
+ }
5898
5901
  function recommendedRoute(task, keys) {
5899
5902
  return task.recommended.find(
5900
5903
  (r) => r.provider === "openai" ? keys.hasOpenaiKey : keys.hasAnthropicKey
@@ -6067,7 +6070,7 @@ var init_config = __esm({
6067
6070
  #env;
6068
6071
  constructor(env) {
6069
6072
  this.#env = env;
6070
- this.environment = env.ENVIRONMENT?.trim().toLowerCase() === "saas" ? "saas" : "local";
6073
+ this.environment = environmentOf(env);
6071
6074
  if (this.environment === "saas") {
6072
6075
  const url = env.BRAINJAR_SAAS_DATABASE_URL?.trim();
6073
6076
  if (!url) {
@@ -6401,6 +6404,154 @@ var init_audit_origin = __esm({
6401
6404
  }
6402
6405
  });
6403
6406
 
6407
+ // packages/db/src/settings.ts
6408
+ function isAppSettingKey(k) {
6409
+ return APP_SETTING_KEYS.includes(k);
6410
+ }
6411
+ async function getAppSettings(pool2 = getPool()) {
6412
+ const rows = (await pool2.query(
6413
+ "SELECT key, value FROM app_setting"
6414
+ )).rows;
6415
+ const out = {};
6416
+ for (const r of rows) if (isAppSettingKey(r.key)) out[r.key] = r.value;
6417
+ return out;
6418
+ }
6419
+ async function swapAppSetting(key, value, pool2 = getPool()) {
6420
+ const r = await pool2.query(
6421
+ `INSERT INTO app_setting (key, value) VALUES ($1, $2)
6422
+ ON CONFLICT (tenant_id, key) DO UPDATE SET value = EXCLUDED.value, updated_at = now()
6423
+ WHERE app_setting.value IS DISTINCT FROM EXCLUDED.value
6424
+ RETURNING 1`,
6425
+ [key, value]
6426
+ );
6427
+ return (r.rowCount ?? 0) > 0;
6428
+ }
6429
+ async function resolveSetting(key, envValue, pool2 = getPool()) {
6430
+ const fromEnv = envValue?.trim();
6431
+ if (fromEnv) return fromEnv;
6432
+ try {
6433
+ return (await getAppSettings(pool2))[key];
6434
+ } catch {
6435
+ return void 0;
6436
+ }
6437
+ }
6438
+ async function resolveModelChoice(workload, envPin, pool2 = getPool()) {
6439
+ const pin = envPin?.trim();
6440
+ if (pin) return pin;
6441
+ const task = aiTaskOf(workload);
6442
+ if (!task) return void 0;
6443
+ return (await resolveSetting(`model_${task.key}`, void 0, pool2))?.trim() || void 0;
6444
+ }
6445
+ async function resolveProviderApiKey(provider, envKey, pool2 = getPool()) {
6446
+ const fromEnv = envKey?.trim();
6447
+ if (fromEnv) return fromEnv;
6448
+ try {
6449
+ const r = await pool2.query(
6450
+ "SELECT value FROM app_setting WHERE key = $1",
6451
+ [PROVIDER_KEY_SETTINGS[provider]]
6452
+ );
6453
+ return r.rows[0]?.value?.trim() || null;
6454
+ } catch {
6455
+ return null;
6456
+ }
6457
+ }
6458
+ var APP_SETTING_KEYS, PROVIDER_KEY_SETTINGS;
6459
+ var init_settings = __esm({
6460
+ "packages/db/src/settings.ts"() {
6461
+ "use strict";
6462
+ init_src();
6463
+ init_pool();
6464
+ APP_SETTING_KEYS = [
6465
+ "capture_mode",
6466
+ // transcript privacy: full | distilled | off
6467
+ // The model per AI task (AI_TASKS, 2026-09-25); empty or absent = Recommended.
6468
+ "model_doku",
6469
+ "model_ask",
6470
+ "model_verify",
6471
+ "model_deepscan",
6472
+ "model_extraction",
6473
+ "public_url",
6474
+ // this server's address as clients reach it (wizard command, MCP config)
6475
+ // Outgoing mail (BJ-103); the password is a secret and lives next to the provider keys.
6476
+ "smtp_host",
6477
+ "smtp_port",
6478
+ "smtp_user",
6479
+ "smtp_secure",
6480
+ // "1" = TLS from the start (465), else STARTTLS (587)
6481
+ "mail_from",
6482
+ // Sign in with a provider (BJ-112); the client secrets are secrets, see below.
6483
+ "google_client_id",
6484
+ "github_client_id",
6485
+ // The emergency brake on new accounts (2026-09-26): "true" pauses every sign-up path.
6486
+ "signups_paused",
6487
+ // The legal pages the signup checkbox links to (BJ-113).
6488
+ "terms_url",
6489
+ "privacy_url",
6490
+ // Voice chat (voice handoff, 2026-09-21): an explicit "true" or "false"; absent means on.
6491
+ "voice_enabled",
6492
+ // The GPT-Live voice (voice picker, 2026-09-22): an id from VOICE_OPTIONS; absent = default.
6493
+ "voice_name",
6494
+ // AI cost cap (BJ-139), set on the Operator page; env overrides, defaults in ingest/allowance.
6495
+ "ai_contingent",
6496
+ // "on" | "off": monthly contingent per workspace (default on in SaaS)
6497
+ "ai_free_monthly_usd",
6498
+ // Free workspace, USD per month
6499
+ "ai_team_seat_monthly_usd",
6500
+ // Team, USD per seat and month (applies once licenses exist)
6501
+ "ai_operator_exempt",
6502
+ // "true" | "false": operator accounts are never capped
6503
+ "ai_daily_budget_usd",
6504
+ // the instance's emergency brake on the company key; empty = off
6505
+ "ai_budget_released_day",
6506
+ // YYYY-MM-DD the operator lifted today's brake
6507
+ "ai_budget_alerted_day",
6508
+ // YYYY-MM-DD the operator was told the brake tripped
6509
+ // Health alarms (BJ-143): the thresholds on the Operator page; empty = default, "0" = off.
6510
+ "alert_queue_minutes",
6511
+ // a runnable job waited longer than this
6512
+ "alert_failure_percent",
6513
+ // share of the last hour's finished jobs that failed
6514
+ "alert_budget_percent",
6515
+ // share of the daily AI budget spent
6516
+ "alert_provider_percent",
6517
+ // a provider limit has less than this share left
6518
+ // The self-host license token (BJ-132), pasted on Operator > Plan; BRAINJAR_LICENSE_TOKEN
6519
+ // overrides. Signed, so it is checked on every read, never trusted as stored.
6520
+ "license_token"
6521
+ ];
6522
+ PROVIDER_KEY_SETTINGS = {
6523
+ anthropic: "anthropic_api_key",
6524
+ openai: "openai_api_key"
6525
+ };
6526
+ }
6527
+ });
6528
+
6529
+ // packages/db/src/license-key.ts
6530
+ var LICENSE_PUBLIC_KEY;
6531
+ var init_license_key = __esm({
6532
+ "packages/db/src/license-key.ts"() {
6533
+ "use strict";
6534
+ LICENSE_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
6535
+ MCowBQYDK2VwAyEAKOUWx/Qgav+dKg78fIlckGby22CRKeuMWR5tkT1rYuw=
6536
+ -----END PUBLIC KEY-----
6537
+ `;
6538
+ }
6539
+ });
6540
+
6541
+ // packages/db/src/plan.ts
6542
+ import { createPublicKey, sign, verify } from "node:crypto";
6543
+ var trustedKeys;
6544
+ var init_plan = __esm({
6545
+ "packages/db/src/plan.ts"() {
6546
+ "use strict";
6547
+ init_src();
6548
+ init_pool();
6549
+ init_settings();
6550
+ init_license_key();
6551
+ trustedKeys = [createPublicKey(LICENSE_PUBLIC_KEY)];
6552
+ }
6553
+ });
6554
+
6404
6555
  // packages/db/src/repository.ts
6405
6556
  async function getBrain(id, pool2 = getPool()) {
6406
6557
  return (await pool2.query("SELECT * FROM brain WHERE id = $1", [id])).rows[0] ?? null;
@@ -6416,6 +6567,7 @@ var init_repository = __esm({
6416
6567
  init_pool();
6417
6568
  init_audit_origin();
6418
6569
  init_vector();
6570
+ init_plan();
6419
6571
  MO_COLUMNS = "id, brain_id, type, title, body, why, status, confidence, version, created_by, verified_by, created_at, occurred_at, updated_at, last_verified_at";
6420
6572
  MO_COLUMNS_MO = MO_COLUMNS.split(", ").map((c) => `mo.${c}`).join(", ");
6421
6573
  evAgg = (ref) => `(SELECT count(*)::int FROM evidence_link ev WHERE ev.memory_object_id = ${ref}.id) AS evidence_count, (SELECT bool_or(ev.artifact_uri IS NOT NULL AND ev.artifact_uri <> '') FROM evidence_link ev WHERE ev.memory_object_id = ${ref}.id) AS evidence_uri`;
@@ -7808,6 +7960,7 @@ var init_auth = __esm({
7808
7960
  "use strict";
7809
7961
  init_src();
7810
7962
  init_pool();
7963
+ init_plan();
7811
7964
  init_ratelimit();
7812
7965
  init_auth_event();
7813
7966
  init_email_token();
@@ -7877,6 +8030,7 @@ var init_team = __esm({
7877
8030
  "use strict";
7878
8031
  init_pool();
7879
8032
  init_auth();
8033
+ init_plan();
7880
8034
  }
7881
8035
  });
7882
8036
 
@@ -7890,125 +8044,6 @@ var init_rbac = __esm({
7890
8044
  }
7891
8045
  });
7892
8046
 
7893
- // packages/db/src/settings.ts
7894
- function isAppSettingKey(k) {
7895
- return APP_SETTING_KEYS.includes(k);
7896
- }
7897
- async function getAppSettings(pool2 = getPool()) {
7898
- const rows = (await pool2.query(
7899
- "SELECT key, value FROM app_setting"
7900
- )).rows;
7901
- const out = {};
7902
- for (const r of rows) if (isAppSettingKey(r.key)) out[r.key] = r.value;
7903
- return out;
7904
- }
7905
- async function swapAppSetting(key, value, pool2 = getPool()) {
7906
- const r = await pool2.query(
7907
- `INSERT INTO app_setting (key, value) VALUES ($1, $2)
7908
- ON CONFLICT (tenant_id, key) DO UPDATE SET value = EXCLUDED.value, updated_at = now()
7909
- WHERE app_setting.value IS DISTINCT FROM EXCLUDED.value
7910
- RETURNING 1`,
7911
- [key, value]
7912
- );
7913
- return (r.rowCount ?? 0) > 0;
7914
- }
7915
- async function resolveSetting(key, envValue, pool2 = getPool()) {
7916
- const fromEnv = envValue?.trim();
7917
- if (fromEnv) return fromEnv;
7918
- try {
7919
- return (await getAppSettings(pool2))[key];
7920
- } catch {
7921
- return void 0;
7922
- }
7923
- }
7924
- async function resolveModelChoice(workload, envPin, pool2 = getPool()) {
7925
- const pin = envPin?.trim();
7926
- if (pin) return pin;
7927
- const task = aiTaskOf(workload);
7928
- if (!task) return void 0;
7929
- return (await resolveSetting(`model_${task.key}`, void 0, pool2))?.trim() || void 0;
7930
- }
7931
- async function resolveProviderApiKey(provider, envKey, pool2 = getPool()) {
7932
- const fromEnv = envKey?.trim();
7933
- if (fromEnv) return fromEnv;
7934
- try {
7935
- const r = await pool2.query(
7936
- "SELECT value FROM app_setting WHERE key = $1",
7937
- [PROVIDER_KEY_SETTINGS[provider]]
7938
- );
7939
- return r.rows[0]?.value?.trim() || null;
7940
- } catch {
7941
- return null;
7942
- }
7943
- }
7944
- var APP_SETTING_KEYS, PROVIDER_KEY_SETTINGS;
7945
- var init_settings = __esm({
7946
- "packages/db/src/settings.ts"() {
7947
- "use strict";
7948
- init_src();
7949
- init_pool();
7950
- APP_SETTING_KEYS = [
7951
- "capture_mode",
7952
- // transcript privacy: full | distilled | off
7953
- // The model per AI task (AI_TASKS, 2026-09-25); empty or absent = Recommended.
7954
- "model_doku",
7955
- "model_ask",
7956
- "model_verify",
7957
- "model_deepscan",
7958
- "model_extraction",
7959
- "public_url",
7960
- // this server's address as clients reach it (wizard command, MCP config)
7961
- // Outgoing mail (BJ-103); the password is a secret and lives next to the provider keys.
7962
- "smtp_host",
7963
- "smtp_port",
7964
- "smtp_user",
7965
- "smtp_secure",
7966
- // "1" = TLS from the start (465), else STARTTLS (587)
7967
- "mail_from",
7968
- // Sign in with a provider (BJ-112); the client secrets are secrets, see below.
7969
- "google_client_id",
7970
- "github_client_id",
7971
- // The emergency brake on new accounts (2026-09-26): "true" pauses every sign-up path.
7972
- "signups_paused",
7973
- // The legal pages the signup checkbox links to (BJ-113).
7974
- "terms_url",
7975
- "privacy_url",
7976
- // Voice chat (voice handoff, 2026-09-21): an explicit "true" or "false"; absent means on.
7977
- "voice_enabled",
7978
- // The GPT-Live voice (voice picker, 2026-09-22): an id from VOICE_OPTIONS; absent = default.
7979
- "voice_name",
7980
- // AI cost cap (BJ-139), set on the Operator page; env overrides, defaults in ingest/allowance.
7981
- "ai_contingent",
7982
- // "on" | "off": monthly contingent per workspace (default on in SaaS)
7983
- "ai_free_monthly_usd",
7984
- // Free workspace, USD per month
7985
- "ai_team_seat_monthly_usd",
7986
- // Team, USD per seat and month (applies once licenses exist)
7987
- "ai_operator_exempt",
7988
- // "true" | "false": operator accounts are never capped
7989
- "ai_daily_budget_usd",
7990
- // the instance's emergency brake on the company key; empty = off
7991
- "ai_budget_released_day",
7992
- // YYYY-MM-DD the operator lifted today's brake
7993
- "ai_budget_alerted_day",
7994
- // YYYY-MM-DD the operator was told the brake tripped
7995
- // Health alarms (BJ-143): the thresholds on the Operator page; empty = default, "0" = off.
7996
- "alert_queue_minutes",
7997
- // a runnable job waited longer than this
7998
- "alert_failure_percent",
7999
- // share of the last hour's finished jobs that failed
8000
- "alert_budget_percent",
8001
- // share of the daily AI budget spent
8002
- "alert_provider_percent"
8003
- // a provider limit has less than this share left
8004
- ];
8005
- PROVIDER_KEY_SETTINGS = {
8006
- anthropic: "anthropic_api_key",
8007
- openai: "openai_api_key"
8008
- };
8009
- }
8010
- });
8011
-
8012
8047
  // packages/db/src/jobs.ts
8013
8048
  async function enqueueJob(brainId, kind, payload = {}, opts = {}, pool2 = getPool()) {
8014
8049
  const key = opts.dedupeKey ?? "";
@@ -8319,6 +8354,7 @@ var init_src2 = __esm({
8319
8354
  init_jobs();
8320
8355
  init_health();
8321
8356
  init_spend();
8357
+ init_plan();
8322
8358
  init_provider_rate();
8323
8359
  init_ruleset();
8324
8360
  init_usage();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brainjar",
3
- "version": "0.3.1220",
3
+ "version": "0.3.1222",
4
4
  "description": "BrainJar CLI: turn a repository into a live, self-documenting Brain.",
5
5
  "type": "module",
6
6
  "bin": {