robrain 2.4.11 → 2.6.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/dist/commands/capture.d.ts +96 -0
- package/dist/commands/capture.d.ts.map +1 -0
- package/dist/commands/capture.js +356 -0
- package/dist/commands/capture.js.map +1 -0
- package/dist/commands/capture.test.d.ts +2 -0
- package/dist/commands/capture.test.d.ts.map +1 -0
- package/dist/commands/capture.test.js +105 -0
- package/dist/commands/capture.test.js.map +1 -0
- package/dist/commands/check.d.ts +5 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +15 -0
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/governance.d.ts +32 -0
- package/dist/commands/governance.d.ts.map +1 -0
- package/dist/commands/governance.js +181 -0
- package/dist/commands/governance.js.map +1 -0
- package/dist/commands/governance.test.d.ts +2 -0
- package/dist/commands/governance.test.d.ts.map +1 -0
- package/dist/commands/governance.test.js +42 -0
- package/dist/commands/governance.test.js.map +1 -0
- package/dist/commands/install.js +2 -2
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/projects.d.ts +40 -0
- package/dist/commands/projects.d.ts.map +1 -1
- package/dist/commands/projects.js +168 -2
- package/dist/commands/projects.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +6 -4
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/search.d.ts +34 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +100 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/search.test.d.ts +2 -0
- package/dist/commands/search.test.d.ts.map +1 -0
- package/dist/commands/search.test.js +43 -0
- package/dist/commands/search.test.js.map +1 -0
- package/dist/index.js +119 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/vendor/codex-hooks/user-prompt-submit.mjs +14 -1
- package/vendor/sensing-mcp/dist/index.js +430 -95
- package/vendor/sensing-mcp/package.json +1 -1
- package/vendor/synthesis/dist/index.js +317 -16
- package/vendor/synthesis/package.json +1 -1
|
@@ -6589,22 +6589,26 @@ var require_embeddings = __commonJS({
|
|
|
6589
6589
|
}
|
|
6590
6590
|
};
|
|
6591
6591
|
exports.EmbeddingProviderError = EmbeddingProviderError;
|
|
6592
|
-
async function embed2(text, config3, signal) {
|
|
6593
|
-
let
|
|
6592
|
+
async function embed2(text, config3, signal, onUsage) {
|
|
6593
|
+
let out;
|
|
6594
6594
|
switch (config3.provider) {
|
|
6595
6595
|
case "openai":
|
|
6596
|
-
|
|
6596
|
+
out = await embedOpenAI(text, config3, signal);
|
|
6597
6597
|
break;
|
|
6598
6598
|
case "voyage":
|
|
6599
|
-
|
|
6599
|
+
out = await embedVoyage(text, config3, signal);
|
|
6600
6600
|
break;
|
|
6601
6601
|
case "cohere":
|
|
6602
|
-
|
|
6602
|
+
out = await embedCohere(text, config3, signal);
|
|
6603
6603
|
break;
|
|
6604
6604
|
default:
|
|
6605
6605
|
throw new EmbeddingProviderError(config3.provider, `Unknown embedding provider: ${config3.provider}`);
|
|
6606
6606
|
}
|
|
6607
|
-
|
|
6607
|
+
onUsage?.({ inputTokens: out.inputTokens });
|
|
6608
|
+
return padToLength(out.vector, exports.EMBEDDING_TARGET_DIMS);
|
|
6609
|
+
}
|
|
6610
|
+
function tokenCount(x) {
|
|
6611
|
+
return typeof x === "number" && Number.isFinite(x) && x >= 0 ? Math.round(x) : null;
|
|
6608
6612
|
}
|
|
6609
6613
|
async function embedOpenAI(text, config3, signal) {
|
|
6610
6614
|
const baseUrl = config3.openaiBaseUrl.replace(/\/+$/, "");
|
|
@@ -6624,7 +6628,10 @@ var require_embeddings = __commonJS({
|
|
|
6624
6628
|
})
|
|
6625
6629
|
}, "openai", config3, signal);
|
|
6626
6630
|
const data = await res.json();
|
|
6627
|
-
return
|
|
6631
|
+
return {
|
|
6632
|
+
vector: ensureEmbedding("openai", data.data?.[0]?.embedding),
|
|
6633
|
+
inputTokens: tokenCount(data.usage?.prompt_tokens) ?? tokenCount(data.usage?.total_tokens)
|
|
6634
|
+
};
|
|
6628
6635
|
}
|
|
6629
6636
|
async function embedVoyage(text, config3, signal) {
|
|
6630
6637
|
if (!config3.voyageApiKey) {
|
|
@@ -6642,7 +6649,10 @@ var require_embeddings = __commonJS({
|
|
|
6642
6649
|
})
|
|
6643
6650
|
}, "voyage", config3, signal);
|
|
6644
6651
|
const data = await res.json();
|
|
6645
|
-
return
|
|
6652
|
+
return {
|
|
6653
|
+
vector: ensureEmbedding("voyage", data.data?.[0]?.embedding),
|
|
6654
|
+
inputTokens: tokenCount(data.usage?.total_tokens)
|
|
6655
|
+
};
|
|
6646
6656
|
}
|
|
6647
6657
|
async function embedCohere(text, config3, signal) {
|
|
6648
6658
|
if (!config3.cohereApiKey) {
|
|
@@ -6662,7 +6672,10 @@ var require_embeddings = __commonJS({
|
|
|
6662
6672
|
})
|
|
6663
6673
|
}, "cohere", config3, signal);
|
|
6664
6674
|
const data = await res.json();
|
|
6665
|
-
return
|
|
6675
|
+
return {
|
|
6676
|
+
vector: ensureEmbedding("cohere", data.embeddings?.float?.[0]),
|
|
6677
|
+
inputTokens: tokenCount(data.meta?.billed_units?.input_tokens)
|
|
6678
|
+
};
|
|
6666
6679
|
}
|
|
6667
6680
|
async function fetchEmbedding(url, init, provider, config3, callerSignal) {
|
|
6668
6681
|
let lastDetail = "";
|
|
@@ -7190,16 +7203,179 @@ var require_trust = __commonJS({
|
|
|
7190
7203
|
}
|
|
7191
7204
|
});
|
|
7192
7205
|
|
|
7206
|
+
// ../shared/dist/capture-settings.js
|
|
7207
|
+
var require_capture_settings = __commonJS({
|
|
7208
|
+
"../shared/dist/capture-settings.js"(exports) {
|
|
7209
|
+
"use strict";
|
|
7210
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7211
|
+
exports.DEFAULT_CAPTURE_SETTINGS = exports.DEFAULT_CAPTURE_KIND = exports.CAPTURE_MODES = exports.CAPTURE_KIND_DESCRIPTION_MAX_CHARS = exports.CAPTURE_KIND_NAME_MAX_CHARS = exports.CAPTURE_KINDS_MAX = exports.CAPTURE_INSTRUCTIONS_MAX_CHARS = void 0;
|
|
7212
|
+
exports.isDefaultCaptureSettings = isDefaultCaptureSettings;
|
|
7213
|
+
exports.normalizeKindName = normalizeKindName;
|
|
7214
|
+
exports.applyCaptureSettingsPatch = applyCaptureSettingsPatch;
|
|
7215
|
+
exports.coerceCaptureSettings = coerceCaptureSettings2;
|
|
7216
|
+
exports.subjectTokens = subjectTokens;
|
|
7217
|
+
exports.subjectsMatch = subjectsMatch;
|
|
7218
|
+
exports.effectiveConfidenceMin = effectiveConfidenceMin2;
|
|
7219
|
+
exports.allowedKindNames = allowedKindNames;
|
|
7220
|
+
exports.CAPTURE_INSTRUCTIONS_MAX_CHARS = 2e3;
|
|
7221
|
+
exports.CAPTURE_KINDS_MAX = 8;
|
|
7222
|
+
exports.CAPTURE_KIND_NAME_MAX_CHARS = 32;
|
|
7223
|
+
exports.CAPTURE_KIND_DESCRIPTION_MAX_CHARS = 300;
|
|
7224
|
+
exports.CAPTURE_MODES = ["strict", "broad"];
|
|
7225
|
+
exports.DEFAULT_CAPTURE_KIND = "decision";
|
|
7226
|
+
exports.DEFAULT_CAPTURE_SETTINGS = {
|
|
7227
|
+
instructions: null,
|
|
7228
|
+
mode: "strict",
|
|
7229
|
+
confidence_min: null,
|
|
7230
|
+
kinds: []
|
|
7231
|
+
};
|
|
7232
|
+
function isDefaultCaptureSettings(s) {
|
|
7233
|
+
return s.instructions === null && s.mode === "strict" && s.confidence_min === null && s.kinds.length === 0;
|
|
7234
|
+
}
|
|
7235
|
+
function normalizeKindName(name) {
|
|
7236
|
+
return name.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
7237
|
+
}
|
|
7238
|
+
function applyCaptureSettingsPatch(current, patch) {
|
|
7239
|
+
const errors = [];
|
|
7240
|
+
const next = { ...current, kinds: [...current.kinds] };
|
|
7241
|
+
if (patch.instructions !== void 0) {
|
|
7242
|
+
if (patch.instructions === null || patch.instructions.trim() === "") {
|
|
7243
|
+
next.instructions = null;
|
|
7244
|
+
} else if (typeof patch.instructions !== "string") {
|
|
7245
|
+
errors.push("instructions must be text");
|
|
7246
|
+
} else if (patch.instructions.length > exports.CAPTURE_INSTRUCTIONS_MAX_CHARS) {
|
|
7247
|
+
errors.push(`instructions must be at most ${exports.CAPTURE_INSTRUCTIONS_MAX_CHARS} characters (got ${patch.instructions.length})`);
|
|
7248
|
+
} else {
|
|
7249
|
+
next.instructions = patch.instructions.trim();
|
|
7250
|
+
}
|
|
7251
|
+
}
|
|
7252
|
+
if (patch.mode !== void 0) {
|
|
7253
|
+
const mode = String(patch.mode).trim().toLowerCase();
|
|
7254
|
+
if (exports.CAPTURE_MODES.includes(mode)) {
|
|
7255
|
+
next.mode = mode;
|
|
7256
|
+
} else {
|
|
7257
|
+
errors.push(`mode must be one of: ${exports.CAPTURE_MODES.join(", ")}`);
|
|
7258
|
+
}
|
|
7259
|
+
}
|
|
7260
|
+
if (patch.confidence_min !== void 0) {
|
|
7261
|
+
if (patch.confidence_min === null) {
|
|
7262
|
+
next.confidence_min = null;
|
|
7263
|
+
} else if (typeof patch.confidence_min !== "number" || !Number.isFinite(patch.confidence_min)) {
|
|
7264
|
+
errors.push("confidence_min must be a number between 0 and 1");
|
|
7265
|
+
} else if (patch.confidence_min < 0 || patch.confidence_min > 1) {
|
|
7266
|
+
errors.push("confidence_min must be between 0 and 1");
|
|
7267
|
+
} else {
|
|
7268
|
+
next.confidence_min = Math.round(patch.confidence_min * 100) / 100;
|
|
7269
|
+
}
|
|
7270
|
+
}
|
|
7271
|
+
if (patch.kinds !== void 0) {
|
|
7272
|
+
if (patch.kinds === null) {
|
|
7273
|
+
next.kinds = [];
|
|
7274
|
+
} else if (!Array.isArray(patch.kinds)) {
|
|
7275
|
+
errors.push("kinds must be a list");
|
|
7276
|
+
} else if (patch.kinds.length > exports.CAPTURE_KINDS_MAX) {
|
|
7277
|
+
errors.push(`at most ${exports.CAPTURE_KINDS_MAX} kinds`);
|
|
7278
|
+
} else {
|
|
7279
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7280
|
+
const kinds = [];
|
|
7281
|
+
for (const raw of patch.kinds) {
|
|
7282
|
+
const name = typeof raw?.name === "string" ? normalizeKindName(raw.name) : "";
|
|
7283
|
+
const description = typeof raw?.description === "string" ? raw.description.trim() : "";
|
|
7284
|
+
if (!name) {
|
|
7285
|
+
errors.push("each kind needs a name (letters, digits, - or _)");
|
|
7286
|
+
continue;
|
|
7287
|
+
}
|
|
7288
|
+
if (name.length > exports.CAPTURE_KIND_NAME_MAX_CHARS) {
|
|
7289
|
+
errors.push(`kind name "${name}" is longer than ${exports.CAPTURE_KIND_NAME_MAX_CHARS} characters`);
|
|
7290
|
+
continue;
|
|
7291
|
+
}
|
|
7292
|
+
if (name === exports.DEFAULT_CAPTURE_KIND) {
|
|
7293
|
+
errors.push(`"${exports.DEFAULT_CAPTURE_KIND}" is the built-in kind and cannot be redefined`);
|
|
7294
|
+
continue;
|
|
7295
|
+
}
|
|
7296
|
+
if (!description) {
|
|
7297
|
+
errors.push(`kind "${name}" needs a description so the model knows what to store`);
|
|
7298
|
+
continue;
|
|
7299
|
+
}
|
|
7300
|
+
if (description.length > exports.CAPTURE_KIND_DESCRIPTION_MAX_CHARS) {
|
|
7301
|
+
errors.push(`description for kind "${name}" is longer than ${exports.CAPTURE_KIND_DESCRIPTION_MAX_CHARS} characters`);
|
|
7302
|
+
continue;
|
|
7303
|
+
}
|
|
7304
|
+
if (seen.has(name)) {
|
|
7305
|
+
errors.push(`kind "${name}" is listed twice`);
|
|
7306
|
+
continue;
|
|
7307
|
+
}
|
|
7308
|
+
seen.add(name);
|
|
7309
|
+
kinds.push({ name, description });
|
|
7310
|
+
}
|
|
7311
|
+
next.kinds = kinds;
|
|
7312
|
+
}
|
|
7313
|
+
}
|
|
7314
|
+
return errors.length ? { ok: false, errors } : { ok: true, settings: next };
|
|
7315
|
+
}
|
|
7316
|
+
function coerceCaptureSettings2(raw) {
|
|
7317
|
+
if (!raw || typeof raw !== "object")
|
|
7318
|
+
return { ...exports.DEFAULT_CAPTURE_SETTINGS };
|
|
7319
|
+
const r = raw;
|
|
7320
|
+
const result = applyCaptureSettingsPatch(exports.DEFAULT_CAPTURE_SETTINGS, {
|
|
7321
|
+
instructions: typeof r.instructions === "string" ? r.instructions : null,
|
|
7322
|
+
mode: typeof r.mode === "string" ? r.mode : "strict",
|
|
7323
|
+
confidence_min: typeof r.confidence_min === "number" ? r.confidence_min : null,
|
|
7324
|
+
kinds: Array.isArray(r.kinds) ? r.kinds : []
|
|
7325
|
+
});
|
|
7326
|
+
if (result.ok)
|
|
7327
|
+
return result.settings;
|
|
7328
|
+
const safe = { ...exports.DEFAULT_CAPTURE_SETTINGS };
|
|
7329
|
+
const instructions = applyCaptureSettingsPatch(safe, { instructions: typeof r.instructions === "string" ? r.instructions : null });
|
|
7330
|
+
if (instructions.ok)
|
|
7331
|
+
safe.instructions = instructions.settings.instructions;
|
|
7332
|
+
const mode = applyCaptureSettingsPatch(safe, { mode: typeof r.mode === "string" ? r.mode : "strict" });
|
|
7333
|
+
if (mode.ok)
|
|
7334
|
+
safe.mode = mode.settings.mode;
|
|
7335
|
+
const conf = applyCaptureSettingsPatch(safe, { confidence_min: typeof r.confidence_min === "number" ? r.confidence_min : null });
|
|
7336
|
+
if (conf.ok)
|
|
7337
|
+
safe.confidence_min = conf.settings.confidence_min;
|
|
7338
|
+
const kinds = applyCaptureSettingsPatch(safe, { kinds: Array.isArray(r.kinds) ? r.kinds : [] });
|
|
7339
|
+
if (kinds.ok)
|
|
7340
|
+
safe.kinds = kinds.settings.kinds;
|
|
7341
|
+
return safe;
|
|
7342
|
+
}
|
|
7343
|
+
var SUBJECT_STOPWORDS = /* @__PURE__ */ new Set(["the", "a", "an", "of", "for", "on", "in", "at", "to", "and", "this", "that", "our", "my", "its", "last", "latest", "current"]);
|
|
7344
|
+
function subjectTokens(subject) {
|
|
7345
|
+
return subject.toLowerCase().replace(/[^a-z0-9\s_-]+/g, " ").split(/[\s_-]+/).filter((t) => t.length > 1 && !SUBJECT_STOPWORDS.has(t));
|
|
7346
|
+
}
|
|
7347
|
+
function subjectsMatch(a, b) {
|
|
7348
|
+
const ta = new Set(subjectTokens(a));
|
|
7349
|
+
const tb = new Set(subjectTokens(b));
|
|
7350
|
+
if (ta.size === 0 || tb.size === 0)
|
|
7351
|
+
return false;
|
|
7352
|
+
const [small, large] = ta.size <= tb.size ? [ta, tb] : [tb, ta];
|
|
7353
|
+
for (const t of small)
|
|
7354
|
+
if (!large.has(t))
|
|
7355
|
+
return false;
|
|
7356
|
+
return true;
|
|
7357
|
+
}
|
|
7358
|
+
function effectiveConfidenceMin2(settings, stock) {
|
|
7359
|
+
return settings?.confidence_min ?? stock;
|
|
7360
|
+
}
|
|
7361
|
+
function allowedKindNames(settings) {
|
|
7362
|
+
return [exports.DEFAULT_CAPTURE_KIND, ...(settings?.kinds ?? []).map((k) => k.name)];
|
|
7363
|
+
}
|
|
7364
|
+
}
|
|
7365
|
+
});
|
|
7366
|
+
|
|
7193
7367
|
// ../shared/dist/extract-decision.js
|
|
7194
7368
|
var require_extract_decision = __commonJS({
|
|
7195
7369
|
"../shared/dist/extract-decision.js"(exports) {
|
|
7196
7370
|
"use strict";
|
|
7197
7371
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7198
7372
|
exports.LlmKeyMissingError = exports.SELF_HOSTED_USER_RULE_OVERRIDE = exports.DECISION_EXTRACTION_SYSTEM_PROMPT = void 0;
|
|
7373
|
+
exports.buildCaptureRules = buildCaptureRules;
|
|
7199
7374
|
exports.stripMarkdownJsonFence = stripMarkdownJsonFence;
|
|
7200
7375
|
exports.parseExtractedDecision = parseExtractedDecision;
|
|
7201
7376
|
exports.extractDecisionLlm = extractDecisionLlm2;
|
|
7202
7377
|
var llm_js_1 = require_llm();
|
|
7378
|
+
var capture_settings_js_1 = require_capture_settings();
|
|
7203
7379
|
exports.DECISION_EXTRACTION_SYSTEM_PROMPT = `You extract technical decisions from software development conversations.
|
|
7204
7380
|
|
|
7205
7381
|
A decision includes ANY of the following (not only formal deliberation):
|
|
@@ -7225,6 +7401,23 @@ Fields:
|
|
|
7225
7401
|
Output ONLY valid JSON. If no decision: {"decision": null, "rationale": null, "rejected": [], "confidence": 0}.
|
|
7226
7402
|
Never add explanation outside the JSON.
|
|
7227
7403
|
Schema: {"decision": string|null, "rationale": string|null, "rejected": [{"option": string, "reason": string}], "confidence": number}`;
|
|
7404
|
+
function buildCaptureRules(capture) {
|
|
7405
|
+
if (!capture)
|
|
7406
|
+
return "";
|
|
7407
|
+
const sections = [];
|
|
7408
|
+
if (capture.kinds.length > 0) {
|
|
7409
|
+
const kindLines = capture.kinds.map((k) => `- "${k.name}": ${k.description}`).join("\n");
|
|
7410
|
+
sections.push(`Besides decisions, this project also stores these kinds of memory:
|
|
7411
|
+
${kindLines}
|
|
7412
|
+
The rules above about what is NOT a decision apply only to kind "${capture_settings_js_1.DEFAULT_CAPTURE_KIND}". A turn that contains an entry of one of the listed kinds must be returned even though it contains no decision and nothing durable was committed: set "kind" to that kind's name, put the entry in "entry" as one short factual sentence (what happened, when, with what result), set "subject" to a short stable label for the thing it is about (max 6 words, the same words each time so a newer entry about the same subject replaces the older one), set "confidence" to how sure you are that the turn contains such an entry, and leave "decision" null. When the turn contains a decision, return it as usual with "kind": "${capture_settings_js_1.DEFAULT_CAPTURE_KIND}", "entry": null and "subject": null. Never invent a kind that is not listed.
|
|
7413
|
+
Schema: {"decision": string|null, "rationale": string|null, "rejected": [{"option": string, "reason": string}], "confidence": number, "kind": string, "entry": string|null, "subject": string|null}`);
|
|
7414
|
+
}
|
|
7415
|
+
if (capture.instructions) {
|
|
7416
|
+
sections.push(`Project instructions for what to store (they refine the rules above; the output must stay valid JSON in the schema given):
|
|
7417
|
+
${capture.instructions}`);
|
|
7418
|
+
}
|
|
7419
|
+
return sections.join("\n\n");
|
|
7420
|
+
}
|
|
7228
7421
|
exports.SELF_HOSTED_USER_RULE_OVERRIDE = `User-stated rule wins:
|
|
7229
7422
|
- A durable rule is a standing instruction for future work in this repo or team (e.g. "from now on", "always", "never", "we no longer"). An instruction scoped to the current task, file, or step (e.g. "don't use that file", "stop logging here", "don't add tests for this one") is not durable; apply the rules above to it.
|
|
7230
7423
|
- If the user states a durable rule in this turn, extract that rule even when the assistant refuses it, cites an older rule, or says it will not follow the new one. In that case do not return null, and do not extract the older rule the assistant restates.`;
|
|
@@ -7239,24 +7432,28 @@ Schema: {"decision": string|null, "rationale": string|null, "rejected": [{"optio
|
|
|
7239
7432
|
function stripMarkdownJsonFence(raw) {
|
|
7240
7433
|
return raw.trim().replace(/^```[a-z]*\s*/i, "").replace(/\s*```\s*$/, "").trim();
|
|
7241
7434
|
}
|
|
7242
|
-
function parseExtractedDecision(rawText) {
|
|
7435
|
+
function parseExtractedDecision(rawText, allowedKinds = [capture_settings_js_1.DEFAULT_CAPTURE_KIND]) {
|
|
7243
7436
|
const raw = JSON.parse(stripMarkdownJsonFence(rawText));
|
|
7244
7437
|
const rejected = Array.isArray(raw.rejected) ? raw.rejected.filter((x) => x !== null && typeof x === "object" && typeof x.option === "string" && typeof x.reason === "string") : [];
|
|
7245
7438
|
const confidence = typeof raw.confidence === "number" && Number.isFinite(raw.confidence) ? raw.confidence : 0;
|
|
7439
|
+
const requestedKind = typeof raw.kind === "string" ? (0, capture_settings_js_1.normalizeKindName)(raw.kind) : capture_settings_js_1.DEFAULT_CAPTURE_KIND;
|
|
7440
|
+
const kind = allowedKinds.includes(requestedKind) ? requestedKind : capture_settings_js_1.DEFAULT_CAPTURE_KIND;
|
|
7441
|
+
const subject = kind !== capture_settings_js_1.DEFAULT_CAPTURE_KIND && typeof raw.subject === "string" && raw.subject.trim() ? raw.subject.trim().slice(0, 120) : null;
|
|
7442
|
+
const entry = kind !== capture_settings_js_1.DEFAULT_CAPTURE_KIND && typeof raw.entry === "string" && raw.entry.trim() ? raw.entry.trim() : null;
|
|
7246
7443
|
return {
|
|
7247
|
-
decision: typeof raw.decision === "string" ? raw.decision : null,
|
|
7444
|
+
decision: entry ?? (typeof raw.decision === "string" ? raw.decision : null),
|
|
7248
7445
|
rationale: typeof raw.rationale === "string" ? raw.rationale : null,
|
|
7249
7446
|
rejected,
|
|
7250
|
-
confidence
|
|
7447
|
+
confidence,
|
|
7448
|
+
kind,
|
|
7449
|
+
subject
|
|
7251
7450
|
};
|
|
7252
7451
|
}
|
|
7253
7452
|
async function extractDecisionLlm2(userMessage, claudeReply, cfg) {
|
|
7254
7453
|
const userPrompt = `Session turn:
|
|
7255
7454
|
User: ${userMessage}
|
|
7256
7455
|
Claude: ${claudeReply}`;
|
|
7257
|
-
const systemPrompt = cfg.extraSystemRules
|
|
7258
|
-
|
|
7259
|
-
${cfg.extraSystemRules}` : exports.DECISION_EXTRACTION_SYSTEM_PROMPT;
|
|
7456
|
+
const systemPrompt = [exports.DECISION_EXTRACTION_SYSTEM_PROMPT, cfg.extraSystemRules, buildCaptureRules(cfg.capture)].filter((section) => Boolean(section)).join("\n\n");
|
|
7260
7457
|
let rawText;
|
|
7261
7458
|
if (cfg.provider === "openai") {
|
|
7262
7459
|
const baseUrl = cfg.openaiBaseUrl ?? (0, llm_js_1.resolveOpenAiBaseUrl)();
|
|
@@ -7288,7 +7485,108 @@ ${cfg.extraSystemRules}` : exports.DECISION_EXTRACTION_SYSTEM_PROMPT;
|
|
|
7288
7485
|
temperature: 0
|
|
7289
7486
|
});
|
|
7290
7487
|
}
|
|
7291
|
-
return parseExtractedDecision(rawText);
|
|
7488
|
+
return parseExtractedDecision(rawText, (0, capture_settings_js_1.allowedKindNames)(cfg.capture));
|
|
7489
|
+
}
|
|
7490
|
+
}
|
|
7491
|
+
});
|
|
7492
|
+
|
|
7493
|
+
// ../shared/dist/capture-gate.js
|
|
7494
|
+
var require_capture_gate = __commonJS({
|
|
7495
|
+
"../shared/dist/capture-gate.js"(exports) {
|
|
7496
|
+
"use strict";
|
|
7497
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7498
|
+
exports.BROAD_MODE_MIN_USER_CHARS = exports.DECISION_KEYWORDS = void 0;
|
|
7499
|
+
exports.captureGate = captureGate2;
|
|
7500
|
+
exports.DECISION_KEYWORDS = [
|
|
7501
|
+
"decided",
|
|
7502
|
+
"decision",
|
|
7503
|
+
"going with",
|
|
7504
|
+
"we'll use",
|
|
7505
|
+
"let's use",
|
|
7506
|
+
"instead of",
|
|
7507
|
+
"switched to",
|
|
7508
|
+
"switching to",
|
|
7509
|
+
"rejected",
|
|
7510
|
+
"won't use",
|
|
7511
|
+
"we tried",
|
|
7512
|
+
"too slow",
|
|
7513
|
+
"doesn't work",
|
|
7514
|
+
"went with",
|
|
7515
|
+
"chosen",
|
|
7516
|
+
"settled on",
|
|
7517
|
+
"ruling out",
|
|
7518
|
+
"dropping",
|
|
7519
|
+
"replacing",
|
|
7520
|
+
// Casual commitments / conventions (often no spelled-out alternatives)
|
|
7521
|
+
"standardize",
|
|
7522
|
+
"standardise",
|
|
7523
|
+
"standardizing",
|
|
7524
|
+
"moving to ",
|
|
7525
|
+
"migrate to",
|
|
7526
|
+
"migrate from",
|
|
7527
|
+
"defaults to",
|
|
7528
|
+
"default to",
|
|
7529
|
+
"stick with",
|
|
7530
|
+
"locking in",
|
|
7531
|
+
"lock in"
|
|
7532
|
+
];
|
|
7533
|
+
var AFFIRMATION_PATTERNS = [
|
|
7534
|
+
/\b(yes|yep|yeah|yup|sure)\b/i,
|
|
7535
|
+
/\b(agreed|agree|approved?)\b/i,
|
|
7536
|
+
/\blet['’]s\s+(do|go|use|try|ship|stick|adopt|switch|move|migrate)\b/i,
|
|
7537
|
+
/\b(go|going)\s+with\b/i,
|
|
7538
|
+
/\bsounds\s+good\b/i,
|
|
7539
|
+
/\bdo\s+it\b/i,
|
|
7540
|
+
/\bship\s+it\b/i
|
|
7541
|
+
];
|
|
7542
|
+
var IMPLICIT_ACTION_PATTERNS = [
|
|
7543
|
+
/import .+ from ['"][^'"]+['"]/,
|
|
7544
|
+
/require\(['"][^'"]+['"]\)/,
|
|
7545
|
+
/npm install|pnpm add|yarn add/
|
|
7546
|
+
];
|
|
7547
|
+
var IMPLICIT_USER_COMMITMENT_PATTERNS = [
|
|
7548
|
+
/\blet['’]s\s+(standardize|standardise|use|go with|stick with|adopt)\b/i,
|
|
7549
|
+
/\b(from now on|going forward)\b/i,
|
|
7550
|
+
/\b(always|never)\s+(use|write|add|call|prefer|put|name|run|import|suggest|commit|push|merge|install|mock)\b/i,
|
|
7551
|
+
/\b(don['’]t|do not|stop|no longer)\s+(use|using|write|writing|add|adding|call|calling|suggest|suggesting|import|importing)\b/i
|
|
7552
|
+
];
|
|
7553
|
+
exports.BROAD_MODE_MIN_USER_CHARS = 24;
|
|
7554
|
+
function captureGate2(turn, settings) {
|
|
7555
|
+
const userText = turn.user_message.toLowerCase();
|
|
7556
|
+
const assistantText = turn.claude_reply.toLowerCase();
|
|
7557
|
+
const userAffirmed = AFFIRMATION_PATTERNS.some((p) => p.test(turn.user_message));
|
|
7558
|
+
const keywordInUser = exports.DECISION_KEYWORDS.some((kw) => userText.includes(kw));
|
|
7559
|
+
const keywordInAssistant = !keywordInUser && exports.DECISION_KEYWORDS.some((kw) => assistantText.includes(kw));
|
|
7560
|
+
if (keywordInUser || keywordInAssistant && userAffirmed) {
|
|
7561
|
+
return { reachesModel: true, reason: "keyword" };
|
|
7562
|
+
}
|
|
7563
|
+
const implicitHit = IMPLICIT_ACTION_PATTERNS.some((p) => p.test(`${turn.user_message} ${turn.claude_reply}`)) || IMPLICIT_USER_COMMITMENT_PATTERNS.some((p) => p.test(turn.user_message));
|
|
7564
|
+
if (implicitHit)
|
|
7565
|
+
return { reachesModel: true, reason: "implicit" };
|
|
7566
|
+
if (settings?.mode === "broad" && turn.user_message.trim().length >= exports.BROAD_MODE_MIN_USER_CHARS) {
|
|
7567
|
+
return { reachesModel: true, reason: "broad" };
|
|
7568
|
+
}
|
|
7569
|
+
return { reachesModel: false, reason: "none" };
|
|
7570
|
+
}
|
|
7571
|
+
}
|
|
7572
|
+
});
|
|
7573
|
+
|
|
7574
|
+
// ../shared/dist/author-email.js
|
|
7575
|
+
var require_author_email = __commonJS({
|
|
7576
|
+
"../shared/dist/author-email.js"(exports) {
|
|
7577
|
+
"use strict";
|
|
7578
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7579
|
+
exports.AUTHOR_EMAIL_MAX_CHARS = void 0;
|
|
7580
|
+
exports.normalizeAuthorEmail = normalizeAuthorEmail2;
|
|
7581
|
+
exports.AUTHOR_EMAIL_MAX_CHARS = 254;
|
|
7582
|
+
var AUTHOR_EMAIL_RE = /^[a-z0-9._%+-]{1,64}@[a-z0-9-]+(\.[a-z0-9-]+)+$/;
|
|
7583
|
+
function normalizeAuthorEmail2(raw) {
|
|
7584
|
+
if (typeof raw !== "string")
|
|
7585
|
+
return null;
|
|
7586
|
+
const email2 = raw.trim().toLowerCase();
|
|
7587
|
+
if (!email2 || email2.length > exports.AUTHOR_EMAIL_MAX_CHARS)
|
|
7588
|
+
return null;
|
|
7589
|
+
return AUTHOR_EMAIL_RE.test(email2) ? email2 : null;
|
|
7292
7590
|
}
|
|
7293
7591
|
}
|
|
7294
7592
|
});
|
|
@@ -7336,6 +7634,9 @@ var require_dist = __commonJS({
|
|
|
7336
7634
|
__exportStar(require_veto_match(), exports);
|
|
7337
7635
|
__exportStar(require_trust(), exports);
|
|
7338
7636
|
__exportStar(require_extract_decision(), exports);
|
|
7637
|
+
__exportStar(require_capture_settings(), exports);
|
|
7638
|
+
__exportStar(require_capture_gate(), exports);
|
|
7639
|
+
__exportStar(require_author_email(), exports);
|
|
7339
7640
|
__exportStar(require_db(), exports);
|
|
7340
7641
|
}
|
|
7341
7642
|
});
|
|
@@ -22798,6 +23099,9 @@ var init_config = __esm({
|
|
|
22798
23099
|
perceptionApiUrl: (0, import_shared.normalizeLoopbackUrl)(process.env.PERCEPTION_API_URL ?? "http://127.0.0.1:3001"),
|
|
22799
23100
|
perceptionApiKey: process.env.PERCEPTION_API_KEY ?? "",
|
|
22800
23101
|
// ── Classifier thresholds (optional — tune after instrumenting) ─
|
|
23102
|
+
// DECISION_CONFIDENCE_MIN is this machine's stock value; a project can
|
|
23103
|
+
// override it for everyone with `robrain capture set --min-confidence`,
|
|
23104
|
+
// which wins when set (same for Perception's own re-extraction).
|
|
22801
23105
|
decisionConfidenceMin: Number(process.env.DECISION_CONFIDENCE_MIN ?? 0.6),
|
|
22802
23106
|
decisionConfidenceHigh: Number(process.env.DECISION_CONFIDENCE_HIGH ?? 0.9),
|
|
22803
23107
|
topicShiftThreshold: Number(process.env.TOPIC_SHIFT_THRESHOLD ?? 0.35),
|
|
@@ -22895,23 +23199,65 @@ var init_embeddings = __esm({
|
|
|
22895
23199
|
}
|
|
22896
23200
|
});
|
|
22897
23201
|
|
|
23202
|
+
// src/capture-settings.ts
|
|
23203
|
+
async function fetchCaptureSettings(projectId) {
|
|
23204
|
+
if (!config2.perceptionApiUrl) return { ...import_shared4.DEFAULT_CAPTURE_SETTINGS };
|
|
23205
|
+
try {
|
|
23206
|
+
const res = await fetch(
|
|
23207
|
+
`${config2.perceptionApiUrl}/projects/${encodeURIComponent(projectId)}/capture`,
|
|
23208
|
+
{
|
|
23209
|
+
headers: { Authorization: `Bearer ${config2.perceptionApiKey}` },
|
|
23210
|
+
signal: AbortSignal.timeout(config2.fetchTimeoutMs)
|
|
23211
|
+
}
|
|
23212
|
+
);
|
|
23213
|
+
if (!res.ok) {
|
|
23214
|
+
if (res.status !== 404) {
|
|
23215
|
+
console.error(`[Sensing] capture settings fetch failed for ${projectId}: HTTP ${res.status}`);
|
|
23216
|
+
}
|
|
23217
|
+
return { ...import_shared4.DEFAULT_CAPTURE_SETTINGS };
|
|
23218
|
+
}
|
|
23219
|
+
return (0, import_shared4.coerceCaptureSettings)(await res.json());
|
|
23220
|
+
} catch (err) {
|
|
23221
|
+
console.error("[Sensing] capture settings fetch error:", err);
|
|
23222
|
+
return { ...import_shared4.DEFAULT_CAPTURE_SETTINGS };
|
|
23223
|
+
}
|
|
23224
|
+
}
|
|
23225
|
+
async function getCaptureSettings(projectId) {
|
|
23226
|
+
const hit = cache.get(projectId);
|
|
23227
|
+
if (hit && Date.now() - hit.fetchedAt < CACHE_TTL_MS) return hit.settings;
|
|
23228
|
+
const pending = inFlight.get(projectId);
|
|
23229
|
+
if (pending) return pending;
|
|
23230
|
+
const request = fetchCaptureSettings(projectId).then((settings) => {
|
|
23231
|
+
cache.set(projectId, { settings, fetchedAt: Date.now() });
|
|
23232
|
+
return settings;
|
|
23233
|
+
}).finally(() => inFlight.delete(projectId));
|
|
23234
|
+
inFlight.set(projectId, request);
|
|
23235
|
+
return request;
|
|
23236
|
+
}
|
|
23237
|
+
var import_shared4, CACHE_TTL_MS, cache, inFlight;
|
|
23238
|
+
var init_capture_settings = __esm({
|
|
23239
|
+
"src/capture-settings.ts"() {
|
|
23240
|
+
"use strict";
|
|
23241
|
+
import_shared4 = __toESM(require_dist(), 1);
|
|
23242
|
+
init_config();
|
|
23243
|
+
CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
23244
|
+
cache = /* @__PURE__ */ new Map();
|
|
23245
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
23246
|
+
}
|
|
23247
|
+
});
|
|
23248
|
+
|
|
22898
23249
|
// src/classifiers/index.ts
|
|
22899
23250
|
function getLastClassifierFailure() {
|
|
22900
23251
|
return lastClassifierFailure;
|
|
22901
23252
|
}
|
|
22902
23253
|
async function classifyDecision(turn, projectId) {
|
|
22903
|
-
const
|
|
22904
|
-
const
|
|
22905
|
-
|
|
22906
|
-
const keywordInUser = DECISION_KEYWORDS.some((kw) => userText.includes(kw));
|
|
22907
|
-
const keywordInAssistant = !keywordInUser && DECISION_KEYWORDS.some((kw) => assistantText.includes(kw));
|
|
22908
|
-
const keywordHit = keywordInUser || keywordInAssistant && userAffirmed;
|
|
22909
|
-
const implicitHit = !keywordHit && (IMPLICIT_ACTION_PATTERNS.some((p) => p.test(`${turn.user_message} ${turn.claude_reply}`)) || IMPLICIT_USER_COMMITMENT_PATTERNS.some((p) => p.test(turn.user_message)));
|
|
22910
|
-
if (!keywordHit && !implicitHit) {
|
|
23254
|
+
const capture = await getCaptureSettings(projectId);
|
|
23255
|
+
const gate = (0, import_shared5.captureGate)(turn, capture);
|
|
23256
|
+
if (!gate.reachesModel) {
|
|
22911
23257
|
return null;
|
|
22912
23258
|
}
|
|
22913
|
-
const extracted = await extractDecision(turn);
|
|
22914
|
-
if (!extracted.decision || extracted.confidence < config2.decisionConfidenceMin) {
|
|
23259
|
+
const extracted = await extractDecision(turn, capture);
|
|
23260
|
+
if (!extracted.decision || extracted.confidence < (0, import_shared5.effectiveConfidenceMin)(capture, config2.decisionConfidenceMin)) {
|
|
22915
23261
|
return null;
|
|
22916
23262
|
}
|
|
22917
23263
|
const scope = inferScope(turn, extracted);
|
|
@@ -22924,22 +23270,23 @@ async function classifyDecision(turn, projectId) {
|
|
|
22924
23270
|
extracted
|
|
22925
23271
|
};
|
|
22926
23272
|
}
|
|
22927
|
-
async function extractDecision(turn) {
|
|
23273
|
+
async function extractDecision(turn, capture) {
|
|
22928
23274
|
const empty = () => ({ decision: null, rationale: null, rejected: [], confidence: 0 });
|
|
22929
23275
|
try {
|
|
22930
|
-
const extracted = await (0,
|
|
23276
|
+
const extracted = await (0, import_shared5.extractDecisionLlm)(turn.user_message, turn.claude_reply, {
|
|
22931
23277
|
provider: config2.llmProvider,
|
|
22932
23278
|
anthropicApiKey: config2.anthropicApiKey,
|
|
22933
23279
|
anthropicModel: config2.anthropicModel,
|
|
22934
23280
|
openaiApiKey: config2.openaiApiKey,
|
|
22935
23281
|
openaiModel: config2.openaiLlmModel,
|
|
22936
23282
|
openaiBaseUrl: config2.openaiBaseUrl,
|
|
22937
|
-
extraSystemRules:
|
|
23283
|
+
extraSystemRules: import_shared5.SELF_HOSTED_USER_RULE_OVERRIDE,
|
|
23284
|
+
capture
|
|
22938
23285
|
});
|
|
22939
23286
|
lastClassifierFailure = null;
|
|
22940
23287
|
return extracted;
|
|
22941
23288
|
} catch (err) {
|
|
22942
|
-
if (err instanceof
|
|
23289
|
+
if (err instanceof import_shared5.LlmKeyMissingError) {
|
|
22943
23290
|
console.error(`[Sensing] ${err.message} \u2014 skipping decision extraction`);
|
|
22944
23291
|
return empty();
|
|
22945
23292
|
}
|
|
@@ -23014,73 +23361,56 @@ function clearSessionEmbeddings(sessionId) {
|
|
|
23014
23361
|
embeddingWindows.delete(sessionId);
|
|
23015
23362
|
recentFilesPerSession.delete(sessionId);
|
|
23016
23363
|
}
|
|
23017
|
-
var
|
|
23364
|
+
var import_shared5, lastClassifierFailure, embeddingWindows, recentFilesPerSession;
|
|
23018
23365
|
var init_classifiers = __esm({
|
|
23019
23366
|
"src/classifiers/index.ts"() {
|
|
23020
23367
|
"use strict";
|
|
23021
|
-
|
|
23368
|
+
import_shared5 = __toESM(require_dist(), 1);
|
|
23022
23369
|
init_config();
|
|
23023
23370
|
init_embeddings();
|
|
23371
|
+
init_capture_settings();
|
|
23024
23372
|
lastClassifierFailure = null;
|
|
23025
|
-
DECISION_KEYWORDS = [
|
|
23026
|
-
"decided",
|
|
23027
|
-
"decision",
|
|
23028
|
-
"going with",
|
|
23029
|
-
"we'll use",
|
|
23030
|
-
"let's use",
|
|
23031
|
-
"instead of",
|
|
23032
|
-
"switched to",
|
|
23033
|
-
"switching to",
|
|
23034
|
-
"rejected",
|
|
23035
|
-
"won't use",
|
|
23036
|
-
"we tried",
|
|
23037
|
-
"too slow",
|
|
23038
|
-
"doesn't work",
|
|
23039
|
-
"went with",
|
|
23040
|
-
"chosen",
|
|
23041
|
-
"settled on",
|
|
23042
|
-
"ruling out",
|
|
23043
|
-
"dropping",
|
|
23044
|
-
"replacing",
|
|
23045
|
-
// Casual commitments / conventions (often no spelled-out alternatives)
|
|
23046
|
-
"standardize",
|
|
23047
|
-
"standardise",
|
|
23048
|
-
"standardizing",
|
|
23049
|
-
"moving to ",
|
|
23050
|
-
"migrate to",
|
|
23051
|
-
"migrate from",
|
|
23052
|
-
"defaults to",
|
|
23053
|
-
"default to",
|
|
23054
|
-
"stick with",
|
|
23055
|
-
"locking in",
|
|
23056
|
-
"lock in"
|
|
23057
|
-
];
|
|
23058
|
-
AFFIRMATION_PATTERNS = [
|
|
23059
|
-
/\b(yes|yep|yeah|yup|sure)\b/i,
|
|
23060
|
-
/\b(agreed|agree|approved?)\b/i,
|
|
23061
|
-
/\blet['’]s\s+(do|go|use|try|ship|stick|adopt|switch|move|migrate)\b/i,
|
|
23062
|
-
/\b(go|going)\s+with\b/i,
|
|
23063
|
-
/\bsounds\s+good\b/i,
|
|
23064
|
-
/\bdo\s+it\b/i,
|
|
23065
|
-
/\bship\s+it\b/i
|
|
23066
|
-
];
|
|
23067
|
-
IMPLICIT_ACTION_PATTERNS = [
|
|
23068
|
-
/import .+ from ['"][^'"]+['"]/,
|
|
23069
|
-
/require\(['"][^'"]+['"]\)/,
|
|
23070
|
-
/npm install|pnpm add|yarn add/
|
|
23071
|
-
];
|
|
23072
|
-
IMPLICIT_USER_COMMITMENT_PATTERNS = [
|
|
23073
|
-
/\blet['’]s\s+(standardize|standardise|use|go with|stick with|adopt)\b/i,
|
|
23074
|
-
/\b(from now on|going forward)\b/i,
|
|
23075
|
-
/\b(always|never)\s+(use|write|add|call|prefer|put|name|run|import|suggest|commit|push|merge|install|mock)\b/i,
|
|
23076
|
-
/\b(don['’]t|do not|stop|no longer)\s+(use|using|write|writing|add|adding|call|calling|suggest|suggesting|import|importing)\b/i
|
|
23077
|
-
];
|
|
23078
23373
|
embeddingWindows = /* @__PURE__ */ new Map();
|
|
23079
23374
|
recentFilesPerSession = /* @__PURE__ */ new Map();
|
|
23080
23375
|
}
|
|
23081
23376
|
});
|
|
23082
23377
|
|
|
23378
|
+
// src/author.ts
|
|
23379
|
+
import { execFile } from "node:child_process";
|
|
23380
|
+
function normalizeEmail(raw) {
|
|
23381
|
+
return (0, import_shared6.normalizeAuthorEmail)(raw);
|
|
23382
|
+
}
|
|
23383
|
+
function gitUserEmail(cwd) {
|
|
23384
|
+
return new Promise((resolve) => {
|
|
23385
|
+
try {
|
|
23386
|
+
execFile("git", ["config", "--get", "user.email"], { cwd, timeout: GIT_TIMEOUT_MS }, (err, stdout) => {
|
|
23387
|
+
resolve(err ? null : normalizeEmail(String(stdout)));
|
|
23388
|
+
});
|
|
23389
|
+
} catch {
|
|
23390
|
+
resolve(null);
|
|
23391
|
+
}
|
|
23392
|
+
});
|
|
23393
|
+
}
|
|
23394
|
+
function resolveAuthorEmail(env = process.env, cwd = process.cwd()) {
|
|
23395
|
+
if (!cached2) {
|
|
23396
|
+
cached2 = (async () => normalizeEmail(env.ROBRAIN_AUTHOR_EMAIL) ?? await gitUserEmail(cwd))();
|
|
23397
|
+
}
|
|
23398
|
+
return cached2;
|
|
23399
|
+
}
|
|
23400
|
+
var import_shared6, GIT_TIMEOUT_MS, cached2;
|
|
23401
|
+
var init_author = __esm({
|
|
23402
|
+
"src/author.ts"() {
|
|
23403
|
+
"use strict";
|
|
23404
|
+
import_shared6 = __toESM(require_dist(), 1);
|
|
23405
|
+
GIT_TIMEOUT_MS = 2e3;
|
|
23406
|
+
}
|
|
23407
|
+
});
|
|
23408
|
+
|
|
23083
23409
|
// src/router.ts
|
|
23410
|
+
async function withAuthor(signal) {
|
|
23411
|
+
const authorEmail = await resolveAuthorEmail();
|
|
23412
|
+
return authorEmail ? { ...signal, author_email: authorEmail } : signal;
|
|
23413
|
+
}
|
|
23084
23414
|
function parsePerceptionUserMessage(status, rawText) {
|
|
23085
23415
|
try {
|
|
23086
23416
|
const j = JSON.parse(rawText);
|
|
@@ -23111,7 +23441,7 @@ async function routeDecisionSignal(signal, projectId) {
|
|
|
23111
23441
|
"Authorization": `Bearer ${config2.perceptionApiKey}`,
|
|
23112
23442
|
"X-Project-Id": projectId
|
|
23113
23443
|
},
|
|
23114
|
-
body: JSON.stringify({ signal })
|
|
23444
|
+
body: JSON.stringify({ signal: await withAuthor(signal) })
|
|
23115
23445
|
});
|
|
23116
23446
|
const raw = await res.text();
|
|
23117
23447
|
if (!res.ok) {
|
|
@@ -23186,6 +23516,7 @@ async function routeFlushTurns(turns, projectId) {
|
|
|
23186
23516
|
errors.push("PERCEPTION_API_URL is not set \u2014 flush could not reach Perception.");
|
|
23187
23517
|
return errors;
|
|
23188
23518
|
}
|
|
23519
|
+
const authorEmail = await resolveAuthorEmail();
|
|
23189
23520
|
const signals = turns.map((turn) => ({
|
|
23190
23521
|
signal: {
|
|
23191
23522
|
turn,
|
|
@@ -23193,7 +23524,8 @@ async function routeFlushTurns(turns, projectId) {
|
|
|
23193
23524
|
confidence: 0.5,
|
|
23194
23525
|
files_affected: turn.files_touched,
|
|
23195
23526
|
scope: "team",
|
|
23196
|
-
needs_classification: true
|
|
23527
|
+
needs_classification: true,
|
|
23528
|
+
...authorEmail ? { author_email: authorEmail } : {}
|
|
23197
23529
|
}
|
|
23198
23530
|
}));
|
|
23199
23531
|
await Promise.allSettled(
|
|
@@ -23223,6 +23555,7 @@ var init_router = __esm({
|
|
|
23223
23555
|
"src/router.ts"() {
|
|
23224
23556
|
"use strict";
|
|
23225
23557
|
init_config();
|
|
23558
|
+
init_author();
|
|
23226
23559
|
}
|
|
23227
23560
|
});
|
|
23228
23561
|
|
|
@@ -23364,7 +23697,7 @@ function resolveSessionId(raw) {
|
|
|
23364
23697
|
function buildServer() {
|
|
23365
23698
|
const server = new McpServer({
|
|
23366
23699
|
name: "sensing-mcp",
|
|
23367
|
-
version: "2.
|
|
23700
|
+
version: "2.6.0"
|
|
23368
23701
|
});
|
|
23369
23702
|
server.tool(
|
|
23370
23703
|
"sensing_start_session",
|
|
@@ -23384,6 +23717,7 @@ function buildServer() {
|
|
|
23384
23717
|
const sessionId = resolveSessionId(session_id);
|
|
23385
23718
|
sessionRegistry.register(sessionId, project_id);
|
|
23386
23719
|
const summaryResult = await fetchAlwaysOnSummary(project_id);
|
|
23720
|
+
if (!isThinMode()) void getCaptureSettings(project_id);
|
|
23387
23721
|
console.error(`[Sensing] Session started: ${sessionId} (${project_id})`);
|
|
23388
23722
|
return {
|
|
23389
23723
|
content: [{
|
|
@@ -23431,9 +23765,9 @@ function buildServer() {
|
|
|
23431
23765
|
console.error(`[Sensing] Unknown session adopted: ${session_id} (${session.project_id})`);
|
|
23432
23766
|
}
|
|
23433
23767
|
}
|
|
23434
|
-
const redactedUser = (0,
|
|
23435
|
-
const redactedReply = (0,
|
|
23436
|
-
const secretsRedacted = (0,
|
|
23768
|
+
const redactedUser = (0, import_shared7.redactSecrets)(user_message);
|
|
23769
|
+
const redactedReply = (0, import_shared7.redactSecrets)(claude_reply);
|
|
23770
|
+
const secretsRedacted = (0, import_shared7.totalRedactions)(redactedUser.redactions) + (0, import_shared7.totalRedactions)(redactedReply.redactions);
|
|
23437
23771
|
if (secretsRedacted > 0) {
|
|
23438
23772
|
console.error(`[Sensing] Redacted ${secretsRedacted} secret(s) from turn ${sequence} before buffering`);
|
|
23439
23773
|
}
|
|
@@ -23650,17 +23984,18 @@ async function fetchAlwaysOnSummary(projectId) {
|
|
|
23650
23984
|
return { text: `Project: ${projectId}` };
|
|
23651
23985
|
}
|
|
23652
23986
|
}
|
|
23653
|
-
var
|
|
23987
|
+
var import_shared7, sessionRegistry, lastDecisionShipFailure, pendingConflictNotices;
|
|
23654
23988
|
var init_server3 = __esm({
|
|
23655
23989
|
"src/server.ts"() {
|
|
23656
23990
|
"use strict";
|
|
23657
23991
|
init_mcp();
|
|
23658
23992
|
init_zod();
|
|
23659
|
-
|
|
23993
|
+
import_shared7 = __toESM(require_dist(), 1);
|
|
23660
23994
|
init_buffer();
|
|
23661
23995
|
init_classifiers();
|
|
23662
23996
|
init_router();
|
|
23663
23997
|
init_config();
|
|
23998
|
+
init_capture_settings();
|
|
23664
23999
|
init_pending_notices();
|
|
23665
24000
|
init_session_registry();
|
|
23666
24001
|
sessionRegistry = new SessionRegistry(config2.sessionRegistryPath);
|
|
@@ -23763,8 +24098,8 @@ var StdioServerTransport = class {
|
|
|
23763
24098
|
};
|
|
23764
24099
|
|
|
23765
24100
|
// src/index.ts
|
|
23766
|
-
var
|
|
23767
|
-
(0,
|
|
24101
|
+
var import_shared8 = __toESM(require_dist(), 1);
|
|
24102
|
+
(0, import_shared8.loadEnv)();
|
|
23768
24103
|
process.on("unhandledRejection", (reason) => {
|
|
23769
24104
|
console.error("[Sensing] Unhandled rejection (process kept alive):", reason);
|
|
23770
24105
|
});
|