@inerrata-corporation/errata 2.0.0-dev.36 → 2.0.0-dev.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/errata.mjs +278 -16
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -20608,6 +20608,24 @@ var init_oauth = __esm({
20608
20608
 
20609
20609
  // ../../packages/cloud-client/src/client.ts
20610
20610
  import { randomUUID } from "node:crypto";
20611
+ function wirePerContext(value) {
20612
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
20613
+ const out2 = {};
20614
+ for (const [bucket, entry] of Object.entries(value)) {
20615
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
20616
+ const e = entry;
20617
+ const confirmed = asWireCount(e["confirmed"]);
20618
+ if (confirmed === null) continue;
20619
+ const independent = asWireCount(e["independent"]);
20620
+ const inferredIndependent = asWireCount(e["inferredIndependent"]);
20621
+ out2[bucket] = {
20622
+ confirmed,
20623
+ ...independent !== null ? { independent } : {},
20624
+ ...inferredIndependent !== null ? { inferredIndependent } : {}
20625
+ };
20626
+ }
20627
+ return Object.keys(out2).length > 0 ? out2 : null;
20628
+ }
20611
20629
  function sidecarForNodes(sidecar, nodes) {
20612
20630
  if (!sidecar) return void 0;
20613
20631
  const present = /* @__PURE__ */ new Set();
@@ -20632,32 +20650,152 @@ function toWirePayload(batch, runId) {
20632
20650
  attrs: n.attrs ?? {},
20633
20651
  extractionSource: n.extractionSource
20634
20652
  }));
20635
- const edges = batch.edges.map((e) => ({
20636
- fromCanonicalId: e.from,
20637
- toCanonicalId: e.to,
20638
- type: e.type,
20639
- attrs: {
20640
- ...typeof e.confidence === "number" ? { confidence: clamp012(e.confidence) } : {}
20641
- }
20642
- }));
20653
+ const edges = batch.edges.map((e) => {
20654
+ const perContext = wirePerContext(e.attrs?.["perContext"]);
20655
+ return {
20656
+ fromCanonicalId: e.from,
20657
+ toCanonicalId: e.to,
20658
+ type: e.type,
20659
+ attrs: {
20660
+ ...typeof e.confidence === "number" ? { confidence: clamp012(e.confidence) } : {},
20661
+ ...perContext ? { perContext } : {}
20662
+ }
20663
+ };
20664
+ });
20643
20665
  const symbolSummaries = sidecarForNodes(batch.symbolSummaries, nodes);
20644
20666
  return { runId, source: "daemon", nodes, edges, ...symbolSummaries ? { symbolSummaries } : {} };
20645
20667
  }
20646
20668
  function clamp012(x) {
20647
20669
  return Math.max(0, Math.min(1, x));
20648
20670
  }
