@inerrata-corporation/errata 2.0.0-dev.39 → 2.0.0-dev.41
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/errata.mjs +233 -17
- package/package.json +1 -1
- package/pass-worker.mjs +9 -3
package/errata.mjs
CHANGED
|
@@ -18445,7 +18445,7 @@ var init_triage = __esm({
|
|
|
18445
18445
|
// ../../packages/math/src/relevance.ts
|
|
18446
18446
|
function scoreRelevance(input, weights) {
|
|
18447
18447
|
const w = { ...DEFAULT_RELEVANCE_WEIGHTS, ...weights };
|
|
18448
|
-
const semantic = input.semantic
|
|
18448
|
+
const semantic = input.semantic != null ? clamp01((input.semantic - w.semanticFloor) / (1 - w.semanticFloor)) : input.semanticUnknown ? clamp01(w.semanticNeutral) : 1;
|
|
18449
18449
|
const specificity = 1 + w.specificityWeight * clamp01(input.specificity ?? 0);
|
|
18450
18450
|
const centrality = 1 + w.centralityWeight * Math.tanh((input.centrality ?? 0) / w.centralityScale);
|
|
18451
18451
|
const quality = 1 + w.qualityWeight * Math.tanh((input.quality ?? 0) / w.qualityScale);
|
|
@@ -18462,6 +18462,7 @@ var init_relevance = __esm({
|
|
|
18462
18462
|
"use strict";
|
|
18463
18463
|
DEFAULT_RELEVANCE_WEIGHTS = {
|
|
18464
18464
|
semanticFloor: 0.5,
|
|
18465
|
+
semanticNeutral: 0.4,
|
|
18465
18466
|
centralityWeight: 0.5,
|
|
18466
18467
|
centralityScale: 1,
|
|
18467
18468
|
qualityWeight: 0.4,
|
|
@@ -20054,11 +20055,15 @@ function buildSnapshot(opts) {
|
|
|
20054
20055
|
languages: opts.profile.languages.map((name2) => ({ name: name2, node: matchNode(langNodes, name2) })),
|
|
20055
20056
|
packages: opts.profile.stack.map((name2) => ({ name: name2, node: matchNode(pkgNodes, pkgBase(name2)) }))
|
|
20056
20057
|
};
|
|
20058
|
+
const causalNudge = recent.length >= 2 && recent.every(
|
|
20059
|
+
(r) => opts.store.outEdges(r.node.id, ["CAUSED_BY"]).length === 0 && opts.store.inEdges(r.node.id, ["CAUSED_BY"]).length === 0
|
|
20060
|
+
);
|
|
20057
20061
|
return {
|
|
20058
20062
|
profile: opts.profile,
|
|
20059
20063
|
profileContext,
|
|
20060
20064
|
recentProblems: recent,
|
|
20061
20065
|
recentResolved,
|
|
20066
|
+
...causalNudge ? { causalNudge } : {},
|
|
20062
20067
|
motifs,
|
|
20063
20068
|
reviewCount: opts.reviewCount,
|
|
20064
20069
|
reviewUiUrl: opts.reviewUiUrl,
|
|
@@ -20205,6 +20210,11 @@ function renderSnapshot(s) {
|
|
|
20205
20210
|
const surprise = (r.node.cumulativeSurprise ?? 0).toFixed(2);
|
|
20206
20211
|
lines.push(` - observed ${hits}\xD7 \xB7 cumulativeSurprise ${surprise}`);
|
|
20207
20212
|
}
|
|
20213
|
+
if (s.causalNudge) {
|
|
20214
|
+
lines.push(
|
|
20215
|
+
"_None of these problems are causally linked yet \u2014 if one caused another (or your report says so in prose), bind them with `(cause:#slug \u2026)` / `(cause:[handle])`. Trace can only follow edges you declare._"
|
|
20216
|
+
);
|
|
20217
|
+
}
|
|
20208
20218
|
}
|
|
20209
20219
|
if (s.recentResolved.length > 0) {
|
|
20210
20220
|
lines.push("_Recently resolved \u2014 solved here; jumping-off points, not live defects:_");
|
|
@@ -20857,6 +20867,18 @@ var init_client = __esm({
|
|
|
20857
20867
|
async me() {
|
|
20858
20868
|
return this.json("GET", "/v2/me");
|
|
20859
20869
|
}
|
|
20870
|
+
// ─── acting-agent switching (gateway control plane, #898) ───────────
|
|
20871
|
+
/** Agents the authenticated user may act as, plus their default agent.
|
|
20872
|
+
* Authenticated with the caller's console-signed gateway JWT. */
|
|
20873
|
+
async actableAgents() {
|
|
20874
|
+
return this.json("GET", "/api/gate/actable-agents");
|
|
20875
|
+
}
|
|
20876
|
+
/** Mint a fresh gateway JWT stamped with `handle` (authz-checked + audited
|
|
20877
|
+
* server-side). The returned `token` bears the acting-agent identity for
|
|
20878
|
+
* subsequent cloud calls. Authenticated with the caller's base JWT. */
|
|
20879
|
+
async actAs(handle2) {
|
|
20880
|
+
return this.json("POST", "/api/gate/act-as", { handle: handle2 });
|
|
20881
|
+
}
|
|
20860
20882
|
// ─── ingest ────────────────────────────────────────────────────────
|
|
20861
20883
|
/** Upload one outbox batch (projected onto the reconciled wire) and fold
|
|
20862
20884
|
* the per-decision response into flush accounting.
|
|
@@ -21337,7 +21359,8 @@ function defaultConfig() {
|
|
|
21337
21359
|
notifications: true,
|
|
21338
21360
|
onboardedAt: null,
|
|
21339
21361
|
machineId: null,
|
|
21340
|
-
updateChannel: "dev"
|
|
21362
|
+
updateChannel: "dev",
|
|
21363
|
+
activeAgent: null
|
|
21341
21364
|
};
|
|
21342
21365
|
}
|
|
21343
21366
|
function loadConfig() {
|
|
@@ -21348,7 +21371,7 @@ function loadConfig() {
|
|
|
21348
21371
|
saveConfig(cfg);
|
|
21349
21372
|
return cfg;
|
|
21350
21373
|
}
|
|
21351
|
-
const raw2 = readFileSync3(p, "utf8");
|
|
21374
|
+
const raw2 = readFileSync3(p, "utf8").replace(/^\uFEFF/, "");
|
|
21352
21375
|
const parsed = JSON.parse(raw2);
|
|
21353
21376
|
const base = defaultConfig();
|
|
21354
21377
|
return {
|
|
@@ -21372,6 +21395,19 @@ function machineId() {
|
|
|
21372
21395
|
saveConfig({ ...cfg, machineId: id });
|
|
21373
21396
|
return id;
|
|
21374
21397
|
}
|
|
21398
|
+
function getActiveAgent(cfg = loadConfig()) {
|
|
21399
|
+
return cfg.activeAgent ?? null;
|
|
21400
|
+
}
|
|
21401
|
+
function setActiveAgent(agent, cfg = loadConfig()) {
|
|
21402
|
+
const next = { ...cfg, activeAgent: { handle: agent.handle, id: agent.id } };
|
|
21403
|
+
saveConfig(next);
|
|
21404
|
+
return next;
|
|
21405
|
+
}
|
|
21406
|
+
function clearActiveAgent(cfg = loadConfig()) {
|
|
21407
|
+
const next = { ...cfg, activeAgent: null };
|
|
21408
|
+
saveConfig(next);
|
|
21409
|
+
return next;
|
|
21410
|
+
}
|
|
21375
21411
|
var DEFAULT_CLOUD_URL;
|
|
21376
21412
|
var init_config = __esm({
|
|
21377
21413
|
"src/config.ts"() {
|
|
@@ -24557,6 +24593,18 @@ import { mkdirSync as mkdirSync4, existsSync as existsSync6 } from "node:fs";
|
|
|
24557
24593
|
import { homedir as homedir2 } from "node:os";
|
|
24558
24594
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
24559
24595
|
import { createRequire } from "node:module";
|
|
24596
|
+
function semanticFloorFor(version2) {
|
|
24597
|
+
if (version2 === EMBEDDING_VERSION) return 0.25;
|
|
24598
|
+
return 0.5;
|
|
24599
|
+
}
|
|
24600
|
+
function noteHashFallback() {
|
|
24601
|
+
if (warnedHashFallback) return;
|
|
24602
|
+
if (process.env["ERRATA_EMBED_HASH_ONLY"] === "1") return;
|
|
24603
|
+
warnedHashFallback = true;
|
|
24604
|
+
console.warn(
|
|
24605
|
+
`[errata] embedding model unavailable (${lastError?.message ?? "unknown"}) \u2014 falling back to ${EMBEDDING_VERSION} hash vectors; semantic ranking runs at reduced fidelity`
|
|
24606
|
+
);
|
|
24607
|
+
}
|
|
24560
24608
|
function getCacheDir() {
|
|
24561
24609
|
return process.env["ERRATA_MODEL_CACHE"] ?? join4(homedir2(), ".errata", "models");
|
|
24562
24610
|
}
|
|
@@ -24647,6 +24695,7 @@ async function embedBatchWithModelOrHash(texts) {
|
|
|
24647
24695
|
}
|
|
24648
24696
|
} catch {
|
|
24649
24697
|
}
|
|
24698
|
+
noteHashFallback();
|
|
24650
24699
|
return texts.map((t) => {
|
|
24651
24700
|
const v = embed(t);
|
|
24652
24701
|
return { vector: v, version: EMBEDDING_VERSION, dim: v.length };
|
|
@@ -24661,11 +24710,12 @@ async function embedTextWithModelOrHash(text) {
|
|
|
24661
24710
|
const v = await embedTextWithModel(text);
|
|
24662
24711
|
return { vector: v, version: MODEL_EMBEDDING_VERSION, dim: v.length };
|
|
24663
24712
|
} catch {
|
|
24713
|
+
noteHashFallback();
|
|
24664
24714
|
const v = embed(text);
|
|
24665
24715
|
return { vector: v, version: EMBEDDING_VERSION, dim: v.length };
|
|
24666
24716
|
}
|
|
24667
24717
|
}
|
|
24668
|
-
var MODEL_NAME, MODEL_EMBEDDING_DIM, MODEL_EMBEDDING_VERSION, pipelinePromise, lastError;
|
|
24718
|
+
var MODEL_NAME, MODEL_EMBEDDING_DIM, MODEL_EMBEDDING_VERSION, pipelinePromise, lastError, warnedHashFallback;
|
|
24669
24719
|
var init_model = __esm({
|
|
24670
24720
|
"../../packages/embedding/src/model.ts"() {
|
|
24671
24721
|
"use strict";
|
|
@@ -24675,6 +24725,7 @@ var init_model = __esm({
|
|
|
24675
24725
|
MODEL_EMBEDDING_VERSION = "minilm-l6-v2";
|
|
24676
24726
|
pipelinePromise = null;
|
|
24677
24727
|
lastError = null;
|
|
24728
|
+
warnedHashFallback = false;
|
|
24678
24729
|
}
|
|
24679
24730
|
});
|
|
24680
24731
|
|
|
@@ -25834,11 +25885,11 @@ var init_generalizer = __esm({
|
|
|
25834
25885
|
function layerOf(kind) {
|
|
25835
25886
|
return kind === "Technique" ? "technique" : kind === "AntiPattern" ? "antipattern" : "pattern";
|
|
25836
25887
|
}
|
|
25837
|
-
function motifTitle(members, layer) {
|
|
25888
|
+
function motifTitle(members, layer, instanceCount) {
|
|
25838
25889
|
const top = [...members].sort(
|
|
25839
25890
|
(a, b) => b.extractionConfidence - a.extractionConfidence
|
|
25840
25891
|
)[0];
|
|
25841
|
-
return `${layer}: ${top?.description ?? "recurring problem cluster"}`;
|
|
25892
|
+
return `${layer} \xD7${instanceCount} (exemplar): ${top?.description ?? "recurring problem cluster"}`;
|
|
25842
25893
|
}
|
|
25843
25894
|
function classifyMotif(store, instances, promoted) {
|
|
25844
25895
|
if (!promoted || instances.length === 0) return "Pattern";
|
|
@@ -25884,7 +25935,9 @@ function promoteMotifs(store, t) {
|
|
|
25884
25935
|
const motif = {
|
|
25885
25936
|
id: motifId,
|
|
25886
25937
|
label: kind,
|
|
25887
|
-
|
|
25938
|
+
// Refresh the deterministic title every run (exemplar/count/kind drift),
|
|
25939
|
+
// but never clobber a distilled one — a distillation pass owns it then.
|
|
25940
|
+
description: existing?.attrs["titleDistilled"] === true ? existing.description : motifTitle(members, layerOf(kind), instanceCount),
|
|
25888
25941
|
extractionConfidence: d.motifConfidence,
|
|
25889
25942
|
extractionSource: "bko-inferred",
|
|
25890
25943
|
embedding: existing?.embedding ?? [],
|
|
@@ -26095,8 +26148,8 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
26095
26148
|
durationMs: 0,
|
|
26096
26149
|
versionsSeen: {}
|
|
26097
26150
|
};
|
|
26098
|
-
const
|
|
26099
|
-
const currentVersion = probe[0]?.version ?? "unknown";
|
|
26151
|
+
const hashOnly = opts.mode === "hash";
|
|
26152
|
+
const currentVersion = hashOnly ? EMBEDDING_VERSION : (await embedBatchWithModelOrHash(["probe"]))[0]?.version ?? "unknown";
|
|
26100
26153
|
const todo = [];
|
|
26101
26154
|
for (const label of labels) {
|
|
26102
26155
|
for (const node2 of store.findNodesByLabel(label)) {
|
|
@@ -26105,6 +26158,10 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
26105
26158
|
if (existingVersion) {
|
|
26106
26159
|
report.versionsSeen[existingVersion] = (report.versionsSeen[existingVersion] ?? 0) + 1;
|
|
26107
26160
|
}
|
|
26161
|
+
if (hashOnly && node2.embedding.length > 0) {
|
|
26162
|
+
report.skippedFresh++;
|
|
26163
|
+
continue;
|
|
26164
|
+
}
|
|
26108
26165
|
if (!opts.force && existingVersion === currentVersion && node2.embedding.length > 0) {
|
|
26109
26166
|
report.skippedFresh++;
|
|
26110
26167
|
continue;
|
|
@@ -26118,7 +26175,10 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
26118
26175
|
const batch = todo.slice(i2, i2 + BATCH_SIZE);
|
|
26119
26176
|
let results;
|
|
26120
26177
|
try {
|
|
26121
|
-
results =
|
|
26178
|
+
results = hashOnly ? batch.map((b) => {
|
|
26179
|
+
const v = embed(b.text);
|
|
26180
|
+
return { vector: v, version: EMBEDDING_VERSION, dim: v.length };
|
|
26181
|
+
}) : await embedBatchWithModelOrHash(batch.map((b) => b.text));
|
|
26122
26182
|
} catch {
|
|
26123
26183
|
report.failed += batch.length;
|
|
26124
26184
|
continue;
|
|
@@ -26184,12 +26244,15 @@ function nodeFreshness(node2, currentIngestSeq) {
|
|
|
26184
26244
|
}
|
|
26185
26245
|
function scoreCandidate(candidate, ctx = {}, weights) {
|
|
26186
26246
|
const sameVersion = !ctx.seedEmbeddingVersion || !candidate.attrs["embeddingVersion"] || candidate.attrs["embeddingVersion"] === ctx.seedEmbeddingVersion;
|
|
26187
|
-
const
|
|
26247
|
+
const comparable = ctx.seedEmbedding != null && candidate.embedding.length === ctx.seedEmbedding.length && sameVersion;
|
|
26248
|
+
const semantic = comparable ? cosine(ctx.seedEmbedding, candidate.embedding) : void 0;
|
|
26249
|
+
const semanticUnknown = ctx.seedEmbedding != null && !comparable;
|
|
26188
26250
|
const quality = typeof candidate.attrs["effectivenessScore"] === "number" ? candidate.attrs["effectivenessScore"] : void 0;
|
|
26189
26251
|
const trustTier = candidate.attrs["trustTier"];
|
|
26190
26252
|
return scoreRelevance(
|
|
26191
26253
|
{
|
|
26192
26254
|
...semantic !== void 0 ? { semantic } : {},
|
|
26255
|
+
...semanticUnknown ? { semanticUnknown } : {},
|
|
26193
26256
|
centrality: candidate.pageRank,
|
|
26194
26257
|
...quality !== void 0 ? { quality } : {},
|
|
26195
26258
|
...ctx.specificity !== void 0 ? { specificity: ctx.specificity } : {},
|
|
@@ -26209,7 +26272,11 @@ function rankByRelevance(store, seedId, candidateIds, opts = {}) {
|
|
|
26209
26272
|
};
|
|
26210
26273
|
const nodes = candidateIds.map((id) => store.getNode(id)).filter((n) => n != null);
|
|
26211
26274
|
const maxPr = Math.max(1e-9, ...nodes.map((n) => n.pageRank));
|
|
26212
|
-
const weights = {
|
|
26275
|
+
const weights = {
|
|
26276
|
+
centralityScale: maxPr,
|
|
26277
|
+
...ctx.seedEmbedding ? { semanticFloor: semanticFloorFor(ctx.seedEmbeddingVersion) } : {},
|
|
26278
|
+
...opts.weights
|
|
26279
|
+
};
|
|
26213
26280
|
const now = store.currentIngestSeq();
|
|
26214
26281
|
return nodes.map((node2) => {
|
|
26215
26282
|
const r = scoreCandidate(node2, { ...ctx, decay: nodeFreshness(node2, now) }, weights);
|
|
@@ -26244,7 +26311,11 @@ function localBurst(store, seedId, opts = {}) {
|
|
|
26244
26311
|
const gated = seed.embedding.length > 0;
|
|
26245
26312
|
const nodes = [...hopOf.entries()].map(([id, hops]) => ({ node: store.getNode(id), hops })).filter((x) => x.node != null);
|
|
26246
26313
|
const maxPr = Math.max(1e-9, ...nodes.map((x) => x.node.pageRank));
|
|
26247
|
-
const weights = {
|
|
26314
|
+
const weights = {
|
|
26315
|
+
centralityScale: maxPr,
|
|
26316
|
+
...gated ? { semanticFloor: semanticFloorFor(ctxSeed.seedEmbeddingVersion) } : {},
|
|
26317
|
+
...opts.weights
|
|
26318
|
+
};
|
|
26248
26319
|
const now = store.currentIngestSeq();
|
|
26249
26320
|
return nodes.map(({ node: node2, hops }) => {
|
|
26250
26321
|
const r = scoreCandidate(node2, { ...ctxSeed, hops, decay: nodeFreshness(node2, now) }, weights);
|
|
@@ -37436,8 +37507,8 @@ function buildWebUi(deps) {
|
|
|
37436
37507
|
const arrText = Array.isArray(respObj["content"]) ? respObj["content"].map(
|
|
37437
37508
|
(c2) => c2 && typeof c2 === "object" && typeof c2["text"] === "string" ? c2["text"] : ""
|
|
37438
37509
|
).join("\n") : "";
|
|
37439
|
-
const
|
|
37440
|
-
const errorTokens =
|
|
37510
|
+
const errText2 = typeof rawResp === "string" ? rawResp : typeof respObj["error"] === "string" ? respObj["error"] : typeof respObj["message"] === "string" ? respObj["message"] : typeof respObj["stderr"] === "string" ? respObj["stderr"] : typeof respObj["content"] === "string" ? respObj["content"] : arrText;
|
|
37511
|
+
const errorTokens = errText2.split(/\r?\n/).map((l) => l.trim()).filter(Boolean).slice(0, 20);
|
|
37441
37512
|
if (errorTokens.length > 0) {
|
|
37442
37513
|
deps.onToolError({
|
|
37443
37514
|
tool,
|
|
@@ -37446,7 +37517,7 @@ function buildWebUi(deps) {
|
|
|
37446
37517
|
exitCode: numericExit ?? 1,
|
|
37447
37518
|
ts: Date.now()
|
|
37448
37519
|
});
|
|
37449
|
-
recallCtx = recallForError(deps.store,
|
|
37520
|
+
recallCtx = recallForError(deps.store, errText2);
|
|
37450
37521
|
}
|
|
37451
37522
|
}
|
|
37452
37523
|
}
|
|
@@ -42478,7 +42549,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
42478
42549
|
}
|
|
42479
42550
|
|
|
42480
42551
|
// src/engine.ts
|
|
42481
|
-
var DAEMON_VERSION = true ? "2.0.0-dev.
|
|
42552
|
+
var DAEMON_VERSION = true ? "2.0.0-dev.41" : "2.0.0-alpha.0";
|
|
42482
42553
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
42483
42554
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
42484
42555
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -43506,6 +43577,16 @@ function createWorkspaceEngine(opts) {
|
|
|
43506
43577
|
telemetry.count("problems_resolved", gen.problemsResolved);
|
|
43507
43578
|
telemetry.count("reviews_triggered", gen.reviewsTriggered);
|
|
43508
43579
|
telemetry.count("signals_credited", report.signalsCredited);
|
|
43580
|
+
if (gen.problemsWritten > 0) {
|
|
43581
|
+
try {
|
|
43582
|
+
const inline = await embedSemanticNodes(store, { mode: "hash" });
|
|
43583
|
+
if (inline.embedded > 0) {
|
|
43584
|
+
console.log(`[errata] inline-embedded ${inline.embedded} fresh semantic node(s) (hash)`);
|
|
43585
|
+
}
|
|
43586
|
+
} catch (err2) {
|
|
43587
|
+
console.warn("[errata] inline semantic embed failed:", err2 instanceof Error ? err2.message : err2);
|
|
43588
|
+
}
|
|
43589
|
+
}
|
|
43509
43590
|
const graphChanged = gen.problemsWritten + gen.problemsResolved + gen.problemsReinforced + gen.reviewsTriggered + report.signalsCredited > 0;
|
|
43510
43591
|
if (!opts.skipContextWriter && (graphChanged || contextDirty)) {
|
|
43511
43592
|
refreshContextNow();
|
|
@@ -45202,6 +45283,114 @@ init_src4();
|
|
|
45202
45283
|
init_config();
|
|
45203
45284
|
init_src6();
|
|
45204
45285
|
init_cloud_auth();
|
|
45286
|
+
|
|
45287
|
+
// src/agent-switch.ts
|
|
45288
|
+
function parseUseArgs(args2) {
|
|
45289
|
+
const positional = [];
|
|
45290
|
+
let clear = false;
|
|
45291
|
+
for (const arg of args2) {
|
|
45292
|
+
if (arg === "--none" || arg === "--clear") {
|
|
45293
|
+
clear = true;
|
|
45294
|
+
continue;
|
|
45295
|
+
}
|
|
45296
|
+
if (arg.startsWith("--")) continue;
|
|
45297
|
+
positional.push(arg);
|
|
45298
|
+
}
|
|
45299
|
+
if (clear) return { kind: "clear" };
|
|
45300
|
+
const handle2 = positional[0];
|
|
45301
|
+
if (!handle2) return { kind: "show" };
|
|
45302
|
+
return { kind: "set", handle: handle2 };
|
|
45303
|
+
}
|
|
45304
|
+
function normalizeHandle(handle2) {
|
|
45305
|
+
return handle2.trim().replace(/^@/, "").toLowerCase();
|
|
45306
|
+
}
|
|
45307
|
+
function findActable(agents, handle2) {
|
|
45308
|
+
const want = normalizeHandle(handle2);
|
|
45309
|
+
return agents.find((a) => normalizeHandle(a.handle) === want) ?? null;
|
|
45310
|
+
}
|
|
45311
|
+
async function runUse(action, ctx) {
|
|
45312
|
+
switch (action.kind) {
|
|
45313
|
+
case "clear":
|
|
45314
|
+
return runClear(ctx);
|
|
45315
|
+
case "show":
|
|
45316
|
+
return runShow(ctx);
|
|
45317
|
+
case "set":
|
|
45318
|
+
return runSet(action.handle, ctx);
|
|
45319
|
+
}
|
|
45320
|
+
}
|
|
45321
|
+
function runClear(ctx) {
|
|
45322
|
+
const active = ctx.getActiveAgent();
|
|
45323
|
+
ctx.clearActiveAgent();
|
|
45324
|
+
if (active) {
|
|
45325
|
+
ctx.log(`no longer acting as ${active.handle} \u2014 the daemon acts as your default identity`);
|
|
45326
|
+
} else {
|
|
45327
|
+
ctx.log(`already on the default identity \u2014 nothing to clear`);
|
|
45328
|
+
}
|
|
45329
|
+
return 0;
|
|
45330
|
+
}
|
|
45331
|
+
async function runShow(ctx) {
|
|
45332
|
+
const active = ctx.getActiveAgent();
|
|
45333
|
+
ctx.log(active ? `active agent: ${active.handle} (id ${active.id})` : `active agent: (default identity)`);
|
|
45334
|
+
if (!ctx.loggedIn) {
|
|
45335
|
+
ctx.log(` log in to list the agents you can act as: errata login`);
|
|
45336
|
+
return 0;
|
|
45337
|
+
}
|
|
45338
|
+
let resp;
|
|
45339
|
+
try {
|
|
45340
|
+
resp = await ctx.actableAgents();
|
|
45341
|
+
} catch (err2) {
|
|
45342
|
+
ctx.log(` couldn't list actable agents: ${errText(err2)}`);
|
|
45343
|
+
return 1;
|
|
45344
|
+
}
|
|
45345
|
+
printActable(resp, active, ctx);
|
|
45346
|
+
return 0;
|
|
45347
|
+
}
|
|
45348
|
+
async function runSet(handle2, ctx) {
|
|
45349
|
+
if (!ctx.loggedIn) {
|
|
45350
|
+
ctx.log(`not logged in \u2014 run \`errata login\` first, then \`errata use ${handle2}\``);
|
|
45351
|
+
return 1;
|
|
45352
|
+
}
|
|
45353
|
+
let resp;
|
|
45354
|
+
try {
|
|
45355
|
+
resp = await ctx.actableAgents();
|
|
45356
|
+
} catch (err2) {
|
|
45357
|
+
ctx.log(`couldn't verify \`${handle2}\`: ${errText(err2)}`);
|
|
45358
|
+
return 1;
|
|
45359
|
+
}
|
|
45360
|
+
const match2 = findActable(resp.agents, handle2);
|
|
45361
|
+
if (!match2) {
|
|
45362
|
+
ctx.log(`unknown agent: ${handle2}`);
|
|
45363
|
+
if (resp.agents.length === 0) {
|
|
45364
|
+
ctx.log(` you can't act as any agents yet.`);
|
|
45365
|
+
} else {
|
|
45366
|
+
ctx.log(` agents you can act as: ${resp.agents.map((a) => a.handle).join(", ")}`);
|
|
45367
|
+
}
|
|
45368
|
+
return 2;
|
|
45369
|
+
}
|
|
45370
|
+
ctx.setActiveAgent({ handle: match2.handle, id: match2.id });
|
|
45371
|
+
ctx.log(`now acting as ${match2.handle} (id ${match2.id}) \u2014 saved; persists across daemon restarts`);
|
|
45372
|
+
return 0;
|
|
45373
|
+
}
|
|
45374
|
+
function printActable(resp, active, ctx) {
|
|
45375
|
+
if (resp.agents.length === 0) {
|
|
45376
|
+
ctx.log(` (no agents you can act as)`);
|
|
45377
|
+
return;
|
|
45378
|
+
}
|
|
45379
|
+
ctx.log(` agents you can act as:`);
|
|
45380
|
+
for (const a of resp.agents) {
|
|
45381
|
+
const marks = [];
|
|
45382
|
+
if (active && a.id === active.id) marks.push("active");
|
|
45383
|
+
if (a.id === resp.defaultAgentId) marks.push("default");
|
|
45384
|
+
const suffix = marks.length ? ` (${marks.join(", ")})` : "";
|
|
45385
|
+
const scope = a.scope ? ` \xB7 ${a.scope}` : "";
|
|
45386
|
+
ctx.log(` ${a.handle}${scope}${suffix}`);
|
|
45387
|
+
}
|
|
45388
|
+
}
|
|
45389
|
+
function errText(err2) {
|
|
45390
|
+
return err2 instanceof Error ? err2.message : String(err2);
|
|
45391
|
+
}
|
|
45392
|
+
|
|
45393
|
+
// src/cli.ts
|
|
45205
45394
|
init_cloud_endpoint_policy();
|
|
45206
45395
|
|
|
45207
45396
|
// src/oauth-login.ts
|
|
@@ -45446,6 +45635,8 @@ async function main() {
|
|
|
45446
45635
|
return cmdLogin();
|
|
45447
45636
|
case "logout":
|
|
45448
45637
|
return cmdLogout();
|
|
45638
|
+
case "use":
|
|
45639
|
+
return cmdUse(rest);
|
|
45449
45640
|
case "review":
|
|
45450
45641
|
return cmdReview();
|
|
45451
45642
|
case "tick":
|
|
@@ -45570,6 +45761,9 @@ Commands:
|
|
|
45570
45761
|
surface (navigation, problems, claims, burst, health)
|
|
45571
45762
|
login Sign in with the cloud (OAuth by default; --device for legacy device-code)
|
|
45572
45763
|
logout Clear local cloud credentials
|
|
45764
|
+
use [<handle>] Set the sticky session active agent the daemon acts as.
|
|
45765
|
+
No arg lists the agents you can act as + the current one;
|
|
45766
|
+
--none (or --clear) reverts to your default identity.
|
|
45573
45767
|
sync now Flush outbox to the cloud once
|
|
45574
45768
|
privacy Show what is collected/scrubbed + your consent state
|
|
45575
45769
|
consent <channel> <on|off>
|
|
@@ -45772,6 +45966,10 @@ async function cmdStatus() {
|
|
|
45772
45966
|
console.log(` cloud:`);
|
|
45773
45967
|
console.log(` url: ${cfg.cloudUrl}`);
|
|
45774
45968
|
console.log(` logged in: ${hasCloudCredential(cfg) ? `yes (${cfg.email})` : "no"}`);
|
|
45969
|
+
const active = getActiveAgent(cfg);
|
|
45970
|
+
console.log(
|
|
45971
|
+
` active agent: ${active ? `${active.handle} (acting-as; \`errata use --none\` to clear)` : "default identity"}`
|
|
45972
|
+
);
|
|
45775
45973
|
const inspection = await inspectCloudEndpoint(cfg.cloudUrl);
|
|
45776
45974
|
const decision = evaluateCloudEndpoint(cfg.cloudUrl, inspection);
|
|
45777
45975
|
const service = inspection.service ? ` \xB7 service ${inspection.service}` : "";
|
|
@@ -46048,6 +46246,24 @@ async function cmdLogout() {
|
|
|
46048
46246
|
saveConfig(cfg);
|
|
46049
46247
|
console.log(`logged out`);
|
|
46050
46248
|
}
|
|
46249
|
+
async function cmdUse(args2) {
|
|
46250
|
+
const cfg = loadConfig();
|
|
46251
|
+
const action = parseUseArgs(args2);
|
|
46252
|
+
const ctx = {
|
|
46253
|
+
loggedIn: hasCloudCredential(cfg),
|
|
46254
|
+
actableAgents: () => authedCloudClient(loadConfig()).actableAgents(),
|
|
46255
|
+
getActiveAgent: () => getActiveAgent(),
|
|
46256
|
+
setActiveAgent: (agent) => {
|
|
46257
|
+
setActiveAgent(agent);
|
|
46258
|
+
},
|
|
46259
|
+
clearActiveAgent: () => {
|
|
46260
|
+
clearActiveAgent();
|
|
46261
|
+
},
|
|
46262
|
+
log: (line) => console.log(line)
|
|
46263
|
+
};
|
|
46264
|
+
const code = await runUse(action, ctx);
|
|
46265
|
+
if (code !== 0) process.exitCode = code;
|
|
46266
|
+
}
|
|
46051
46267
|
async function cmdReview() {
|
|
46052
46268
|
const paths = workspacePaths(ROOT);
|
|
46053
46269
|
if (!existsSync20(paths.reviewQueue)) {
|
package/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -25393,11 +25393,11 @@ var MEMBER_LABELS = ["Problem", "RootCause", "Solution"];
|
|
|
25393
25393
|
function layerOf(kind) {
|
|
25394
25394
|
return kind === "Technique" ? "technique" : kind === "AntiPattern" ? "antipattern" : "pattern";
|
|
25395
25395
|
}
|
|
25396
|
-
function motifTitle(members, layer) {
|
|
25396
|
+
function motifTitle(members, layer, instanceCount) {
|
|
25397
25397
|
const top = [...members].sort(
|
|
25398
25398
|
(a, b) => b.extractionConfidence - a.extractionConfidence
|
|
25399
25399
|
)[0];
|
|
25400
|
-
return `${layer}: ${top?.description ?? "recurring problem cluster"}`;
|
|
25400
|
+
return `${layer} \xD7${instanceCount} (exemplar): ${top?.description ?? "recurring problem cluster"}`;
|
|
25401
25401
|
}
|
|
25402
25402
|
function classifyMotif(store2, instances, promoted) {
|
|
25403
25403
|
if (!promoted || instances.length === 0) return "Pattern";
|
|
@@ -25443,7 +25443,9 @@ function promoteMotifs(store2, t) {
|
|
|
25443
25443
|
const motif = {
|
|
25444
25444
|
id: motifId,
|
|
25445
25445
|
label: kind,
|
|
25446
|
-
|
|
25446
|
+
// Refresh the deterministic title every run (exemplar/count/kind drift),
|
|
25447
|
+
// but never clobber a distilled one — a distillation pass owns it then.
|
|
25448
|
+
description: existing?.attrs["titleDistilled"] === true ? existing.description : motifTitle(members, layerOf(kind), instanceCount),
|
|
25447
25449
|
extractionConfidence: d.motifConfidence,
|
|
25448
25450
|
extractionSource: "bko-inferred",
|
|
25449
25451
|
embedding: existing?.embedding ?? [],
|
|
@@ -25681,11 +25683,15 @@ function buildSnapshot(opts) {
|
|
|
25681
25683
|
languages: opts.profile.languages.map((name2) => ({ name: name2, node: matchNode(langNodes, name2) })),
|
|
25682
25684
|
packages: opts.profile.stack.map((name2) => ({ name: name2, node: matchNode(pkgNodes, pkgBase(name2)) }))
|
|
25683
25685
|
};
|
|
25686
|
+
const causalNudge = recent.length >= 2 && recent.every(
|
|
25687
|
+
(r) => opts.store.outEdges(r.node.id, ["CAUSED_BY"]).length === 0 && opts.store.inEdges(r.node.id, ["CAUSED_BY"]).length === 0
|
|
25688
|
+
);
|
|
25684
25689
|
return {
|
|
25685
25690
|
profile: opts.profile,
|
|
25686
25691
|
profileContext,
|
|
25687
25692
|
recentProblems: recent,
|
|
25688
25693
|
recentResolved,
|
|
25694
|
+
...causalNudge ? { causalNudge } : {},
|
|
25689
25695
|
motifs,
|
|
25690
25696
|
reviewCount: opts.reviewCount,
|
|
25691
25697
|
reviewUiUrl: opts.reviewUiUrl,
|