brainjar 0.3.975 → 0.3.976
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/brainjar.js +355 -69
- 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.
|
|
110
|
+
CLI_VERSION = "0.3.976";
|
|
111
111
|
CACHE = path.join(os.homedir(), ".brainjar", "version-check.json");
|
|
112
112
|
DAY = 864e5;
|
|
113
113
|
}
|
|
@@ -5895,6 +5895,11 @@ function loadEnv() {
|
|
|
5895
5895
|
}
|
|
5896
5896
|
return { ...cachedFileVars, ...process.env };
|
|
5897
5897
|
}
|
|
5898
|
+
function estimateCostUsd(model, tokens) {
|
|
5899
|
+
const [base = model, tier] = model.split(":");
|
|
5900
|
+
const p = MODEL_PRICES[base] ?? MODEL_PRICES[MODEL_TIERS.standard];
|
|
5901
|
+
return (tier === "flex" ? 0.5 : 1) * (tokens.input * p.input + tokens.cachedInput * p.cachedInput + tokens.output * p.output) / 1e6;
|
|
5902
|
+
}
|
|
5898
5903
|
function loadConfig(env = loadEnv()) {
|
|
5899
5904
|
return new Config(env);
|
|
5900
5905
|
}
|
|
@@ -5907,10 +5912,22 @@ function redactUrlPassword(url) {
|
|
|
5907
5912
|
return url;
|
|
5908
5913
|
}
|
|
5909
5914
|
}
|
|
5910
|
-
var cachedFileVars, DEFAULT_TENANT_ID, SECRETS, CORPORATE_API_KEY_ENV, DEFAULT_DATABASE_URL, MissingSecretError, Config;
|
|
5915
|
+
var cachedFileVars, MODEL_TIERS, MODEL_PRICES, DEFAULT_TENANT_ID, SECRETS, CORPORATE_API_KEY_ENV, DEFAULT_DATABASE_URL, MissingSecretError, Config;
|
|
5911
5916
|
var init_config = __esm({
|
|
5912
5917
|
"packages/shared/src/config.ts"() {
|
|
5913
5918
|
"use strict";
|
|
5919
|
+
MODEL_TIERS = {
|
|
5920
|
+
fast: "claude-haiku-4-5",
|
|
5921
|
+
standard: "claude-sonnet-5",
|
|
5922
|
+
premium: "claude-opus-5"
|
|
5923
|
+
};
|
|
5924
|
+
MODEL_PRICES = {
|
|
5925
|
+
"claude-opus-5": { input: 5, cachedInput: 0.5, output: 25 },
|
|
5926
|
+
// Launch pricing made permanent (official pricing page, checked 2026-08-18).
|
|
5927
|
+
"claude-sonnet-5": { input: 2, cachedInput: 0.2, output: 10 },
|
|
5928
|
+
"claude-haiku-4-5": { input: 1, cachedInput: 0.1, output: 5 },
|
|
5929
|
+
"gpt-5.6-luna": { input: 0.2, cachedInput: 0.02, output: 1.2 }
|
|
5930
|
+
};
|
|
5914
5931
|
DEFAULT_TENANT_ID = "00000000-0000-0000-0000-000000000002";
|
|
5915
5932
|
SECRETS = {
|
|
5916
5933
|
anthropicApiKey: {
|
|
@@ -6016,13 +6033,6 @@ var init_config = __esm({
|
|
|
6016
6033
|
}
|
|
6017
6034
|
});
|
|
6018
6035
|
|
|
6019
|
-
// packages/shared/src/ratelimit.ts
|
|
6020
|
-
var init_ratelimit = __esm({
|
|
6021
|
-
"packages/shared/src/ratelimit.ts"() {
|
|
6022
|
-
"use strict";
|
|
6023
|
-
}
|
|
6024
|
-
});
|
|
6025
|
-
|
|
6026
6036
|
// packages/shared/src/sanitize.ts
|
|
6027
6037
|
var init_sanitize = __esm({
|
|
6028
6038
|
"packages/shared/src/sanitize.ts"() {
|
|
@@ -6216,7 +6226,6 @@ var init_src = __esm({
|
|
|
6216
6226
|
init_memory();
|
|
6217
6227
|
init_confidence();
|
|
6218
6228
|
init_config();
|
|
6219
|
-
init_ratelimit();
|
|
6220
6229
|
init_sanitize();
|
|
6221
6230
|
init_flow();
|
|
6222
6231
|
init_capture_events();
|
|
@@ -6238,8 +6247,11 @@ function getPool() {
|
|
|
6238
6247
|
}
|
|
6239
6248
|
pool = new esm_default.Pool({
|
|
6240
6249
|
connectionString: config.databaseUrl,
|
|
6250
|
+
// Per process (BJ-137): many instances times the default would fill Postgres; each role
|
|
6251
|
+
// sets its own in the compose file. PgBouncer in front is the cloud ticket's (BJ-140).
|
|
6252
|
+
max: Number(process.env.DATABASE_POOL_MAX) || 10,
|
|
6241
6253
|
// Session GUC set in the startup packet — race-free, applies before any query.
|
|
6242
|
-
options: `-c app.tenant_id=${config.tenantId}`
|
|
6254
|
+
options: `-c app.tenant_id=${config.tenantId} -c hnsw.iterative_scan=strict_order`
|
|
6243
6255
|
});
|
|
6244
6256
|
pool.on("error", () => {
|
|
6245
6257
|
});
|
|
@@ -7599,7 +7611,7 @@ var init_repository = __esm({
|
|
|
7599
7611
|
});
|
|
7600
7612
|
|
|
7601
7613
|
// packages/db/src/ratelimit.ts
|
|
7602
|
-
var
|
|
7614
|
+
var init_ratelimit = __esm({
|
|
7603
7615
|
"packages/db/src/ratelimit.ts"() {
|
|
7604
7616
|
"use strict";
|
|
7605
7617
|
init_pool();
|
|
@@ -7629,7 +7641,7 @@ var init_auth = __esm({
|
|
|
7629
7641
|
"use strict";
|
|
7630
7642
|
init_src();
|
|
7631
7643
|
init_pool();
|
|
7632
|
-
|
|
7644
|
+
init_ratelimit();
|
|
7633
7645
|
init_auth_event();
|
|
7634
7646
|
init_email_token();
|
|
7635
7647
|
DEFAULT_TTL_HOURS = 24 * 90;
|
|
@@ -7776,7 +7788,22 @@ var init_settings = __esm({
|
|
|
7776
7788
|
// Voice chat (voice handoff, 2026-09-21): an explicit "true" or "false"; absent means on.
|
|
7777
7789
|
"voice_enabled",
|
|
7778
7790
|
// The GPT-Live voice (voice picker, 2026-09-22): an id from VOICE_OPTIONS; absent = default.
|
|
7779
|
-
"voice_name"
|
|
7791
|
+
"voice_name",
|
|
7792
|
+
// AI cost cap (BJ-139), set on the Operator page; env overrides, defaults in ingest/allowance.
|
|
7793
|
+
"ai_contingent",
|
|
7794
|
+
// "on" | "off": monthly contingent per workspace (default on in SaaS)
|
|
7795
|
+
"ai_free_monthly_usd",
|
|
7796
|
+
// Free workspace, USD per month
|
|
7797
|
+
"ai_team_seat_monthly_usd",
|
|
7798
|
+
// Team, USD per seat and month (applies once licenses exist)
|
|
7799
|
+
"ai_operator_exempt",
|
|
7800
|
+
// "true" | "false": operator accounts are never capped
|
|
7801
|
+
"ai_daily_budget_usd",
|
|
7802
|
+
// the instance's emergency brake on the company key; empty = off
|
|
7803
|
+
"ai_budget_released_day",
|
|
7804
|
+
// YYYY-MM-DD the operator lifted today's brake
|
|
7805
|
+
"ai_budget_alerted_day"
|
|
7806
|
+
// YYYY-MM-DD the operator was told the brake tripped
|
|
7780
7807
|
];
|
|
7781
7808
|
PROVIDER_KEY_SETTINGS = {
|
|
7782
7809
|
anthropic: "anthropic_api_key",
|
|
@@ -7810,10 +7837,102 @@ var init_tickets = __esm({
|
|
|
7810
7837
|
});
|
|
7811
7838
|
|
|
7812
7839
|
// packages/db/src/jobs.ts
|
|
7840
|
+
var CAPTURE_JOB_KINDS, USER_JOB_KINDS;
|
|
7813
7841
|
var init_jobs = __esm({
|
|
7814
7842
|
"packages/db/src/jobs.ts"() {
|
|
7815
7843
|
"use strict";
|
|
7816
7844
|
init_pool();
|
|
7845
|
+
CAPTURE_JOB_KINDS = [
|
|
7846
|
+
"capture-extract",
|
|
7847
|
+
"capture-session",
|
|
7848
|
+
"capture-transcript",
|
|
7849
|
+
"capture-structure"
|
|
7850
|
+
];
|
|
7851
|
+
USER_JOB_KINDS = [
|
|
7852
|
+
...CAPTURE_JOB_KINDS,
|
|
7853
|
+
"deepscan",
|
|
7854
|
+
"verify",
|
|
7855
|
+
"summary-report",
|
|
7856
|
+
"resynthesize"
|
|
7857
|
+
];
|
|
7858
|
+
}
|
|
7859
|
+
});
|
|
7860
|
+
|
|
7861
|
+
// packages/db/src/spend.ts
|
|
7862
|
+
function dayKey(at = /* @__PURE__ */ new Date()) {
|
|
7863
|
+
return `day:${at.toISOString().slice(0, 10)}`;
|
|
7864
|
+
}
|
|
7865
|
+
async function addSpend(brainId, usd, at = /* @__PURE__ */ new Date(), pool2 = getPool()) {
|
|
7866
|
+
if (!(usd > 0)) return;
|
|
7867
|
+
await pool2.query(
|
|
7868
|
+
`INSERT INTO llm_spend (key, usd)
|
|
7869
|
+
SELECT k, $2 FROM (
|
|
7870
|
+
SELECT $3::text AS k
|
|
7871
|
+
UNION ALL
|
|
7872
|
+
SELECT 'ws:' || b.owner_id || ':' || $4 FROM brain b
|
|
7873
|
+
WHERE b.id = $1 AND b.owner_id IS NOT NULL
|
|
7874
|
+
) keys
|
|
7875
|
+
ON CONFLICT (key) DO UPDATE SET usd = llm_spend.usd + EXCLUDED.usd, updated_at = now()`,
|
|
7876
|
+
[brainId, usd, dayKey(at), at.toISOString().slice(0, 7)]
|
|
7877
|
+
);
|
|
7878
|
+
}
|
|
7879
|
+
var init_spend = __esm({
|
|
7880
|
+
"packages/db/src/spend.ts"() {
|
|
7881
|
+
"use strict";
|
|
7882
|
+
init_pool();
|
|
7883
|
+
}
|
|
7884
|
+
});
|
|
7885
|
+
|
|
7886
|
+
// packages/db/src/provider-rate.ts
|
|
7887
|
+
async function saveRate(keyId2, model, s, pool2 = getPool()) {
|
|
7888
|
+
await pool2.query(
|
|
7889
|
+
`INSERT INTO llm_rate (key_id, model, requests_limit, requests_remaining, requests_reset_at,
|
|
7890
|
+
tokens_limit, tokens_remaining, tokens_reset_at, observed_at)
|
|
7891
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
7892
|
+
ON CONFLICT (key_id, model) DO UPDATE SET
|
|
7893
|
+
requests_limit = EXCLUDED.requests_limit,
|
|
7894
|
+
requests_remaining = EXCLUDED.requests_remaining,
|
|
7895
|
+
requests_reset_at = EXCLUDED.requests_reset_at,
|
|
7896
|
+
tokens_limit = EXCLUDED.tokens_limit,
|
|
7897
|
+
tokens_remaining = EXCLUDED.tokens_remaining,
|
|
7898
|
+
tokens_reset_at = EXCLUDED.tokens_reset_at,
|
|
7899
|
+
observed_at = EXCLUDED.observed_at
|
|
7900
|
+
WHERE llm_rate.observed_at <= EXCLUDED.observed_at`,
|
|
7901
|
+
[
|
|
7902
|
+
keyId2,
|
|
7903
|
+
model,
|
|
7904
|
+
s.requestsLimit,
|
|
7905
|
+
s.requestsRemaining,
|
|
7906
|
+
s.requestsResetAt,
|
|
7907
|
+
s.tokensLimit,
|
|
7908
|
+
s.tokensRemaining,
|
|
7909
|
+
s.tokensResetAt,
|
|
7910
|
+
s.observedAt
|
|
7911
|
+
]
|
|
7912
|
+
);
|
|
7913
|
+
}
|
|
7914
|
+
async function loadRate(keyId2, model, pool2 = getPool()) {
|
|
7915
|
+
const r = await pool2.query(
|
|
7916
|
+
"SELECT * FROM llm_rate WHERE key_id = $1 AND model = $2",
|
|
7917
|
+
[keyId2, model]
|
|
7918
|
+
);
|
|
7919
|
+
const x = r.rows[0];
|
|
7920
|
+
if (!x) return null;
|
|
7921
|
+
const n2 = (v) => v === null ? null : Number(v);
|
|
7922
|
+
return {
|
|
7923
|
+
requestsLimit: n2(x.requests_limit),
|
|
7924
|
+
requestsRemaining: n2(x.requests_remaining),
|
|
7925
|
+
requestsResetAt: x.requests_reset_at,
|
|
7926
|
+
tokensLimit: n2(x.tokens_limit),
|
|
7927
|
+
tokensRemaining: n2(x.tokens_remaining),
|
|
7928
|
+
tokensResetAt: x.tokens_reset_at,
|
|
7929
|
+
observedAt: x.observed_at
|
|
7930
|
+
};
|
|
7931
|
+
}
|
|
7932
|
+
var init_provider_rate = __esm({
|
|
7933
|
+
"packages/db/src/provider-rate.ts"() {
|
|
7934
|
+
"use strict";
|
|
7935
|
+
init_pool();
|
|
7817
7936
|
}
|
|
7818
7937
|
});
|
|
7819
7938
|
|
|
@@ -7841,11 +7960,21 @@ async function recordLlmUsage(u) {
|
|
|
7841
7960
|
Math.max(0, Math.round(u.outputTokens))
|
|
7842
7961
|
]
|
|
7843
7962
|
);
|
|
7963
|
+
await addSpend(
|
|
7964
|
+
u.brainId ?? null,
|
|
7965
|
+
estimateCostUsd(u.model, {
|
|
7966
|
+
input: u.inputTokens,
|
|
7967
|
+
cachedInput: u.cachedInputTokens,
|
|
7968
|
+
output: u.outputTokens
|
|
7969
|
+
})
|
|
7970
|
+
);
|
|
7844
7971
|
}
|
|
7845
7972
|
var init_usage = __esm({
|
|
7846
7973
|
"packages/db/src/usage.ts"() {
|
|
7847
7974
|
"use strict";
|
|
7975
|
+
init_src();
|
|
7848
7976
|
init_pool();
|
|
7977
|
+
init_spend();
|
|
7849
7978
|
}
|
|
7850
7979
|
});
|
|
7851
7980
|
|
|
@@ -7859,7 +7988,7 @@ var init_src2 = __esm({
|
|
|
7859
7988
|
init_auth();
|
|
7860
7989
|
init_api_token();
|
|
7861
7990
|
init_oauth();
|
|
7862
|
-
|
|
7991
|
+
init_ratelimit();
|
|
7863
7992
|
init_auth_event();
|
|
7864
7993
|
init_email_token();
|
|
7865
7994
|
init_totp2();
|
|
@@ -7872,6 +8001,8 @@ var init_src2 = __esm({
|
|
|
7872
8001
|
init_conversations();
|
|
7873
8002
|
init_tickets();
|
|
7874
8003
|
init_jobs();
|
|
8004
|
+
init_spend();
|
|
8005
|
+
init_provider_rate();
|
|
7875
8006
|
init_ruleset();
|
|
7876
8007
|
init_usage();
|
|
7877
8008
|
init_audit_origin();
|
|
@@ -12740,11 +12871,118 @@ var init_sdk = __esm({
|
|
|
12740
12871
|
}
|
|
12741
12872
|
});
|
|
12742
12873
|
|
|
12874
|
+
// packages/ingest/src/provider-rate.ts
|
|
12875
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
12876
|
+
function parseDuration(s) {
|
|
12877
|
+
if (!s) return null;
|
|
12878
|
+
let ms = 0;
|
|
12879
|
+
let hit = false;
|
|
12880
|
+
for (const [, n2, unit] of s.matchAll(/(\d+(?:\.\d+)?)(ms|h|m|s)/g)) {
|
|
12881
|
+
hit = true;
|
|
12882
|
+
ms += Number(n2) * UNIT_MS[unit];
|
|
12883
|
+
}
|
|
12884
|
+
return hit ? ms : null;
|
|
12885
|
+
}
|
|
12886
|
+
function parseRateHeaders(h, now = /* @__PURE__ */ new Date()) {
|
|
12887
|
+
const num = (a, b) => {
|
|
12888
|
+
const v = h.get(a) ?? h.get(b);
|
|
12889
|
+
const n2 = v === null ? NaN : Number(v);
|
|
12890
|
+
return Number.isFinite(n2) ? n2 : null;
|
|
12891
|
+
};
|
|
12892
|
+
const at = (openai, anthropic) => {
|
|
12893
|
+
const d = parseDuration(h.get(openai));
|
|
12894
|
+
if (d !== null) return new Date(now.getTime() + d);
|
|
12895
|
+
const t = Date.parse(h.get(anthropic) ?? "");
|
|
12896
|
+
return Number.isFinite(t) ? new Date(t) : null;
|
|
12897
|
+
};
|
|
12898
|
+
const s = {
|
|
12899
|
+
requestsLimit: num(
|
|
12900
|
+
"x-ratelimit-limit-requests",
|
|
12901
|
+
"anthropic-ratelimit-requests-limit"
|
|
12902
|
+
),
|
|
12903
|
+
requestsRemaining: num(
|
|
12904
|
+
"x-ratelimit-remaining-requests",
|
|
12905
|
+
"anthropic-ratelimit-requests-remaining"
|
|
12906
|
+
),
|
|
12907
|
+
requestsResetAt: at(
|
|
12908
|
+
"x-ratelimit-reset-requests",
|
|
12909
|
+
"anthropic-ratelimit-requests-reset"
|
|
12910
|
+
),
|
|
12911
|
+
tokensLimit: num(
|
|
12912
|
+
"x-ratelimit-limit-tokens",
|
|
12913
|
+
"anthropic-ratelimit-tokens-limit"
|
|
12914
|
+
),
|
|
12915
|
+
tokensRemaining: num(
|
|
12916
|
+
"x-ratelimit-remaining-tokens",
|
|
12917
|
+
"anthropic-ratelimit-tokens-remaining"
|
|
12918
|
+
),
|
|
12919
|
+
tokensResetAt: at(
|
|
12920
|
+
"x-ratelimit-reset-tokens",
|
|
12921
|
+
"anthropic-ratelimit-tokens-reset"
|
|
12922
|
+
),
|
|
12923
|
+
observedAt: now
|
|
12924
|
+
};
|
|
12925
|
+
return s.requestsLimit === null && s.tokensLimit === null ? null : s;
|
|
12926
|
+
}
|
|
12927
|
+
function roomWaitMs(s, now = /* @__PURE__ */ new Date(), reserve = RESERVE) {
|
|
12928
|
+
const wait = (limit, remaining, resetAt) => {
|
|
12929
|
+
if (!limit || remaining === null || !resetAt) return 0;
|
|
12930
|
+
const need = reserve * limit;
|
|
12931
|
+
if (remaining >= need || resetAt <= now) return 0;
|
|
12932
|
+
const span = resetAt.getTime() - s.observedAt.getTime();
|
|
12933
|
+
const okAt = s.observedAt.getTime() + span * (need - remaining) / (limit - remaining);
|
|
12934
|
+
return Math.max(0, Math.ceil(okAt - now.getTime()));
|
|
12935
|
+
};
|
|
12936
|
+
return Math.max(
|
|
12937
|
+
wait(s.requestsLimit, s.requestsRemaining, s.requestsResetAt),
|
|
12938
|
+
wait(s.tokensLimit, s.tokensRemaining, s.tokensResetAt)
|
|
12939
|
+
);
|
|
12940
|
+
}
|
|
12941
|
+
async function awaitRoom(id, model) {
|
|
12942
|
+
for (; ; ) {
|
|
12943
|
+
const s = await loadRate(id, model).catch(() => null);
|
|
12944
|
+
const ms = s ? roomWaitMs(s) : 0;
|
|
12945
|
+
if (ms <= 0) return;
|
|
12946
|
+
await sleep2(Math.min(ms, MAX_NAP_MS) + Math.random() * 250);
|
|
12947
|
+
}
|
|
12948
|
+
}
|
|
12949
|
+
function noteRate(id, model, headers) {
|
|
12950
|
+
const s = headers ? parseRateHeaders(headers) : null;
|
|
12951
|
+
if (s) void saveRate(id, model, s).catch(() => {
|
|
12952
|
+
});
|
|
12953
|
+
}
|
|
12954
|
+
function rateFetch(apiKey, model, automatic) {
|
|
12955
|
+
const id = keyId(apiKey);
|
|
12956
|
+
return async (input, init2) => {
|
|
12957
|
+
if (automatic) await awaitRoom(id, model);
|
|
12958
|
+
const res = await fetch(input, init2);
|
|
12959
|
+
noteRate(id, model, res.headers);
|
|
12960
|
+
return res;
|
|
12961
|
+
};
|
|
12962
|
+
}
|
|
12963
|
+
var RESERVE, MAX_NAP_MS, sleep2, isAutomatic, keyId, UNIT_MS;
|
|
12964
|
+
var init_provider_rate2 = __esm({
|
|
12965
|
+
"packages/ingest/src/provider-rate.ts"() {
|
|
12966
|
+
"use strict";
|
|
12967
|
+
init_src2();
|
|
12968
|
+
RESERVE = 0.2;
|
|
12969
|
+
MAX_NAP_MS = 6e4;
|
|
12970
|
+
sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
12971
|
+
isAutomatic = (meta) => !meta?.actor && !meta?.waiting;
|
|
12972
|
+
keyId = (apiKey) => createHash2("sha256").update(apiKey).digest("hex").slice(0, 16);
|
|
12973
|
+
UNIT_MS = { ms: 1, s: 1e3, m: 6e4, h: 36e5 };
|
|
12974
|
+
}
|
|
12975
|
+
});
|
|
12976
|
+
|
|
12743
12977
|
// packages/ingest/src/llm.ts
|
|
12744
12978
|
function rationaleModelId(env = process.env) {
|
|
12745
12979
|
return env.BRAINJAR_RATIONALE_MODEL?.trim() || "claude-opus-5";
|
|
12746
12980
|
}
|
|
12747
12981
|
function logUsage(meta, model, usage) {
|
|
12982
|
+
if (!meta?.brainId)
|
|
12983
|
+
console.warn(
|
|
12984
|
+
`brainjar: AI call without a Brain (workload ${meta?.workload ?? "other"}); it counts only toward the daily budget`
|
|
12985
|
+
);
|
|
12748
12986
|
void recordLlmUsage({
|
|
12749
12987
|
brainId: meta?.brainId ?? null,
|
|
12750
12988
|
workload: meta?.workload ?? "other",
|
|
@@ -12770,6 +13008,7 @@ var init_llm = __esm({
|
|
|
12770
13008
|
"use strict";
|
|
12771
13009
|
init_sdk();
|
|
12772
13010
|
init_src2();
|
|
13011
|
+
init_provider_rate2();
|
|
12773
13012
|
cachedSystem = (system) => [
|
|
12774
13013
|
{
|
|
12775
13014
|
type: "text",
|
|
@@ -12782,9 +13021,12 @@ var init_llm = __esm({
|
|
|
12782
13021
|
model;
|
|
12783
13022
|
meta;
|
|
12784
13023
|
constructor(opts) {
|
|
12785
|
-
this.client = new Anthropic({ apiKey: opts.apiKey });
|
|
12786
13024
|
this.model = opts.model ?? rationaleModelId();
|
|
12787
13025
|
this.meta = opts.meta;
|
|
13026
|
+
this.client = new Anthropic({
|
|
13027
|
+
apiKey: opts.apiKey,
|
|
13028
|
+
fetch: rateFetch(opts.apiKey, this.model, isAutomatic(opts.meta))
|
|
13029
|
+
});
|
|
12788
13030
|
}
|
|
12789
13031
|
async complete({
|
|
12790
13032
|
system,
|
|
@@ -12831,7 +13073,18 @@ var init_llm = __esm({
|
|
|
12831
13073
|
var init_openai = __esm({
|
|
12832
13074
|
"packages/ingest/src/openai.ts"() {
|
|
12833
13075
|
"use strict";
|
|
13076
|
+
init_src();
|
|
12834
13077
|
init_llm();
|
|
13078
|
+
init_provider_rate2();
|
|
13079
|
+
}
|
|
13080
|
+
});
|
|
13081
|
+
|
|
13082
|
+
// packages/ingest/src/allowance.ts
|
|
13083
|
+
var init_allowance = __esm({
|
|
13084
|
+
"packages/ingest/src/allowance.ts"() {
|
|
13085
|
+
"use strict";
|
|
13086
|
+
init_src2();
|
|
13087
|
+
init_src();
|
|
12835
13088
|
}
|
|
12836
13089
|
});
|
|
12837
13090
|
|
|
@@ -12841,6 +13094,7 @@ var init_routing = __esm({
|
|
|
12841
13094
|
"use strict";
|
|
12842
13095
|
init_src2();
|
|
12843
13096
|
init_src();
|
|
13097
|
+
init_allowance();
|
|
12844
13098
|
init_llm();
|
|
12845
13099
|
init_openai();
|
|
12846
13100
|
}
|
|
@@ -14394,6 +14648,8 @@ var init_summaries = __esm({
|
|
|
14394
14648
|
"use strict";
|
|
14395
14649
|
init_src2();
|
|
14396
14650
|
init_src();
|
|
14651
|
+
init_routing();
|
|
14652
|
+
init_allowance();
|
|
14397
14653
|
REPORT_SYSTEM = [
|
|
14398
14654
|
"You write the period report of a software project for the people who work on it: what changed, why it matters, what was decided, what is still open.",
|
|
14399
14655
|
"Input: the captured records inside the period, numbered, oldest first, each with its date, time, type and title. Record types: feature (behavior that was built or changed), decision (a recorded direction, NOT a delivery), failure (an approach that did not work), event (a commit or another recorded event), note (a note or follow-up).",
|
|
@@ -15094,7 +15350,7 @@ var init_doku_model = __esm({
|
|
|
15094
15350
|
});
|
|
15095
15351
|
|
|
15096
15352
|
// packages/ingest/src/doku.ts
|
|
15097
|
-
import { createHash as
|
|
15353
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
15098
15354
|
import { mkdir as mkdir10, readFile as readFile10, rm as rm6, stat, writeFile as writeFile10 } from "node:fs/promises";
|
|
15099
15355
|
import path15 from "node:path";
|
|
15100
15356
|
function bodyLocations(o) {
|
|
@@ -16094,7 +16350,7 @@ var init_doku = __esm({
|
|
|
16094
16350
|
DOKU_DIR = "brainjar-doku";
|
|
16095
16351
|
MANIFEST = ".manifest.json";
|
|
16096
16352
|
CHANGELOG_DAYS = 60;
|
|
16097
|
-
sha1 = (s) =>
|
|
16353
|
+
sha1 = (s) => createHash3("sha1").update(s).digest("hex");
|
|
16098
16354
|
exists = (p) => stat(p).then(
|
|
16099
16355
|
() => true,
|
|
16100
16356
|
() => false
|
|
@@ -16311,10 +16567,12 @@ var init_verify_agent = __esm({
|
|
|
16311
16567
|
init_sdk();
|
|
16312
16568
|
init_src2();
|
|
16313
16569
|
init_src();
|
|
16570
|
+
init_allowance();
|
|
16314
16571
|
init_product_facts();
|
|
16315
16572
|
init_doku();
|
|
16316
16573
|
init_llm();
|
|
16317
16574
|
init_openai();
|
|
16575
|
+
init_provider_rate2();
|
|
16318
16576
|
init_routing();
|
|
16319
16577
|
VERIFY_SYSTEM = [
|
|
16320
16578
|
"You are BrainJar's verification agent. You read a software repository and record durable product knowledge, with one iron rule: prose is never truth, code is.",
|
|
@@ -16363,17 +16621,40 @@ var init_verify_poll = __esm({
|
|
|
16363
16621
|
}
|
|
16364
16622
|
});
|
|
16365
16623
|
|
|
16624
|
+
// packages/ingest/src/scheduler.ts
|
|
16625
|
+
var init_scheduler = __esm({
|
|
16626
|
+
"packages/ingest/src/scheduler.ts"() {
|
|
16627
|
+
"use strict";
|
|
16628
|
+
init_src2();
|
|
16629
|
+
init_daily_log();
|
|
16630
|
+
init_summaries();
|
|
16631
|
+
}
|
|
16632
|
+
});
|
|
16633
|
+
|
|
16366
16634
|
// packages/ingest/src/job-worker.ts
|
|
16367
16635
|
var init_job_worker = __esm({
|
|
16368
16636
|
"packages/ingest/src/job-worker.ts"() {
|
|
16369
16637
|
"use strict";
|
|
16370
16638
|
init_src2();
|
|
16371
16639
|
init_deepscan();
|
|
16640
|
+
init_doku();
|
|
16641
|
+
init_scheduler();
|
|
16642
|
+
init_summaries();
|
|
16643
|
+
init_verify_poll();
|
|
16372
16644
|
init_routing();
|
|
16645
|
+
init_allowance();
|
|
16373
16646
|
init_verify_start();
|
|
16374
16647
|
}
|
|
16375
16648
|
});
|
|
16376
16649
|
|
|
16650
|
+
// packages/ingest/src/job-clock.ts
|
|
16651
|
+
var init_job_clock = __esm({
|
|
16652
|
+
"packages/ingest/src/job-clock.ts"() {
|
|
16653
|
+
"use strict";
|
|
16654
|
+
init_src2();
|
|
16655
|
+
}
|
|
16656
|
+
});
|
|
16657
|
+
|
|
16377
16658
|
// packages/ingest/src/ask-agent-model.ts
|
|
16378
16659
|
var init_ask_agent_model = __esm({
|
|
16379
16660
|
"packages/ingest/src/ask-agent-model.ts"() {
|
|
@@ -16381,18 +16662,10 @@ var init_ask_agent_model = __esm({
|
|
|
16381
16662
|
init_sdk();
|
|
16382
16663
|
init_src2();
|
|
16383
16664
|
init_src();
|
|
16665
|
+
init_allowance();
|
|
16384
16666
|
init_llm();
|
|
16385
16667
|
init_openai();
|
|
16386
|
-
|
|
16387
|
-
});
|
|
16388
|
-
|
|
16389
|
-
// packages/ingest/src/scheduler.ts
|
|
16390
|
-
var init_scheduler = __esm({
|
|
16391
|
-
"packages/ingest/src/scheduler.ts"() {
|
|
16392
|
-
"use strict";
|
|
16393
|
-
init_src2();
|
|
16394
|
-
init_daily_log();
|
|
16395
|
-
init_summaries();
|
|
16668
|
+
init_provider_rate2();
|
|
16396
16669
|
}
|
|
16397
16670
|
});
|
|
16398
16671
|
|
|
@@ -16415,6 +16688,7 @@ var init_src3 = __esm({
|
|
|
16415
16688
|
init_llm();
|
|
16416
16689
|
init_openai();
|
|
16417
16690
|
init_routing();
|
|
16691
|
+
init_allowance();
|
|
16418
16692
|
init_rationale_extractor();
|
|
16419
16693
|
init_extraction();
|
|
16420
16694
|
init_entities();
|
|
@@ -16453,6 +16727,7 @@ var init_src3 = __esm({
|
|
|
16453
16727
|
init_verify_poll();
|
|
16454
16728
|
init_verify_start();
|
|
16455
16729
|
init_job_worker();
|
|
16730
|
+
init_job_clock();
|
|
16456
16731
|
init_ask_agent_model();
|
|
16457
16732
|
init_scheduler();
|
|
16458
16733
|
registerConnector(
|
|
@@ -16505,7 +16780,24 @@ async function captureApi(pathAndQuery, init2 = {}) {
|
|
|
16505
16780
|
}
|
|
16506
16781
|
return body;
|
|
16507
16782
|
}
|
|
16508
|
-
|
|
16783
|
+
async function uploadArtifacts(brain, sourceId, artifacts, cursor3) {
|
|
16784
|
+
let inserted = 0;
|
|
16785
|
+
for (let i = 0; i < artifacts.length; i += UPLOAD_PORTION) {
|
|
16786
|
+
const last = i + UPLOAD_PORTION >= artifacts.length;
|
|
16787
|
+
const r = await captureApi("/capture/artifacts", {
|
|
16788
|
+
method: "POST",
|
|
16789
|
+
body: {
|
|
16790
|
+
brain,
|
|
16791
|
+
sourceId,
|
|
16792
|
+
artifacts: artifacts.slice(i, i + UPLOAD_PORTION),
|
|
16793
|
+
cursor: last ? cursor3 : null
|
|
16794
|
+
}
|
|
16795
|
+
});
|
|
16796
|
+
inserted += r.inserted;
|
|
16797
|
+
}
|
|
16798
|
+
return inserted;
|
|
16799
|
+
}
|
|
16800
|
+
var TokenError, TOKEN_HELP, UPLOAD_PORTION;
|
|
16509
16801
|
var init_api_client = __esm({
|
|
16510
16802
|
"packages/cli/src/api-client.ts"() {
|
|
16511
16803
|
"use strict";
|
|
@@ -16513,6 +16805,7 @@ var init_api_client = __esm({
|
|
|
16513
16805
|
TokenError = class extends Error {
|
|
16514
16806
|
};
|
|
16515
16807
|
TOKEN_HELP = "BrainJar token revoked or invalid. Create a new token under Account in the web app, then run `npx brainjar init --brain <id> --token <token>` once in any project on this machine.";
|
|
16808
|
+
UPLOAD_PORTION = 2e3;
|
|
16516
16809
|
}
|
|
16517
16810
|
});
|
|
16518
16811
|
|
|
@@ -16745,7 +17038,7 @@ var init_debt = __esm({
|
|
|
16745
17038
|
});
|
|
16746
17039
|
|
|
16747
17040
|
// packages/cli/src/adapters/claude-code.ts
|
|
16748
|
-
import { createHash as
|
|
17041
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
16749
17042
|
function targetOf(input) {
|
|
16750
17043
|
const i = input ?? {};
|
|
16751
17044
|
for (const k of ["command", "file_path", "notebook_path"]) {
|
|
@@ -16790,7 +17083,7 @@ var init_claude_code = __esm({
|
|
|
16790
17083
|
"use strict";
|
|
16791
17084
|
init_src();
|
|
16792
17085
|
EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
|
|
16793
|
-
short2 = (s) =>
|
|
17086
|
+
short2 = (s) => createHash4("sha256").update(s).digest("hex").slice(0, 16);
|
|
16794
17087
|
claudeCode2 = {
|
|
16795
17088
|
id: "claude-code",
|
|
16796
17089
|
map(payload, now) {
|
|
@@ -16889,7 +17182,7 @@ var init_claude_code = __esm({
|
|
|
16889
17182
|
});
|
|
16890
17183
|
|
|
16891
17184
|
// packages/cli/src/adapters/cursor.ts
|
|
16892
|
-
import { createHash as
|
|
17185
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
16893
17186
|
function targetOf2(input) {
|
|
16894
17187
|
const i = input ?? {};
|
|
16895
17188
|
for (const k of ["command", "file_path", "path", "target_file"]) {
|
|
@@ -16910,7 +17203,7 @@ var init_cursor = __esm({
|
|
|
16910
17203
|
"packages/cli/src/adapters/cursor.ts"() {
|
|
16911
17204
|
"use strict";
|
|
16912
17205
|
init_src();
|
|
16913
|
-
short3 = (s) =>
|
|
17206
|
+
short3 = (s) => createHash5("sha256").update(s).digest("hex").slice(0, 16);
|
|
16914
17207
|
cursor2 = {
|
|
16915
17208
|
id: "cursor",
|
|
16916
17209
|
map(payload, now) {
|
|
@@ -17028,7 +17321,7 @@ var init_cursor = __esm({
|
|
|
17028
17321
|
});
|
|
17029
17322
|
|
|
17030
17323
|
// packages/cli/src/adapters/codex.ts
|
|
17031
|
-
import { createHash as
|
|
17324
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
17032
17325
|
function patchFiles(patch) {
|
|
17033
17326
|
const out = /* @__PURE__ */ new Set();
|
|
17034
17327
|
for (const m of patch.matchAll(
|
|
@@ -17064,7 +17357,7 @@ var init_codex = __esm({
|
|
|
17064
17357
|
"use strict";
|
|
17065
17358
|
init_src();
|
|
17066
17359
|
PATCH_TOOLS = /* @__PURE__ */ new Set(["apply_patch", "Edit", "Write"]);
|
|
17067
|
-
short4 = (s) =>
|
|
17360
|
+
short4 = (s) => createHash6("sha256").update(s).digest("hex").slice(0, 16);
|
|
17068
17361
|
codex2 = {
|
|
17069
17362
|
id: "codex",
|
|
17070
17363
|
map(payload, now) {
|
|
@@ -17161,7 +17454,7 @@ var init_codex = __esm({
|
|
|
17161
17454
|
});
|
|
17162
17455
|
|
|
17163
17456
|
// packages/cli/src/adapters/copilot.ts
|
|
17164
|
-
import { createHash as
|
|
17457
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
17165
17458
|
function targetOf3(args) {
|
|
17166
17459
|
if (!args || typeof args !== "object") return "";
|
|
17167
17460
|
const a = args;
|
|
@@ -17194,7 +17487,7 @@ var init_copilot = __esm({
|
|
|
17194
17487
|
"use strict";
|
|
17195
17488
|
init_src();
|
|
17196
17489
|
EDIT_TOOLS2 = /* @__PURE__ */ new Set(["edit", "create"]);
|
|
17197
|
-
short5 = (s) =>
|
|
17490
|
+
short5 = (s) => createHash7("sha256").update(s).digest("hex").slice(0, 16);
|
|
17198
17491
|
EVENT_ALIASES = {
|
|
17199
17492
|
SessionStart: "sessionStart",
|
|
17200
17493
|
SessionEnd: "sessionEnd",
|
|
@@ -17303,7 +17596,7 @@ var init_copilot = __esm({
|
|
|
17303
17596
|
});
|
|
17304
17597
|
|
|
17305
17598
|
// packages/cli/src/adapters/gemini.ts
|
|
17306
|
-
import { createHash as
|
|
17599
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
17307
17600
|
function targetOf4(input) {
|
|
17308
17601
|
const i = input ?? {};
|
|
17309
17602
|
for (const k of ["command", "file_path"]) {
|
|
@@ -17325,7 +17618,7 @@ var init_gemini = __esm({
|
|
|
17325
17618
|
"use strict";
|
|
17326
17619
|
init_src();
|
|
17327
17620
|
EDIT_TOOLS3 = /* @__PURE__ */ new Set(["write_file", "replace"]);
|
|
17328
|
-
short6 = (s) =>
|
|
17621
|
+
short6 = (s) => createHash8("sha256").update(s).digest("hex").slice(0, 16);
|
|
17329
17622
|
gemini2 = {
|
|
17330
17623
|
id: "gemini",
|
|
17331
17624
|
map(payload, now) {
|
|
@@ -17421,7 +17714,7 @@ var init_gemini = __esm({
|
|
|
17421
17714
|
});
|
|
17422
17715
|
|
|
17423
17716
|
// packages/cli/src/adapters/kiro.ts
|
|
17424
|
-
import { createHash as
|
|
17717
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
17425
17718
|
function targetOf5(input) {
|
|
17426
17719
|
const i = input ?? {};
|
|
17427
17720
|
for (const k of ["command", "cmd", "path", "file_path", "filePath"]) {
|
|
@@ -17452,7 +17745,7 @@ var init_kiro = __esm({
|
|
|
17452
17745
|
"use strict";
|
|
17453
17746
|
init_src();
|
|
17454
17747
|
EDIT_TOOLS4 = /* @__PURE__ */ new Set(["fs_write", "write", "str_replace", "fs_append"]);
|
|
17455
|
-
short7 = (s) =>
|
|
17748
|
+
short7 = (s) => createHash9("sha256").update(s).digest("hex").slice(0, 16);
|
|
17456
17749
|
EVENTS5 = {
|
|
17457
17750
|
agentSpawn: "start",
|
|
17458
17751
|
sessionStart: "start",
|
|
@@ -17568,7 +17861,7 @@ var init_kiro = __esm({
|
|
|
17568
17861
|
});
|
|
17569
17862
|
|
|
17570
17863
|
// packages/cli/src/adapters/opencode.ts
|
|
17571
|
-
import { createHash as
|
|
17864
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
17572
17865
|
function commitShas7(text) {
|
|
17573
17866
|
const out = /* @__PURE__ */ new Set();
|
|
17574
17867
|
for (const m of (text ?? "").matchAll(/\[[^\]\n]* ([0-9a-f]{7,40})\]/g)) {
|
|
@@ -17582,7 +17875,7 @@ var init_opencode = __esm({
|
|
|
17582
17875
|
"use strict";
|
|
17583
17876
|
init_src();
|
|
17584
17877
|
EDIT_TOOLS5 = /* @__PURE__ */ new Set(["edit", "write"]);
|
|
17585
|
-
short8 = (s) =>
|
|
17878
|
+
short8 = (s) => createHash10("sha256").update(s).digest("hex").slice(0, 16);
|
|
17586
17879
|
opencode2 = {
|
|
17587
17880
|
id: "opencode",
|
|
17588
17881
|
map(payload, now) {
|
|
@@ -17682,7 +17975,7 @@ var init_opencode = __esm({
|
|
|
17682
17975
|
});
|
|
17683
17976
|
|
|
17684
17977
|
// packages/cli/src/adapters/cline.ts
|
|
17685
|
-
import { createHash as
|
|
17978
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
17686
17979
|
function targetOf6(params) {
|
|
17687
17980
|
const i = params ?? {};
|
|
17688
17981
|
for (const k of ["command", "path"]) {
|
|
@@ -17714,7 +18007,7 @@ var init_cline = __esm({
|
|
|
17714
18007
|
"use strict";
|
|
17715
18008
|
init_src();
|
|
17716
18009
|
EDIT_TOOLS6 = /* @__PURE__ */ new Set(["write_to_file", "replace_in_file", "apply_patch"]);
|
|
17717
|
-
short9 = (s) =>
|
|
18010
|
+
short9 = (s) => createHash11("sha256").update(s).digest("hex").slice(0, 16);
|
|
17718
18011
|
CLINE_REPLY = JSON.stringify({ cancel: false });
|
|
17719
18012
|
cline2 = {
|
|
17720
18013
|
id: "cline",
|
|
@@ -18016,18 +18309,15 @@ async function syncRepo(root) {
|
|
|
18016
18309
|
const connector = createConnector("git_local", { cwd: root }, {});
|
|
18017
18310
|
const artifacts = await connector.sync(project.cursor ?? void 0);
|
|
18018
18311
|
if (artifacts.length > 0) {
|
|
18019
|
-
const
|
|
18020
|
-
|
|
18021
|
-
|
|
18022
|
-
|
|
18023
|
-
|
|
18024
|
-
|
|
18025
|
-
|
|
18026
|
-
}
|
|
18027
|
-
});
|
|
18028
|
-
if (r.inserted > 0) {
|
|
18312
|
+
const inserted = await uploadArtifacts(
|
|
18313
|
+
link.brainId,
|
|
18314
|
+
project.sourceId,
|
|
18315
|
+
artifacts,
|
|
18316
|
+
maxUpdatedAt(artifacts) ?? project.cursor
|
|
18317
|
+
);
|
|
18318
|
+
if (inserted > 0) {
|
|
18029
18319
|
console.error(
|
|
18030
|
-
`brainjar: ${
|
|
18320
|
+
`brainjar: ${inserted} new commits sent, the server reads them in the background`
|
|
18031
18321
|
);
|
|
18032
18322
|
const graph = await scanStructure(root);
|
|
18033
18323
|
await captureApi("/capture/structure", {
|
|
@@ -18095,7 +18385,7 @@ async function waitForServer(brainId, since, opts = {}) {
|
|
|
18095
18385
|
const poll = opts.poll ?? (() => captureApi(
|
|
18096
18386
|
`/capture/progress?brain=${brainId}&since=${encodeURIComponent(since.toISOString())}`
|
|
18097
18387
|
));
|
|
18098
|
-
const
|
|
18388
|
+
const sleep3 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
18099
18389
|
const write = opts.write ?? ((s) => void process.stdout.write(s));
|
|
18100
18390
|
const tty = opts.tty ?? Boolean(process.stdout.isTTY);
|
|
18101
18391
|
const intervalMs = opts.intervalMs ?? 2e3;
|
|
@@ -18112,7 +18402,7 @@ async function waitForServer(brainId, since, opts = {}) {
|
|
|
18112
18402
|
if (tty && shown) write("\n");
|
|
18113
18403
|
return null;
|
|
18114
18404
|
}
|
|
18115
|
-
await
|
|
18405
|
+
await sleep3(intervalMs);
|
|
18116
18406
|
continue;
|
|
18117
18407
|
}
|
|
18118
18408
|
if (p.queued + p.running === 0) {
|
|
@@ -18127,7 +18417,7 @@ async function waitForServer(brainId, since, opts = {}) {
|
|
|
18127
18417
|
shownAt = Date.now();
|
|
18128
18418
|
}
|
|
18129
18419
|
shown = line;
|
|
18130
|
-
await
|
|
18420
|
+
await sleep3(intervalMs);
|
|
18131
18421
|
}
|
|
18132
18422
|
}
|
|
18133
18423
|
var n;
|
|
@@ -18213,16 +18503,12 @@ async function init(argv) {
|
|
|
18213
18503
|
const artifacts = await connector.sync(conn.cursor ?? void 0);
|
|
18214
18504
|
let commits = 0;
|
|
18215
18505
|
if (artifacts.length > 0) {
|
|
18216
|
-
|
|
18217
|
-
|
|
18218
|
-
|
|
18219
|
-
|
|
18220
|
-
|
|
18221
|
-
|
|
18222
|
-
cursor: maxUpdatedAt(artifacts) ?? conn.cursor
|
|
18223
|
-
}
|
|
18224
|
-
});
|
|
18225
|
-
commits = r.inserted;
|
|
18506
|
+
commits = await uploadArtifacts(
|
|
18507
|
+
conn.brainId,
|
|
18508
|
+
conn.sourceId,
|
|
18509
|
+
artifacts,
|
|
18510
|
+
maxUpdatedAt(artifacts) ?? conn.cursor
|
|
18511
|
+
);
|
|
18226
18512
|
}
|
|
18227
18513
|
ok(
|
|
18228
18514
|
`${graph.modules.length} modules, ${commits} new commits sent to the server`
|