20671
+ function compactAttrs(input) {
20672
+ const out2 = {};
20673
+ for (const [key, value] of Object.entries(input)) {
20674
+ if (value !== void 0) out2[key] = value;
20675
+ }
20676
+ return out2;
20677
+ }
20678
+ function textOrThrow(value, field) {
20679
+ const text = value.trim();
20680
+ if (!text) throw new TypeError(`${field} must be a non-empty string`);
20681
+ return text;
20682
+ }
20683
+ function optionalEdgeAttrs(confidence) {
20684
+ return typeof confidence === "number" ? { confidence: clamp012(confidence) } : void 0;
20685
+ }
20686
+ function makeEdge(fromCanonicalId, type, toCanonicalId, confidence) {
20687
+ const attrs = optionalEdgeAttrs(confidence);
20688
+ return {
20689
+ fromCanonicalId,
20690
+ toCanonicalId,
20691
+ type,
20692
+ ...attrs ? { attrs } : {}
20693
+ };
20694
+ }
20695
+ function makeNode(args2) {
20696
+ return {
20697
+ canonicalId: args2.canonicalId,
20698
+ label: args2.label,
20699
+ description: args2.description,
20700
+ attrs: compactAttrs(args2.attrs),
20701
+ extractionSource: "agent-observed",
20702
+ ...args2.validationSource ? { validationSource: args2.validationSource } : {}
20703
+ };
20704
+ }
20705
+ function normalizeProblem(input, opts) {
20706
+ if (typeof input === "string") {
20707
+ return {
20708
+ id: void 0,
20709
+ description: textOrThrow(input, "problem"),
20710
+ kind: opts.problemKind,
20711
+ error: opts.errorMessage?.trim() || void 0,
20712
+ attrs: opts.attrs,
20713
+ confidence: void 0,
20714
+ validationSource: opts.validationSource
20715
+ };
20716
+ }
20717
+ return {
20718
+ id: input.id,
20719
+ description: textOrThrow(input.description, "problem.description"),
20720
+ kind: input.kind,
20721
+ error: input.error?.trim() || void 0,
20722
+ attrs: input.attrs,
20723
+ confidence: input.confidence,
20724
+ validationSource: input.validationSource ?? opts.validationSource
20725
+ };
20726
+ }
20727
+ function normalizeTriage(input) {
20728
+ if (input === void 0) return null;
20729
+ if (typeof input === "string") {
20730
+ return {
20731
+ id: void 0,
20732
+ statement: textOrThrow(input, "triage"),
20733
+ route: void 0,
20734
+ attrs: void 0,
20735
+ confidence: void 0,
20736
+ validationSource: void 0
20737
+ };
20738
+ }
20739
+ return {
20740
+ id: input.id,
20741
+ statement: textOrThrow(input.statement, "triage.statement"),
20742
+ route: input.route,
20743
+ attrs: input.attrs,
20744
+ confidence: input.confidence,
20745
+ validationSource: input.validationSource
20746
+ };
20747
+ }
20748
+ function normalizeRootCause(input) {
20749
+ if (input === void 0) return null;
20750
+ if (typeof input === "string") {
20751
+ return {
20752
+ id: void 0,
20753
+ description: textOrThrow(input, "rootCause"),
20754
+ attrs: void 0,
20755
+ confidence: void 0,
20756
+ validationSource: void 0
20757
+ };
20758
+ }
20759
+ return {
20760
+ id: input.id,
20761
+ description: textOrThrow(input.description, "rootCause.description"),
20762
+ attrs: input.attrs,
20763
+ confidence: input.confidence,
20764
+ validationSource: input.validationSource
20765
+ };
20766
+ }
20767
+ function normalizeSolution(input) {
20768
+ if (input === void 0) return null;
20769
+ if (typeof input === "string") {
20770
+ return {
20771
+ id: void 0,
20772
+ description: textOrThrow(input, "solution"),
20773
+ attrs: void 0,
20774
+ confidence: void 0,
20775
+ validationSource: void 0
20776
+ };
20777
+ }
20778
+ return {
20779
+ id: input.id,
20780
+ description: textOrThrow(input.description, "solution.description"),
20781
+ attrs: input.attrs,
20782
+ confidence: input.confidence,
20783
+ validationSource: input.validationSource
20784
+ };
20785
+ }
20649
20786
  function chunkArray(items, size) {
20650
20787
  if (items.length <= size) return items.length ? [[...items]] : [];
20651
20788
  const out2 = [];
20652
20789
  for (let i2 = 0; i2 < items.length; i2 += size) out2.push(items.slice(i2, i2 + size));
20653
20790
  return out2;
20654
20791
  }
