modelstat 0.0.35 → 0.0.37
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/dist/cli.mjs +298 -39
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -4500,6 +4500,11 @@ var init_schemas = __esm({
|
|
|
4500
4500
|
provider: external_exports.enum(PROVIDERS),
|
|
4501
4501
|
provider_account_id: external_exports.string().max(200),
|
|
4502
4502
|
provider_account_label: external_exports.string().max(200).nullable(),
|
|
4503
|
+
/** Human-facing labels — what the user recognises the account by.
|
|
4504
|
+
* Populated from the keychain blob / OAuth JWT where available. */
|
|
4505
|
+
account_email: external_exports.string().max(200).nullable().optional(),
|
|
4506
|
+
account_org: external_exports.string().max(200).nullable().optional(),
|
|
4507
|
+
display_name: external_exports.string().max(200).nullable().optional(),
|
|
4503
4508
|
owner_scope: external_exports.enum(IDENTITY_OWNER_SCOPES).default("unassigned"),
|
|
4504
4509
|
detection_source: external_exports.string().max(80)
|
|
4505
4510
|
});
|
|
@@ -7302,14 +7307,19 @@ async function probeIdentities(os2) {
|
|
|
7302
7307
|
{ timeout: 3e3 }
|
|
7303
7308
|
).toString();
|
|
7304
7309
|
const body = JSON.parse(out);
|
|
7305
|
-
const
|
|
7310
|
+
const oauth = body.claudeAiOauth;
|
|
7311
|
+
const tok = oauth?.accessToken;
|
|
7306
7312
|
if (tok) {
|
|
7307
|
-
const
|
|
7308
|
-
const
|
|
7313
|
+
const email = oauth?.account?.email_address ?? oauth?.account?.email ?? null;
|
|
7314
|
+
const orgName = oauth?.organization?.name ?? null;
|
|
7315
|
+
const stableId = oauth?.account?.uuid ?? oauth?.organization?.uuid ?? (oauth?.refreshToken ?? tok).slice(0, 48);
|
|
7309
7316
|
ids.push({
|
|
7310
7317
|
provider: "anthropic",
|
|
7311
|
-
provider_account_id:
|
|
7312
|
-
provider_account_label:
|
|
7318
|
+
provider_account_id: stableId,
|
|
7319
|
+
provider_account_label: email ?? orgName ?? oauth?.subscriptionType ?? "Claude account",
|
|
7320
|
+
account_email: email,
|
|
7321
|
+
account_org: orgName ?? oauth?.subscriptionType ?? null,
|
|
7322
|
+
display_name: null,
|
|
7313
7323
|
owner_scope: "unassigned",
|
|
7314
7324
|
detection_source: "claude_keychain"
|
|
7315
7325
|
});
|
|
@@ -7328,6 +7338,8 @@ async function probeIdentities(os2) {
|
|
|
7328
7338
|
const jwt = obj.tokens?.id_token;
|
|
7329
7339
|
let email = null;
|
|
7330
7340
|
let sub = null;
|
|
7341
|
+
let name = null;
|
|
7342
|
+
let org = null;
|
|
7331
7343
|
let provider = "openai";
|
|
7332
7344
|
if (jwt) {
|
|
7333
7345
|
const parts = jwt.split(".");
|
|
@@ -7339,17 +7351,23 @@ async function probeIdentities(os2) {
|
|
|
7339
7351
|
);
|
|
7340
7352
|
email = body.email ?? null;
|
|
7341
7353
|
sub = body.sub ?? null;
|
|
7354
|
+
name = body.name ?? null;
|
|
7355
|
+
const oai = body["https://api.openai.com/auth"];
|
|
7356
|
+
org = oai?.organization_id ?? oai?.chatgpt_plan_type ?? null;
|
|
7342
7357
|
if (body.auth_provider === "google") provider = "openai";
|
|
7343
7358
|
} catch {
|
|
7344
7359
|
}
|
|
7345
7360
|
}
|
|
7346
7361
|
}
|
|
7347
|
-
const pid =
|
|
7362
|
+
const pid = obj.tokens?.account_id ?? sub ?? email;
|
|
7348
7363
|
if (pid) {
|
|
7349
7364
|
ids.push({
|
|
7350
7365
|
provider,
|
|
7351
7366
|
provider_account_id: pid,
|
|
7352
7367
|
provider_account_label: email,
|
|
7368
|
+
account_email: email,
|
|
7369
|
+
account_org: org,
|
|
7370
|
+
display_name: name,
|
|
7353
7371
|
owner_scope: "unassigned",
|
|
7354
7372
|
detection_source: "codex_auth_json"
|
|
7355
7373
|
});
|
|
@@ -7371,6 +7389,7 @@ async function probeIdentities(os2) {
|
|
|
7371
7389
|
provider: "google",
|
|
7372
7390
|
provider_account_id: email,
|
|
7373
7391
|
provider_account_label: email,
|
|
7392
|
+
account_email: email,
|
|
7374
7393
|
owner_scope: "unassigned",
|
|
7375
7394
|
detection_source: "gemini_oauth_creds"
|
|
7376
7395
|
});
|
|
@@ -7395,6 +7414,7 @@ async function probeIdentities(os2) {
|
|
|
7395
7414
|
provider: "cursor",
|
|
7396
7415
|
provider_account_id: auth.sub ?? auth.email,
|
|
7397
7416
|
provider_account_label: auth.email ?? null,
|
|
7417
|
+
account_email: auth.email ?? null,
|
|
7398
7418
|
owner_scope: "unassigned",
|
|
7399
7419
|
detection_source: "cursor_global_storage"
|
|
7400
7420
|
});
|
|
@@ -42435,9 +42455,9 @@ var require_range = __commonJS({
|
|
|
42435
42455
|
parseRange(range) {
|
|
42436
42456
|
const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);
|
|
42437
42457
|
const memoKey = memoOpts + ":" + range;
|
|
42438
|
-
const
|
|
42439
|
-
if (
|
|
42440
|
-
return
|
|
42458
|
+
const cached2 = cache.get(memoKey);
|
|
42459
|
+
if (cached2) {
|
|
42460
|
+
return cached2;
|
|
42441
42461
|
}
|
|
42442
42462
|
const loose = this.options.loose;
|
|
42443
42463
|
const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE];
|
|
@@ -44254,17 +44274,17 @@ var init_queue = __esm({
|
|
|
44254
44274
|
});
|
|
44255
44275
|
|
|
44256
44276
|
// ../../packages/companion-core/src/pipeline/prompts.ts
|
|
44257
|
-
var OLLAMA_CHAT_MODEL, OLLAMA_EMBED_MODEL, SUMMARISER_SYSTEM_PROMPT, SUMMARISER_MAX_TOKENS,
|
|
44277
|
+
var OLLAMA_CHAT_MODEL, OLLAMA_EMBED_MODEL, SUMMARISER_SYSTEM_PROMPT, SUMMARISER_MAX_TOKENS, SUMMARISER_TEMPERATURE, QWEN_CHARS_PER_TOKEN, ABSTRACT_OUTPUT_MAX_CHARS;
|
|
44258
44278
|
var init_prompts = __esm({
|
|
44259
44279
|
"../../packages/companion-core/src/pipeline/prompts.ts"() {
|
|
44260
44280
|
"use strict";
|
|
44261
|
-
OLLAMA_CHAT_MODEL = "qwen3
|
|
44281
|
+
OLLAMA_CHAT_MODEL = "qwen3:4b";
|
|
44262
44282
|
OLLAMA_EMBED_MODEL = "bge-small-en-v1.5";
|
|
44263
|
-
SUMMARISER_SYSTEM_PROMPT = "
|
|
44264
|
-
SUMMARISER_MAX_TOKENS =
|
|
44265
|
-
ABSTRACT_OUTPUT_MAX_CHARS = 400;
|
|
44283
|
+
SUMMARISER_SYSTEM_PROMPT = "You summarise an AI coding session in ONE sentence, \u2264 240 characters. If the user message includes sampled conversation excerpts, base your summary on what the developer was actually working on (the substance \u2014 what was being built, debugged, refactored, or designed). If only metadata is given, paraphrase the metadata. Never quote the excerpts verbatim. No PII, no code literals, no file paths, no API keys. Reply with only the sentence.";
|
|
44284
|
+
SUMMARISER_MAX_TOKENS = 120;
|
|
44266
44285
|
SUMMARISER_TEMPERATURE = 0.2;
|
|
44267
44286
|
QWEN_CHARS_PER_TOKEN = 3.3;
|
|
44287
|
+
ABSTRACT_OUTPUT_MAX_CHARS = 240;
|
|
44268
44288
|
}
|
|
44269
44289
|
});
|
|
44270
44290
|
|
|
@@ -44819,6 +44839,14 @@ function ollamaSummarize(cfg = defaultOllamaConfig()) {
|
|
|
44819
44839
|
body: JSON.stringify({
|
|
44820
44840
|
model: cfg.chatModel,
|
|
44821
44841
|
stream: false,
|
|
44842
|
+
// Disable reasoning. qwen3 (the default summariser family) is a
|
|
44843
|
+
// thinking model: with `think` on it spends the entire
|
|
44844
|
+
// `num_predict` budget on a <think> block and returns EMPTY
|
|
44845
|
+
// content, so the summariser saw "" and the whole pipeline
|
|
44846
|
+
// crash-looped at preflight. We only want the final terse
|
|
44847
|
+
// abstract, never the chain-of-thought. Ollama ignores this
|
|
44848
|
+
// field for non-thinking models, so it's safe across families.
|
|
44849
|
+
think: false,
|
|
44822
44850
|
options: {
|
|
44823
44851
|
temperature: SUMMARISER_TEMPERATURE,
|
|
44824
44852
|
num_predict: Math.min(maxTokens, SUMMARISER_MAX_TOKENS)
|
|
@@ -44848,6 +44876,10 @@ function ollamaCognize(cfg = defaultOllamaConfig()) {
|
|
|
44848
44876
|
model: cfg.chatModel,
|
|
44849
44877
|
stream: false,
|
|
44850
44878
|
format: "json",
|
|
44879
|
+
// Same reason as the summariser: no thinking budget, just the
|
|
44880
|
+
// JSON cognition tags. Thinking models otherwise emit a long
|
|
44881
|
+
// <think> block and return empty content.
|
|
44882
|
+
think: false,
|
|
44851
44883
|
options: {
|
|
44852
44884
|
temperature: COGNITION_TEMPERATURE,
|
|
44853
44885
|
num_predict: COGNITION_MAX_TOKENS
|
|
@@ -44985,12 +45017,21 @@ async function loadOnce(cfg) {
|
|
|
44985
45017
|
const modelPath = await ensureLlamaModel(cfg);
|
|
44986
45018
|
const llama = await llamaMod.getLlama();
|
|
44987
45019
|
const model = await llama.loadModel({ modelPath });
|
|
44988
|
-
const
|
|
44989
|
-
|
|
44990
|
-
|
|
45020
|
+
const summariserContext = await model.createContext({
|
|
45021
|
+
contextSize: cfg.contextSize
|
|
45022
|
+
});
|
|
45023
|
+
const cognizerContext = await model.createContext({
|
|
45024
|
+
contextSize: Math.min(cfg.contextSize, 2048)
|
|
45025
|
+
});
|
|
45026
|
+
const summarizer = new llamaMod.LlamaChatSession({
|
|
45027
|
+
contextSequence: summariserContext.getSequence(),
|
|
44991
45028
|
systemPrompt: SUMMARISER_SYSTEM_PROMPT
|
|
44992
45029
|
});
|
|
44993
|
-
|
|
45030
|
+
const cognizer = new llamaMod.LlamaChatSession({
|
|
45031
|
+
contextSequence: cognizerContext.getSequence(),
|
|
45032
|
+
systemPrompt: COGNITION_SYSTEM_PROMPT
|
|
45033
|
+
});
|
|
45034
|
+
loaded = { summarizer, cognizer };
|
|
44994
45035
|
return loaded;
|
|
44995
45036
|
})();
|
|
44996
45037
|
try {
|
|
@@ -45002,11 +45043,11 @@ async function loadOnce(cfg) {
|
|
|
45002
45043
|
}
|
|
45003
45044
|
function llamaSummarize(cfg = defaultLlamaConfig()) {
|
|
45004
45045
|
return async ({ prompt, maxTokens }) => {
|
|
45005
|
-
const {
|
|
45046
|
+
const { summarizer } = await loadOnce(cfg);
|
|
45006
45047
|
const run = inflight.then(async () => {
|
|
45007
|
-
|
|
45048
|
+
summarizer.resetChatHistory();
|
|
45008
45049
|
void maxTokens;
|
|
45009
|
-
const raw = await
|
|
45050
|
+
const raw = await summarizer.prompt(prompt, {
|
|
45010
45051
|
temperature: SUMMARISER_TEMPERATURE,
|
|
45011
45052
|
maxTokens: LLAMA_MAX_TOKENS
|
|
45012
45053
|
});
|
|
@@ -45022,11 +45063,42 @@ function llamaSummarize(cfg = defaultLlamaConfig()) {
|
|
|
45022
45063
|
return run;
|
|
45023
45064
|
};
|
|
45024
45065
|
}
|
|
45066
|
+
function llamaCognize(cfg = defaultLlamaConfig()) {
|
|
45067
|
+
return async ({ abstract }) => {
|
|
45068
|
+
if (!abstract || abstract.trim().length < 12) return null;
|
|
45069
|
+
let loadedSessions;
|
|
45070
|
+
try {
|
|
45071
|
+
loadedSessions = await loadOnce(cfg);
|
|
45072
|
+
} catch {
|
|
45073
|
+
return null;
|
|
45074
|
+
}
|
|
45075
|
+
const { cognizer } = loadedSessions;
|
|
45076
|
+
const run = inflight.then(async () => {
|
|
45077
|
+
cognizer.resetChatHistory();
|
|
45078
|
+
const raw = await cognizer.prompt(buildCognitionUserPrompt(abstract), {
|
|
45079
|
+
temperature: COGNITION_TEMPERATURE,
|
|
45080
|
+
// Qwen3.5 likes to "think" before answering. Give it a small
|
|
45081
|
+
// budget — the JSON answer is ~30 tokens but the thinking can
|
|
45082
|
+
// run 200-400. The strip below removes the <think> block.
|
|
45083
|
+
maxTokens: COGNITION_MAX_TOKENS + 400
|
|
45084
|
+
});
|
|
45085
|
+
const stripped = stripThinking(raw ?? "");
|
|
45086
|
+
return parseCognitionReply(stripped);
|
|
45087
|
+
});
|
|
45088
|
+
inflight = run.catch(() => void 0);
|
|
45089
|
+
try {
|
|
45090
|
+
return await run;
|
|
45091
|
+
} catch {
|
|
45092
|
+
return null;
|
|
45093
|
+
}
|
|
45094
|
+
};
|
|
45095
|
+
}
|
|
45025
45096
|
var DEFAULT_LLAMA_MODEL_URL, LLAMA_MAX_TOKENS, loaded, loadPromise, inflight;
|
|
45026
45097
|
var init_llama = __esm({
|
|
45027
45098
|
"../../packages/companion-core/src/node/llama.ts"() {
|
|
45028
45099
|
"use strict";
|
|
45029
45100
|
init_prompts();
|
|
45101
|
+
init_cognition();
|
|
45030
45102
|
DEFAULT_LLAMA_MODEL_URL = "https://huggingface.co/lmstudio-community/Qwen3.5-4B-GGUF/resolve/main/Qwen3.5-4B-Q4_K_M.gguf";
|
|
45031
45103
|
LLAMA_MAX_TOKENS = 1024;
|
|
45032
45104
|
loaded = null;
|
|
@@ -45035,15 +45107,77 @@ var init_llama = __esm({
|
|
|
45035
45107
|
}
|
|
45036
45108
|
});
|
|
45037
45109
|
|
|
45110
|
+
// ../../packages/companion-core/src/node/transformersjs-embed.ts
|
|
45111
|
+
async function loadPipeline(model) {
|
|
45112
|
+
if (cached) return cached;
|
|
45113
|
+
if (loadFailedPermanently) return null;
|
|
45114
|
+
if (!loadPromise2) {
|
|
45115
|
+
loadPromise2 = (async () => {
|
|
45116
|
+
try {
|
|
45117
|
+
const moduleId = "@huggingface/transformers";
|
|
45118
|
+
const tjs = await import(
|
|
45119
|
+
/* @vite-ignore */
|
|
45120
|
+
moduleId
|
|
45121
|
+
);
|
|
45122
|
+
const p = await tjs.pipeline("feature-extraction", model, {
|
|
45123
|
+
device: "cpu",
|
|
45124
|
+
dtype: "fp32"
|
|
45125
|
+
});
|
|
45126
|
+
cached = p;
|
|
45127
|
+
return p;
|
|
45128
|
+
} catch (err) {
|
|
45129
|
+
const msg = err.message;
|
|
45130
|
+
if (/unsupported|architecture|not supported|onnx|cannot resolve/i.test(msg)) {
|
|
45131
|
+
loadFailedPermanently = true;
|
|
45132
|
+
}
|
|
45133
|
+
console.warn(
|
|
45134
|
+
`[modelstat] transformers.js embedder unavailable (segments will be re-embedded server-side): ${msg}`
|
|
45135
|
+
);
|
|
45136
|
+
loadPromise2 = null;
|
|
45137
|
+
return null;
|
|
45138
|
+
}
|
|
45139
|
+
})();
|
|
45140
|
+
}
|
|
45141
|
+
return loadPromise2;
|
|
45142
|
+
}
|
|
45143
|
+
function createTransformersJsEmbedder(model = DEFAULT_MODEL) {
|
|
45144
|
+
return async (text) => {
|
|
45145
|
+
if (!text || text.trim().length === 0) return [];
|
|
45146
|
+
const pipe = await loadPipeline(model);
|
|
45147
|
+
if (!pipe) return [];
|
|
45148
|
+
try {
|
|
45149
|
+
const out = await pipe(text, { pooling: "mean", normalize: true });
|
|
45150
|
+
return Array.from(out.data);
|
|
45151
|
+
} catch (err) {
|
|
45152
|
+
console.warn(
|
|
45153
|
+
`[modelstat] embed error (returning empty vector, server will re-embed): ${err.message}`
|
|
45154
|
+
);
|
|
45155
|
+
return [];
|
|
45156
|
+
}
|
|
45157
|
+
};
|
|
45158
|
+
}
|
|
45159
|
+
var cached, loadPromise2, loadFailedPermanently, DEFAULT_MODEL;
|
|
45160
|
+
var init_transformersjs_embed = __esm({
|
|
45161
|
+
"../../packages/companion-core/src/node/transformersjs-embed.ts"() {
|
|
45162
|
+
"use strict";
|
|
45163
|
+
cached = null;
|
|
45164
|
+
loadPromise2 = null;
|
|
45165
|
+
loadFailedPermanently = false;
|
|
45166
|
+
DEFAULT_MODEL = "Xenova/bge-small-en-v1.5";
|
|
45167
|
+
}
|
|
45168
|
+
});
|
|
45169
|
+
|
|
45038
45170
|
// ../../packages/companion-core/src/node/index.ts
|
|
45039
45171
|
var node_exports = {};
|
|
45040
45172
|
__export(node_exports, {
|
|
45041
45173
|
DEFAULT_LLAMA_MODEL_URL: () => DEFAULT_LLAMA_MODEL_URL,
|
|
45042
45174
|
FileQueueStore: () => FileQueueStore,
|
|
45043
45175
|
SqliteQueueStore: () => FileQueueStore,
|
|
45176
|
+
createTransformersJsEmbedder: () => createTransformersJsEmbedder,
|
|
45044
45177
|
defaultLlamaConfig: () => defaultLlamaConfig,
|
|
45045
45178
|
defaultOllamaConfig: () => defaultOllamaConfig,
|
|
45046
45179
|
ensureLlamaModel: () => ensureLlamaModel,
|
|
45180
|
+
llamaCognize: () => llamaCognize,
|
|
45047
45181
|
llamaSummarize: () => llamaSummarize,
|
|
45048
45182
|
ollamaCognize: () => ollamaCognize,
|
|
45049
45183
|
ollamaEmbed: () => ollamaEmbed,
|
|
@@ -45057,6 +45191,103 @@ var init_node2 = __esm({
|
|
|
45057
45191
|
init_file_queue_store();
|
|
45058
45192
|
init_ollama();
|
|
45059
45193
|
init_llama();
|
|
45194
|
+
init_transformersjs_embed();
|
|
45195
|
+
}
|
|
45196
|
+
});
|
|
45197
|
+
|
|
45198
|
+
// ../../packages/companion-core/src/redact/privacy-filter.ts
|
|
45199
|
+
async function createPrivacyFilterRedactor(opts = {}) {
|
|
45200
|
+
const isBrowser = typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
|
|
45201
|
+
const device = opts.device ?? (isBrowser ? "webgpu" : "cpu");
|
|
45202
|
+
const dtype = opts.dtype ?? "q4";
|
|
45203
|
+
const modelId = opts.model ?? "openai/privacy-filter";
|
|
45204
|
+
let cached2 = null;
|
|
45205
|
+
let loadPromise3 = null;
|
|
45206
|
+
async function loadPipeline2() {
|
|
45207
|
+
if (cached2) return cached2;
|
|
45208
|
+
if (!loadPromise3) {
|
|
45209
|
+
loadPromise3 = (async () => {
|
|
45210
|
+
try {
|
|
45211
|
+
const moduleId = "@huggingface/transformers";
|
|
45212
|
+
const tjs = await import(
|
|
45213
|
+
/* @vite-ignore */
|
|
45214
|
+
moduleId
|
|
45215
|
+
);
|
|
45216
|
+
const p = await tjs.pipeline("token-classification", modelId, {
|
|
45217
|
+
device,
|
|
45218
|
+
dtype,
|
|
45219
|
+
...opts.onProgress ? { progress_callback: opts.onProgress } : {}
|
|
45220
|
+
});
|
|
45221
|
+
cached2 = p;
|
|
45222
|
+
return p;
|
|
45223
|
+
} catch (err) {
|
|
45224
|
+
loadPromise3 = null;
|
|
45225
|
+
console.warn(
|
|
45226
|
+
"[privacy-filter] adapter unavailable \u2014 install @huggingface/transformers in the consuming package to enable model-based redaction. Falling back to pass-through.",
|
|
45227
|
+
err.message
|
|
45228
|
+
);
|
|
45229
|
+
return null;
|
|
45230
|
+
}
|
|
45231
|
+
})();
|
|
45232
|
+
}
|
|
45233
|
+
return loadPromise3;
|
|
45234
|
+
}
|
|
45235
|
+
return async function redactWithPrivacyFilter(text) {
|
|
45236
|
+
const empty = {
|
|
45237
|
+
text,
|
|
45238
|
+
counts: {
|
|
45239
|
+
secrets_found: 0,
|
|
45240
|
+
emails_redacted: 0,
|
|
45241
|
+
paths_redacted_absolute: 0
|
|
45242
|
+
}
|
|
45243
|
+
};
|
|
45244
|
+
if (!text) return empty;
|
|
45245
|
+
const classify = await loadPipeline2();
|
|
45246
|
+
if (!classify) return empty;
|
|
45247
|
+
let tokens;
|
|
45248
|
+
try {
|
|
45249
|
+
tokens = await classify(text);
|
|
45250
|
+
} catch (err) {
|
|
45251
|
+
console.warn(
|
|
45252
|
+
"[privacy-filter] inference failed, returning input unchanged:",
|
|
45253
|
+
err.message
|
|
45254
|
+
);
|
|
45255
|
+
return empty;
|
|
45256
|
+
}
|
|
45257
|
+
const spans = [];
|
|
45258
|
+
for (const t of tokens) {
|
|
45259
|
+
const ent = t.entity ?? "";
|
|
45260
|
+
if (!ent || ent === "O" || ent === "0") continue;
|
|
45261
|
+
if (t.start == null || t.end == null || t.end <= t.start) continue;
|
|
45262
|
+
const type = ent.replace(/^[BILUE]-/, "").toUpperCase();
|
|
45263
|
+
const last = spans[spans.length - 1];
|
|
45264
|
+
if (last && last.type === type && t.start - last.end <= 2) {
|
|
45265
|
+
last.end = t.end;
|
|
45266
|
+
} else {
|
|
45267
|
+
spans.push({ type, start: t.start, end: t.end });
|
|
45268
|
+
}
|
|
45269
|
+
}
|
|
45270
|
+
spans.sort((a, b) => b.start - a.start);
|
|
45271
|
+
let out = text;
|
|
45272
|
+
const extra = {};
|
|
45273
|
+
for (const s of spans) {
|
|
45274
|
+
extra[`pf_${s.type.toLowerCase()}`] = (extra[`pf_${s.type.toLowerCase()}`] ?? 0) + 1;
|
|
45275
|
+
out = out.slice(0, s.start) + `[REDACTED:${s.type}]` + out.slice(s.end);
|
|
45276
|
+
}
|
|
45277
|
+
return {
|
|
45278
|
+
text: out,
|
|
45279
|
+
counts: {
|
|
45280
|
+
secrets_found: 0,
|
|
45281
|
+
emails_redacted: 0,
|
|
45282
|
+
paths_redacted_absolute: 0,
|
|
45283
|
+
...extra
|
|
45284
|
+
}
|
|
45285
|
+
};
|
|
45286
|
+
};
|
|
45287
|
+
}
|
|
45288
|
+
var init_privacy_filter = __esm({
|
|
45289
|
+
"../../packages/companion-core/src/redact/privacy-filter.ts"() {
|
|
45290
|
+
"use strict";
|
|
45060
45291
|
}
|
|
45061
45292
|
});
|
|
45062
45293
|
|
|
@@ -45080,11 +45311,26 @@ async function probeOllama(baseUrl) {
|
|
|
45080
45311
|
return false;
|
|
45081
45312
|
}
|
|
45082
45313
|
}
|
|
45083
|
-
function bundledAdapters() {
|
|
45314
|
+
async function bundledAdapters() {
|
|
45315
|
+
const llamaCfg = defaultLlamaConfig();
|
|
45084
45316
|
return {
|
|
45085
|
-
|
|
45086
|
-
|
|
45087
|
-
|
|
45317
|
+
// Same transformers.js BGE-small embedder as the Ollama path. The
|
|
45318
|
+
// bundled-llama path used to ship vector-less (empty arrays);
|
|
45319
|
+
// hooking embeddings here means even no-Ollama installs get
|
|
45320
|
+
// proper segment-vs-leaf cosine matching at classify time.
|
|
45321
|
+
embed: createTransformersJsEmbedder(),
|
|
45322
|
+
summarize: llamaSummarize(llamaCfg),
|
|
45323
|
+
tokenize: (text) => Math.max(1, Math.ceil(text.length / 4)),
|
|
45324
|
+
cognize: llamaCognize(llamaCfg),
|
|
45325
|
+
// Model-based PII redactor (OpenAI Privacy Filter via
|
|
45326
|
+
// transformers.js / ONNX). Runs locally on CPU after the regex
|
|
45327
|
+
// pass in packages/core/redact.ts. ~1 GB model downloaded on
|
|
45328
|
+
// first run; subsequent runs reuse the cached weights. The
|
|
45329
|
+
// factory is async because it dynamic-imports
|
|
45330
|
+
// @huggingface/transformers — if the optional peer dep isn't
|
|
45331
|
+
// installed it returns a pass-through redactor (regex pass is
|
|
45332
|
+
// still the last line of defence).
|
|
45333
|
+
redact: await createPrivacyFilterRedactor()
|
|
45088
45334
|
};
|
|
45089
45335
|
}
|
|
45090
45336
|
async function getAdapters() {
|
|
@@ -45097,18 +45343,21 @@ async function getAdapters() {
|
|
|
45097
45343
|
`[modelstat] ollama up at ${ollamaCfg.baseUrl} \u2014 using ${ollamaCfg.chatModel} for summarisation`
|
|
45098
45344
|
);
|
|
45099
45345
|
adapters = {
|
|
45100
|
-
|
|
45346
|
+
// BGE-small via transformers.js — same model the server uses
|
|
45347
|
+
// via fastembed, so segment vectors land in the same 384-dim
|
|
45348
|
+
// space as leaf-description vectors and cosine similarity is
|
|
45349
|
+
// directly meaningful. We do NOT use ollamaEmbed here because
|
|
45350
|
+
// Ollama's library doesn't host bge-small (404 on pull) and
|
|
45351
|
+
// shipping MiniLM-via-Ollama vs BGE-small-server would break
|
|
45352
|
+
// cross-source similarity.
|
|
45353
|
+
embed: createTransformersJsEmbedder(),
|
|
45101
45354
|
summarize: ollamaSummarize(ollamaCfg),
|
|
45102
45355
|
tokenize: ollamaTokenize(),
|
|
45103
|
-
|
|
45104
|
-
//
|
|
45105
|
-
//
|
|
45106
|
-
//
|
|
45107
|
-
|
|
45108
|
-
// doesn't get cognition — it'd require a second model context
|
|
45109
|
-
// and the segment ships fine without the suffix; install Ollama
|
|
45110
|
-
// for emotion tagging.
|
|
45111
|
-
cognize: ollamaCognize(ollamaCfg)
|
|
45356
|
+
cognize: ollamaCognize(ollamaCfg),
|
|
45357
|
+
// Privacy filter — same OpenAI Privacy Filter model regardless
|
|
45358
|
+
// of which summariser/embedder runtime we ended up on. Factory
|
|
45359
|
+
// is async (dynamic-imports @huggingface/transformers).
|
|
45360
|
+
redact: await createPrivacyFilterRedactor()
|
|
45112
45361
|
};
|
|
45113
45362
|
return adapters;
|
|
45114
45363
|
}
|
|
@@ -45122,7 +45371,7 @@ async function getAdapters() {
|
|
|
45122
45371
|
console.log(
|
|
45123
45372
|
"[modelstat] using bundled local summariser (Qwen3.5-4B, runs on this machine)"
|
|
45124
45373
|
);
|
|
45125
|
-
adapters = bundledAdapters();
|
|
45374
|
+
adapters = await bundledAdapters();
|
|
45126
45375
|
return adapters;
|
|
45127
45376
|
}
|
|
45128
45377
|
async function buildSegments(events) {
|
|
@@ -45147,6 +45396,7 @@ var init_pipeline2 = __esm({
|
|
|
45147
45396
|
"use strict";
|
|
45148
45397
|
init_pipeline();
|
|
45149
45398
|
init_node2();
|
|
45399
|
+
init_privacy_filter();
|
|
45150
45400
|
adapters = null;
|
|
45151
45401
|
probed = false;
|
|
45152
45402
|
}
|
|
@@ -45268,7 +45518,7 @@ var init_scan = __esm({
|
|
|
45268
45518
|
init_pipeline2();
|
|
45269
45519
|
init_config2();
|
|
45270
45520
|
init_api();
|
|
45271
|
-
AGENT_VERSION = "agent-0.0.
|
|
45521
|
+
AGENT_VERSION = "agent-0.0.37";
|
|
45272
45522
|
BATCH_MAX_EVENTS = 2e3;
|
|
45273
45523
|
}
|
|
45274
45524
|
});
|
|
@@ -47360,7 +47610,7 @@ var init_daemon = __esm({
|
|
|
47360
47610
|
init_config2();
|
|
47361
47611
|
init_lock();
|
|
47362
47612
|
init_scan();
|
|
47363
|
-
AGENT_VERSION2 = "agent-0.0.
|
|
47613
|
+
AGENT_VERSION2 = "agent-0.0.37";
|
|
47364
47614
|
HEARTBEAT_INTERVAL_MS = 1e4;
|
|
47365
47615
|
SCAN_INTERVAL_MS = 5 * 60 * 1e3;
|
|
47366
47616
|
status = {
|
|
@@ -47568,6 +47818,11 @@ ${programArgs}
|
|
|
47568
47818
|
<key>EnvironmentVariables</key>
|
|
47569
47819
|
<dict>
|
|
47570
47820
|
<key>PATH</key><string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
|
|
47821
|
+
<!-- Heap headroom for the startup scan of a large transcript backlog.
|
|
47822
|
+
Node's default old-space ceiling (~4 GB) OOM-crashed the daemon on
|
|
47823
|
+
big histories; raise it well below typical RAM. Inherited by the
|
|
47824
|
+
tray-spawned 'modelstat start' child too (NODE_OPTIONS propagates). -->
|
|
47825
|
+
<key>NODE_OPTIONS</key><string>--max-old-space-size=8192</string>
|
|
47571
47826
|
</dict>
|
|
47572
47827
|
<key>WorkingDirectory</key><string>${home()}</string>
|
|
47573
47828
|
</dict>
|
|
@@ -47631,6 +47886,10 @@ Wants=network-online.target
|
|
|
47631
47886
|
|
|
47632
47887
|
[Service]
|
|
47633
47888
|
Type=simple
|
|
47889
|
+
# Heap headroom for the startup scan of a large transcript backlog \u2014
|
|
47890
|
+
# Node's default ~4 GB old-space ceiling OOM-crashed the daemon on big
|
|
47891
|
+
# histories.
|
|
47892
|
+
Environment=NODE_OPTIONS=--max-old-space-size=8192
|
|
47634
47893
|
ExecStart=${nodeBinary()} ${cliPath} start
|
|
47635
47894
|
Restart=always
|
|
47636
47895
|
RestartSec=10
|
|
@@ -47785,7 +48044,7 @@ function tryOpenBrowser(url) {
|
|
|
47785
48044
|
return false;
|
|
47786
48045
|
}
|
|
47787
48046
|
}
|
|
47788
|
-
var AGENT_VERSION3 = "agent-0.0.
|
|
48047
|
+
var AGENT_VERSION3 = "agent-0.0.37";
|
|
47789
48048
|
function osFamily() {
|
|
47790
48049
|
const p = platform4();
|
|
47791
48050
|
if (p === "darwin") return "macos";
|