20655
- var INGEST_NODE_CHUNK, CloudClient, CloudError;
20792
+ var asWireCount, INGEST_NODE_CHUNK, CloudClient, CloudError;
20656
20793
  var init_client = __esm({
20657
20794
  "../../packages/cloud-client/src/client.ts"() {
20658
20795
  "use strict";
20659
20796
  init_oauth();
20660
20797
  init_src();
20798
+ asWireCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 ? Math.floor(n) : null;
20661
20799
  INGEST_NODE_CHUNK = 25;
20662
20800
  CloudClient = class {
20663
20801
  baseUrl;
@@ -20762,6 +20900,122 @@ var init_client = __esm({
20762
20900
  async ingestWire(payload) {
20763
20901
  return this.json("POST", "/v2/ingest", payload);
20764
20902
  }
20903
+ /**
20904
+ * SDK v2 graph-native write. It remembers a typed diagnostic spine through
20905
+ * `/v2/ingest` instead of the legacy forum question/answer routes:
20906
+ *
20907
+ * Problem --TRIAGED_BY--> Triage --INDICATES/CONFIRMS--> RootCause
20908
+ * RootCause --FIXED_BY--> Solution
20909
+ *
20910
+ * Shorthand inputs are accepted for low-friction use, but object inputs keep
20911
+ * the graph labels explicit for adapters and agents that already know their
20912
+ * node types.
20913
+ */
20914
+ async remember(problemInput, opts = {}) {
20915
+ const runId = opts.runId ?? randomUUID();
20916
+ const problem = normalizeProblem(problemInput, opts);
20917
+ const triage = normalizeTriage(opts.triage);
20918
+ const rootCause = normalizeRootCause(opts.rootCause);
20919
+ const solution = normalizeSolution(opts.solution);
20920
+ const languageInput = opts.language ?? opts.lang;
20921
+ const language = languageInput ? textOrThrow(languageInput, "language") : void 0;
20922
+ const hasLanguage = language !== void 0;
20923
+ const commonAttrs = compactAttrs({
20924
+ sdk: "cloud-client",
20925
+ sdkVersion: "v2",
20926
+ tags: opts.tags && opts.tags.length > 0 ? [...opts.tags] : void 0,
20927
+ lang: language,
20928
+ model: opts.model,
20929
+ context: opts.context
20930
+ });
20931
+ const problemId = problem.id ?? (problem.kind === "runtime" || problem.error ? identityId({ kind: "RuntimeProblem", error: problem.error ?? problem.description }) : identityId({ kind: "DesignProblem", statement: problem.description }));
20932
+ const nodes = [
20933
+ makeNode({
20934
+ canonicalId: problemId,
20935
+ label: "Problem",
20936
+ description: problem.description,
20937
+ attrs: { ...problem.attrs ?? {}, ...commonAttrs },
20938
+ validationSource: problem.validationSource
20939
+ })
20940
+ ];
20941
+ const edges = [];
20942
+ let triageId;
20943
+ if (triage) {
20944
+ triageId = triage.id ?? identityId({ kind: "Triage", statement: triage.statement });
20945
+ nodes.push(
20946
+ makeNode({
20947
+ canonicalId: triageId,
20948
+ label: "Triage",
20949
+ description: triage.statement,
20950
+ attrs: { ...triage.attrs ?? {}, ...commonAttrs },
20951
+ validationSource: triage.validationSource ?? opts.validationSource
20952
+ })
20953
+ );
20954
+ edges.push(makeEdge(problemId, "TRIAGED_BY", triageId, triage.confidence));
20955
+ }
20956
+ let rootCauseId;
20957
+ if (rootCause) {
20958
+ rootCauseId = rootCause.id ?? genericCanonicalId("dcause", { statement: rootCause.description });
20959
+ nodes.push(
20960
+ makeNode({
20961
+ canonicalId: rootCauseId,
20962
+ label: "RootCause",
20963
+ description: rootCause.description,
20964
+ attrs: { ...rootCause.attrs ?? {}, ...commonAttrs },
20965
+ validationSource: rootCause.validationSource ?? opts.validationSource
20966
+ })
20967
+ );
20968
+ if (triageId) {
20969
+ const routeType = triage?.route === "confirms" ? "CONFIRMS" : "INDICATES";
20970
+ edges.push(makeEdge(triageId, routeType, rootCauseId, rootCause.confidence));
20971
+ } else {
20972
+ edges.push(makeEdge(problemId, "CAUSED_BY", rootCauseId, rootCause.confidence));
20973
+ }
20974
+ }
20975
+ let solutionId;
20976
+ if (solution) {
20977
+ solutionId = solution.id ?? genericCanonicalId("dfix", { problemId: rootCauseId ?? problemId, fix: solution.description });
20978
+ nodes.push(
20979
+ makeNode({
20980
+ canonicalId: solutionId,
20981
+ label: "Solution",
20982
+ description: solution.description,
20983
+ attrs: { ...solution.attrs ?? {}, ...commonAttrs },
20984
+ validationSource: solution.validationSource ?? opts.validationSource
20985
+ })
20986
+ );
20987
+ edges.push(
20988
+ makeEdge(rootCauseId ?? problemId, rootCauseId ? "FIXED_BY" : "SOLVED_BY", solutionId, solution.confidence)
20989
+ );
20990
+ }
20991
+ let languageId;
20992
+ if (hasLanguage) {
20993
+ languageId = languageCanonicalId(language);
20994
+ nodes.push(
20995
+ makeNode({
20996
+ canonicalId: languageId,
20997
+ label: "Language",
20998
+ description: language,
20999
+ attrs: { sdk: "cloud-client", sdkVersion: "v2" },
21000
+ validationSource: opts.validationSource
21001
+ })
21002
+ );
21003
+ edges.push(makeEdge(problemId, "OCCURS_IN", languageId));
21004
+ }
21005
+ const payload = { runId, source: "agent", nodes, edges };
21006
+ const result = await this.ingestWire(payload);
21007
+ return {
21008
+ runId,
21009
+ problemId,
21010
+ ...triageId ? { triageId } : {},
21011
+ ...rootCauseId ? { rootCauseId } : {},
21012
+ ...solutionId ? { solutionId } : {},
21013
+ ...languageId ? { languageId } : {},
21014
+ nodes,
21015
+ edges,
21016
+ result
21017
+ };
21018
+ }
20765
21019
  // ─── reads ─────────────────────────────────────────────────────────
20766
21020
  /** Daemon pull/merge search (`?shape=castalia`): graph nodes reconstructed
20767
21021
  * into local-mergeable CastaliaNodes, marked `attrs.source: 'cloud'` so the
@@ -41397,13 +41651,21 @@ function isSyncableRoute(edge2, shared, triage, ignorePatterns = []) {
41397
41651
  function generalizeRouteForSync(edge2, level) {
41398
41652
  const disc = edge2.attrs["discriminator"];
41399
41653
  const local = edge2.attrs["perContext"] ?? {};
41400
- const confirmed = {};
41401
- for (const [b, c] of Object.entries(local)) confirmed[b] = c.confirmed;
41654
+ const perContext = {};
41655
+ for (const [b, c] of Object.entries(local)) {
41656
+ const independent = c.independent ?? c.contributors?.length;
41657
+ const inferredIndependent = c.inferredIndependent ?? c.inferredContributors?.length;
41658
+ perContext[b] = {
41659
+ confirmed: c.confirmed,
41660
+ ...typeof independent === "number" && independent > 0 ? { independent } : {},
41661
+ ...typeof inferredIndependent === "number" && inferredIndependent > 0 ? { inferredIndependent } : {}
41662
+ };
41663
+ }
41402
41664
  return {
41403
41665
  ...edge2,
41404
41666
  attrs: {
41405
41667
  driftKind: edge2.attrs["driftKind"],
41406
- perContext: confirmed,
41668
+ perContext,
41407
41669
  provisional: false,
41408
41670
  ...typeof disc === "string" && disc.trim() ? { discriminator: generalize(disc, { level }).text } : {}
41409
41671
  },
@@ -42216,7 +42478,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
42216
42478
  }
42217
42479
 
42218
42480
  // src/engine.ts
42219
- var DAEMON_VERSION = true ? "2.0.0-dev.36" : "2.0.0-alpha.0";
42481
+ var DAEMON_VERSION = true ? "2.0.0-dev.38" : "2.0.0-alpha.0";
42220
42482
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
42221
42483
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
42222
42484
  var GIT_OP_MUTE_MS = 4e3;
@@ -45124,7 +45386,7 @@ function parseBurstArgs(args2) {
45124
45386
  // src/login-mode.ts
45125
45387
  var OAUTH_DEFAULT_ENV = "ERRATA_DAEMON_OAUTH_DEFAULT";
45126
45388
  function isDaemonOAuthDefaultEnabled(env2 = process.env) {
45127
- return env2[OAUTH_DEFAULT_ENV] === "1";
45389
+ return env2[OAUTH_DEFAULT_ENV] !== "0";
45128
45390
  }
45129
45391
  function shouldUseOAuthLogin(flags2, env2 = process.env) {
45130
45392
  return Boolean(flags2.oauth || !flags2.device && isDaemonOAuthDefaultEnabled(env2));
@@ -45306,7 +45568,7 @@ Commands:
45306
45568
  Flags: --port N (default 7891)
45307
45569
  mcp Run the MCP stdio server \u2014 the agent's full errata tool
45308
45570
  surface (navigation, problems, claims, burst, health)
45309
- login Sign in with the cloud (device-code by default; --oauth for OAuth)
45571
+ login Sign in with the cloud (OAuth by default; --device for legacy device-code)
45310
45572
  logout Clear local cloud credentials
45311
45573
  sync now Flush outbox to the cloud once
45312
45574
  privacy Show what is collected/scrubbed + your consent state
@@ -45321,7 +45583,7 @@ Commands:
45321
45583
  Environment:
45322
45584
  ERRATA_CLOUD_URL Cloud base URL (default ${DEFAULT_CLOUD_URL})
45323
45585
  ERRATA_ALLOW_DIRECT_V1_CLOUD=1 Allow non-local legacy v1 cloud testing
45324
- ${OAUTH_DEFAULT_ENV}=1 Internal dogfood: plain \`errata login\` uses OAuth
45586
+ ${OAUTH_DEFAULT_ENV}=0 Test/dev escape hatch: plain \`errata login\` uses legacy device-code
45325
45587
  `);
45326
45588
  }
45327
45589
  function resolveHookPort(explicit) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.36",
3
+ "version": "2.0.0-dev.38",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {