@inerrata-corporation/errata 2.0.6-dev.2511 → 2.0.6-dev.2550

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/README.txt CHANGED
@@ -25,6 +25,28 @@ USE
25
25
 
26
26
  Dashboard: http://127.0.0.1:7891
27
27
 
28
+ CODEX
29
+
30
+ errata install-hooks codex # explicit install or upgrade for this workspace
31
+
32
+ Init detects .codex in the project or CODEX_HOME (default ~/.codex). Successful
33
+ errata link flows also refresh detected Codex hooks; --skip-hooks opts out of
34
+ either automatic install. The installer preserves other config and writes its
35
+ Node relay into .codex/hooks/errata-relay.mjs. No curl or Bash dependency.
36
+
37
+ Restart/resume Codex after installing, and review/trust the hooks with /hooks.
38
+ If your Codex build gates hooks, enable [features] codex_hooks = true. Update
39
+ older Codex builds if UserPromptSubmit or tool hooks are unsupported.
40
+
41
+ SessionStart injects .errata/context.md, including startup/resume/compaction.
42
+ UserPromptSubmit and PostToolUse inject it again only when it changes. Tool
43
+ recall and capture remain enabled. Refresh happens at a tool boundary, not
44
+ during model generation. The daemon must be running; unavailable hooks fail
45
+ open. AGENTS.md's file-read instruction remains a useful fallback.
46
+
47
+ The cloud MCP/plugin installer alone does not install this local daemon.
48
+ Install errata and run init in each workspace to enable daemon context.
49
+
28
50
  UPDATE
29
51
 
30
52
  errata update # pull the newest build on your channel (npm i -g)
@@ -15322,6 +15322,9 @@ var init_symbol_intent = __esm({
15322
15322
  });
15323
15323
 
15324
15324
  // ../../packages/shared/src/wire.ts
15325
+ function isAnchorLabelKind(kind) {
15326
+ return typeof kind === "string" && ANCHOR_LABEL_KINDS.includes(kind);
15327
+ }
15325
15328
  function anchorVersionAttrs(attrs) {
15326
15329
  if (!attrs) return {};
15327
15330
  const commit = attrs["observedAtCommit"];
@@ -15331,7 +15334,24 @@ function anchorVersionAttrs(attrs) {
15331
15334
  ...typeof hash2 === "string" && ANCHOR_BODY_HASH_RE.test(hash2) ? { symbolContentHash: hash2 } : {}
15332
15335
  };
15333
15336
  }
15334
- var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, CastaliaIngestNodeSchema, RouteContextCountWireSchema, ANCHOR_COMMIT_SHA_RE, ANCHOR_BODY_HASH_RE, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
15337
+ function anchorLabelAttrs(attrs) {
15338
+ if (!attrs) return {};
15339
+ const relPath = attrs["labelRelPath"];
15340
+ const qname = attrs["labelQname"];
15341
+ const kind = attrs["labelKind"];
15342
+ const line = attrs["labelLine"];
15343
+ if (typeof relPath !== "string" || !ANCHOR_LABEL_PATH_RE.test(relPath)) return {};
15344
+ if (!isAnchorLabelKind(kind)) return {};
15345
+ const qnameOk = typeof qname === "string" && ANCHOR_LABEL_QNAME_RE.test(qname);
15346
+ if (kind !== "File" && !qnameOk) return {};
15347
+ return {
15348
+ labelRelPath: relPath,
15349
+ labelKind: kind,
15350
+ ...kind !== "File" && qnameOk ? { labelQname: qname } : {},
15351
+ ...typeof line === "number" && Number.isInteger(line) && line >= 1 && line <= 1e7 ? { labelLine: line } : {}
15352
+ };
15353
+ }
15354
+ var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, CastaliaIngestNodeSchema, RouteContextCountWireSchema, ANCHOR_COMMIT_SHA_RE, ANCHOR_BODY_HASH_RE, ANCHOR_SYMBOL_KINDS, ANCHOR_LABEL_KINDS, FILE_ANCHOR_QNAME, ANCHOR_LABEL_PATH_RE, ANCHOR_LABEL_QNAME_RE, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
15335
15355
  var init_wire = __esm({
15336
15356
  "../../packages/shared/src/wire.ts"() {
15337
15357
  "use strict";
@@ -15434,6 +15454,22 @@ var init_wire = __esm({
15434
15454
  });
15435
15455
  ANCHOR_COMMIT_SHA_RE = /^[0-9a-f]{7,40}$/;
15436
15456
  ANCHOR_BODY_HASH_RE = /^[0-9a-f]{8,64}$/;
15457
+ ANCHOR_SYMBOL_KINDS = [
15458
+ "Function",
15459
+ "Class",
15460
+ "Method",
15461
+ "Module",
15462
+ "Interface",
15463
+ "Const",
15464
+ "Enum",
15465
+ "TypeAlias",
15466
+ "Namespace",
15467
+ "Property"
15468
+ ];
15469
+ ANCHOR_LABEL_KINDS = [...ANCHOR_SYMBOL_KINDS, "File"];
15470
+ FILE_ANCHOR_QNAME = "";
15471
+ ANCHOR_LABEL_PATH_RE = /^(?![/])(?![A-Za-z]:)(?!(?:.*\/)?\.\.(?:\/|$))[^\x00-\x1f\x7f\\`]{1,512}$/;
15472
+ ANCHOR_LABEL_QNAME_RE = /^[^\x00-\x1f\x7f`]{1,256}$/;
15437
15473
  CastaliaIngestEdgeSchema = external_exports.object({
15438
15474
  fromCanonicalId: external_exports.string().min(6).max(160),
15439
15475
  toCanonicalId: external_exports.string().min(6).max(160),
@@ -15453,7 +15489,17 @@ var init_wire = __esm({
15453
15489
  * classify the anchor current / pre-change; absent ⇒ the pre-versioning
15454
15490
  * contract, unverified. Only meaningful on `ANCHORED_AT`. */
15455
15491
  observedAtCommit: external_exports.string().regex(ANCHOR_COMMIT_SHA_RE).optional(),
15456
- symbolContentHash: external_exports.string().regex(ANCHOR_BODY_HASH_RE).optional()
15492
+ symbolContentHash: external_exports.string().regex(ANCHOR_BODY_HASH_RE).optional(),
15493
+ /** PJ-anchor-labels: the READABLE identity of the anchor's target —
15494
+ * repo-relative path, qualified name (absent for a File), kind and line.
15495
+ * Sent only for a project whose owner opted in; the door strips them again
15496
+ * for any project that has not (the daemon's flag is not trusted alone).
15497
+ * Prefixed `label*` so no local edge attr (`anchorLine` lives there
15498
+ * natively) can ride out under a shared key. */
15499
+ labelRelPath: external_exports.string().regex(ANCHOR_LABEL_PATH_RE).optional(),
15500
+ labelQname: external_exports.string().regex(ANCHOR_LABEL_QNAME_RE).optional(),
15501
+ labelKind: external_exports.enum(ANCHOR_LABEL_KINDS).optional(),
15502
+ labelLine: external_exports.number().int().min(1).max(1e7).optional()
15457
15503
  }).optional()
15458
15504
  });
15459
15505
  SymbolSummarySidecarSchema = external_exports.record(
@@ -19153,19 +19199,39 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
19153
19199
  for (const e of store.outEdges(sourceId, ["ANCHORED_AT"])) {
19154
19200
  const target = store.getNode(e.to);
19155
19201
  if (!target) continue;
19202
+ if (!isAnchorLabelKind(target.label)) continue;
19203
+ const isFile = target.label === "File";
19204
+ if (isFile && !project.anchorLabels) continue;
19156
19205
  const relPath = target.attrs["relPath"];
19157
- const qname = target.attrs["qname"];
19206
+ const qname = isFile ? FILE_ANCHOR_QNAME : target.attrs["qname"];
19158
19207
  if (typeof relPath !== "string" || typeof qname !== "string") continue;
19159
- if (ignored(relPath) || ignored(qname)) continue;
19160
- planned.push({ e, target, symId: projectSymbolId(project.salt, project.projectId, relPath, qname, target.label) });
19208
+ if (ignored(relPath) || qname !== "" && ignored(qname)) continue;
19209
+ const line = e.attrs?.["anchorLine"];
19210
+ const wireAttrs = {
19211
+ ...anchorVersionAttrs(e.attrs),
19212
+ // PJ-anchor-labels: only for an opted-in project, and only through the
19213
+ // shared projection (invalid path/kind ⇒ no label, never half of one).
19214
+ ...project.anchorLabels ? anchorLabelAttrs({
19215
+ labelRelPath: normalizeSymbolPath(relPath),
19216
+ labelKind: target.label,
19217
+ ...isFile ? {} : { labelQname: qname },
19218
+ ...typeof line === "number" ? { labelLine: line } : {}
19219
+ }) : {}
19220
+ };
19221
+ planned.push({
19222
+ e,
19223
+ target,
19224
+ symId: projectSymbolId(project.salt, project.projectId, relPath, qname, target.label),
19225
+ wireAttrs
19226
+ });
19161
19227
  }
19162
19228
  if (planned.length === 0) continue;
19163
19229
  const dg = digest(
19164
- planned.map(({ e, symId }) => `ANCHORED_AT>${symId}>${JSON.stringify(anchorVersionAttrs(e.attrs))}`).sort()
19230
+ planned.map(({ symId, wireAttrs }) => `ANCHORED_AT>${symId}>${JSON.stringify(wireAttrs)}`).sort()
19165
19231
  );
19166
19232
  if (source.attrs["projectAnchorsContributedDigest"] === dg) continue;
19167
19233
  projectAnchorDigests[sourceId] = dg;
19168
- for (const { e, target, symId } of planned) {
19234
+ for (const { e, target, symId, wireAttrs } of planned) {
19169
19235
  if (!contextSeen.has(symId)) {
19170
19236
  contextSeen.add(symId);
19171
19237
  contextNodes.push({
@@ -19192,7 +19258,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
19192
19258
  stability: "unstable"
19193
19259
  });
19194
19260
  }
19195
- anchorEdges.push({ ...e, from: wireFrom, to: symId, attrs: anchorVersionAttrs(e.attrs) });
19261
+ anchorEdges.push({ ...e, from: wireFrom, to: symId, attrs: wireAttrs });
19196
19262
  }
19197
19263
  }
19198
19264
  }
package/errata.mjs CHANGED
@@ -15729,6 +15729,9 @@ function provenanceBand(source) {
15729
15729
  function isSeedProvenance(source) {
15730
15730
  return provenanceBand(source) === "seed";
15731
15731
  }
15732
+ function isAnchorLabelKind(kind) {
15733
+ return typeof kind === "string" && ANCHOR_LABEL_KINDS.includes(kind);
15734
+ }
15732
15735
  function anchorVersionAttrs(attrs) {
15733
15736
  if (!attrs) return {};
15734
15737
  const commit = attrs["observedAtCommit"];
@@ -15738,6 +15741,28 @@ function anchorVersionAttrs(attrs) {
15738
15741
  ...typeof hash2 === "string" && ANCHOR_BODY_HASH_RE.test(hash2) ? { symbolContentHash: hash2 } : {}
15739
15742
  };
15740
15743
  }
15744
+ function anchorLabelAttrs(attrs) {
15745
+ if (!attrs) return {};
15746
+ const relPath = attrs["labelRelPath"];
15747
+ const qname = attrs["labelQname"];
15748
+ const kind = attrs["labelKind"];
15749
+ const line = attrs["labelLine"];
15750
+ if (typeof relPath !== "string" || !ANCHOR_LABEL_PATH_RE.test(relPath)) return {};
15751
+ if (!isAnchorLabelKind(kind)) return {};
15752
+ const qnameOk = typeof qname === "string" && ANCHOR_LABEL_QNAME_RE.test(qname);
15753
+ if (kind !== "File" && !qnameOk) return {};
15754
+ return {
15755
+ labelRelPath: relPath,
15756
+ labelKind: kind,
15757
+ ...kind !== "File" && qnameOk ? { labelQname: qname } : {},
15758
+ ...typeof line === "number" && Number.isInteger(line) && line >= 1 && line <= 1e7 ? { labelLine: line } : {}
15759
+ };
15760
+ }
15761
+ function stripAnchorLabels(attrs) {
15762
+ const out2 = { ...attrs };
15763
+ for (const k of ANCHOR_LABEL_KEYS) delete out2[k];
15764
+ return out2;
15765
+ }
15741
15766
  function validateCastaliaPayload(p) {
15742
15767
  const errors = [];
15743
15768
  const labelByCid = /* @__PURE__ */ new Map();
@@ -15767,7 +15792,7 @@ function summarizeIngestResult(r) {
15767
15792
  ...r.patternReconciliation ? { patternReconciliation: r.patternReconciliation } : {}
15768
15793
  };
15769
15794
  }
15770
- var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, QUARANTINE_EXTRACTION_SOURCE_PREFIX, MAX_NODES_PER_PAYLOAD, MAX_EDGES_PER_PAYLOAD, CastaliaIngestNodeSchema, RouteContextCountWireSchema, ANCHOR_COMMIT_SHA_RE, ANCHOR_BODY_HASH_RE, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
15795
+ var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, QUARANTINE_EXTRACTION_SOURCE_PREFIX, MAX_NODES_PER_PAYLOAD, MAX_EDGES_PER_PAYLOAD, CastaliaIngestNodeSchema, RouteContextCountWireSchema, ANCHOR_COMMIT_SHA_RE, ANCHOR_BODY_HASH_RE, ANCHOR_SYMBOL_KINDS, ANCHOR_LABEL_KINDS, FILE_ANCHOR_QNAME, ANCHOR_LABEL_PATH_RE, ANCHOR_LABEL_QNAME_RE, ANCHOR_LABEL_KEYS, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
15771
15796
  var init_wire = __esm({
15772
15797
  "../../packages/shared/src/wire.ts"() {
15773
15798
  "use strict";
@@ -15873,6 +15898,23 @@ var init_wire = __esm({
15873
15898
  });
15874
15899
  ANCHOR_COMMIT_SHA_RE = /^[0-9a-f]{7,40}$/;
15875
15900
  ANCHOR_BODY_HASH_RE = /^[0-9a-f]{8,64}$/;
15901
+ ANCHOR_SYMBOL_KINDS = [
15902
+ "Function",
15903
+ "Class",
15904
+ "Method",
15905
+ "Module",
15906
+ "Interface",
15907
+ "Const",
15908
+ "Enum",
15909
+ "TypeAlias",
15910
+ "Namespace",
15911
+ "Property"
15912
+ ];
15913
+ ANCHOR_LABEL_KINDS = [...ANCHOR_SYMBOL_KINDS, "File"];
15914
+ FILE_ANCHOR_QNAME = "";
15915
+ ANCHOR_LABEL_PATH_RE = /^(?![/])(?![A-Za-z]:)(?!(?:.*\/)?\.\.(?:\/|$))[^\x00-\x1f\x7f\\`]{1,512}$/;
15916
+ ANCHOR_LABEL_QNAME_RE = /^[^\x00-\x1f\x7f`]{1,256}$/;
15917
+ ANCHOR_LABEL_KEYS = ["labelRelPath", "labelQname", "labelKind", "labelLine"];
15876
15918
  CastaliaIngestEdgeSchema = external_exports.object({
15877
15919
  fromCanonicalId: external_exports.string().min(6).max(160),
15878
15920
  toCanonicalId: external_exports.string().min(6).max(160),
@@ -15892,7 +15934,17 @@ var init_wire = __esm({
15892
15934
  * classify the anchor current / pre-change; absent ⇒ the pre-versioning
15893
15935
  * contract, unverified. Only meaningful on `ANCHORED_AT`. */
15894
15936
  observedAtCommit: external_exports.string().regex(ANCHOR_COMMIT_SHA_RE).optional(),
15895
- symbolContentHash: external_exports.string().regex(ANCHOR_BODY_HASH_RE).optional()
15937
+ symbolContentHash: external_exports.string().regex(ANCHOR_BODY_HASH_RE).optional(),
15938
+ /** PJ-anchor-labels: the READABLE identity of the anchor's target —
15939
+ * repo-relative path, qualified name (absent for a File), kind and line.
15940
+ * Sent only for a project whose owner opted in; the door strips them again
15941
+ * for any project that has not (the daemon's flag is not trusted alone).
15942
+ * Prefixed `label*` so no local edge attr (`anchorLine` lives there
15943
+ * natively) can ride out under a shared key. */
15944
+ labelRelPath: external_exports.string().regex(ANCHOR_LABEL_PATH_RE).optional(),
15945
+ labelQname: external_exports.string().regex(ANCHOR_LABEL_QNAME_RE).optional(),
15946
+ labelKind: external_exports.enum(ANCHOR_LABEL_KINDS).optional(),
15947
+ labelLine: external_exports.number().int().min(1).max(1e7).optional()
15896
15948
  }).optional()
15897
15949
  });
15898
15950
  SymbolSummarySidecarSchema = external_exports.record(
@@ -16716,7 +16768,12 @@ __export(src_exports, {
16716
16768
  AMBIGUOUS_ALIASES: () => AMBIGUOUS_ALIASES,
16717
16769
  ANCHOR_BODY_HASH_RE: () => ANCHOR_BODY_HASH_RE,
16718
16770
  ANCHOR_COMMIT_SHA_RE: () => ANCHOR_COMMIT_SHA_RE,
16771
+ ANCHOR_LABEL_KEYS: () => ANCHOR_LABEL_KEYS,
16772
+ ANCHOR_LABEL_KINDS: () => ANCHOR_LABEL_KINDS,
16773
+ ANCHOR_LABEL_PATH_RE: () => ANCHOR_LABEL_PATH_RE,
16774
+ ANCHOR_LABEL_QNAME_RE: () => ANCHOR_LABEL_QNAME_RE,
16719
16775
  ANCHOR_REFUSAL_REASONS: () => ANCHOR_REFUSAL_REASONS,
16776
+ ANCHOR_SYMBOL_KINDS: () => ANCHOR_SYMBOL_KINDS,
16720
16777
  BELIEF_EDGES: () => BELIEF_EDGES,
16721
16778
  BRIDGE_EDGES: () => BRIDGE_EDGES,
16722
16779
  CAUSAL_EDGES: () => CAUSAL_EDGES,
@@ -16739,6 +16796,7 @@ __export(src_exports, {
16739
16796
  EDGE_RULES: () => EDGE_RULES,
16740
16797
  EDGE_WEIGHT: () => EDGE_WEIGHT,
16741
16798
  EVIDENCE_EDGES: () => EVIDENCE_EDGES,
16799
+ FILE_ANCHOR_QNAME: () => FILE_ANCHOR_QNAME,
16742
16800
  GIT_EDGES: () => GIT_EDGES,
16743
16801
  GRAPH_EVENT_VOCABULARIES: () => GRAPH_EVENT_VOCABULARIES,
16744
16802
  IDENTITY_EDGES: () => IDENTITY_EDGES,
@@ -16775,6 +16833,7 @@ __export(src_exports, {
16775
16833
  VALIDATION_SOURCES: () => VALIDATION_SOURCES,
16776
16834
  aliasesLongestFirst: () => aliasesLongestFirst,
16777
16835
  allEntities: () => allEntities,
16836
+ anchorLabelAttrs: () => anchorLabelAttrs,
16778
16837
  anchorVersionAttrs: () => anchorVersionAttrs,
16779
16838
  assertGraphEventVocabulary: () => assertGraphEventVocabulary,
16780
16839
  buildSpine: () => buildSpine,
@@ -16796,6 +16855,7 @@ __export(src_exports, {
16796
16855
  extractIdentifierTokens: () => extractIdentifierTokens,
16797
16856
  genericCanonicalId: () => genericCanonicalId,
16798
16857
  identityId: () => identityId,
16858
+ isAnchorLabelKind: () => isAnchorLabelKind,
16799
16859
  isCausalProtected: () => isCausalProtected,
16800
16860
  isCloudWritableNodeLabel: () => isCloudWritableNodeLabel,
16801
16861
  isCodeLabel: () => isCodeLabel,
@@ -16844,6 +16904,7 @@ __export(src_exports, {
16844
16904
  sidecarDropBucket: () => sidecarDropBucket,
16845
16905
  spineDeps: () => spineDeps,
16846
16906
  splitPnpmKey: () => splitPnpmKey,
16907
+ stripAnchorLabels: () => stripAnchorLabels,
16847
16908
  substituteSymbolSummaries: () => substituteSymbolSummaries,
16848
16909
  summarizeIngestResult: () => summarizeIngestResult,
16849
16910
  summaryRejectionReason: () => summaryRejectionReason,
@@ -24956,7 +25017,10 @@ function toWirePayload(batch, runId) {
24956
25017
  ...typeof e.confidence === "number" ? { confidence: clamp012(e.confidence) } : {},
24957
25018
  ...perContext ? { perContext } : {},
24958
25019
  // PJ-anchor-version: the two opaque version stamps ride on anchors only.
24959
- ...e.type === "ANCHORED_AT" ? anchorVersionAttrs(e.attrs) : {}
25020
+ ...e.type === "ANCHORED_AT" ? anchorVersionAttrs(e.attrs) : {},
25021
+ // PJ-anchor-labels: readable labels ride only when the producer set the
25022
+ // `label*` keys, which the daemon does only for an opted-in project.
25023
+ ...e.type === "ANCHORED_AT" ? anchorLabelAttrs(e.attrs) : {}
24960
25024
  }
24961
25025
  };
24962
25026
  });
@@ -28768,7 +28832,7 @@ function buildAgentInstruction(opts = {}) {
28768
28832
  tail
28769
28833
  ].join("\n");
28770
28834
  }
28771
- var TAG_EXAMPLE, GLOSS;
28835
+ var TAG_EXAMPLE, TAG_OPENERS, GLOSS;
28772
28836
  var init_agent_signals = __esm({
28773
28837
  "src/agent-signals.ts"() {
28774
28838
  "use strict";
@@ -28824,6 +28888,11 @@ var init_agent_signals = __esm({
28824
28888
  confirm: (ref) => `(confirm:[${ref}])`,
28825
28889
  refute: (ref) => `(refute:[${ref}] one line why)`
28826
28890
  };
28891
+ TAG_OPENERS = [
28892
+ ...new Set(
28893
+ Object.values(TAG_EXAMPLE).map((example) => /^(\([a-z][\w-]*:|\[[!?])/i.exec(example("x"))?.[1]?.toLowerCase()).filter((opener) => opener !== void 0)
28894
+ )
28895
+ ];
28827
28896
  GLOSS = {
28828
28897
  prior: "a shown prior helped, or you work in a primed language/package",
28829
28898
  problem: "a problem you notice or report \u2014 any bug, finding, or thing wrong; about specific code? name the file: [!what's wrong @ src/file.ts:42]",
@@ -51034,15 +51103,14 @@ function recallForTool(store, command, ctx) {
51034
51103
  ${lines.join("\n")}`;
51035
51104
  }
51036
51105
  function decideContextInject(args2) {
51037
- const { event, source, sessionId, block, lastInjectedHash } = args2;
51106
+ const { event, sessionId, block, lastInjectedHash } = args2;
51038
51107
  if (!block) return null;
51039
51108
  if (event === "SessionStart") {
51040
- lastInjectedHash.set(sessionId, block.hash);
51041
- if (source === "startup") return null;
51042
- } else if (lastInjectedHash.get(sessionId) === block.hash) {
51109
+ if (sessionId) lastInjectedHash.set(sessionId, block.hash);
51110
+ } else if (sessionId && lastInjectedHash.get(sessionId) === block.hash) {
51043
51111
  return null;
51044
51112
  } else {
51045
- lastInjectedHash.set(sessionId, block.hash);
51113
+ if (sessionId) lastInjectedHash.set(sessionId, block.hash);
51046
51114
  }
51047
51115
  const additionalContext = "The errata daemon has updated your live workspace context. The block below REPLACES any earlier errata context block in this conversation \u2014 treat it as the current source of truth:\n\n" + block.body;
51048
51116
  return { hookEventName: event, additionalContext };
@@ -70832,8 +70900,8 @@ var init_report_render = __esm({
70832
70900
 
70833
70901
  // src/cli.ts
70834
70902
  init_src6();
70835
- import { closeSync as closeSync2, existsSync as existsSync33, openSync as openSync2, readFileSync as readFileSync32, renameSync as renameSync4, statSync as statSync8 } from "node:fs";
70836
- import { join as join37, resolve as pathResolve2 } from "node:path";
70903
+ import { closeSync as closeSync2, existsSync as existsSync34, openSync as openSync2, readFileSync as readFileSync33, renameSync as renameSync4, statSync as statSync8 } from "node:fs";
70904
+ import { join as join38, resolve as pathResolve2 } from "node:path";
70837
70905
  import { spawn as spawn3 } from "node:child_process";
70838
70906
 
70839
70907
  // src/daemon.ts
@@ -74082,15 +74150,54 @@ function clauseBefore(sentence, idx) {
74082
74150
  }
74083
74151
  var FIX_RATIONALE_MIN = 12;
74084
74152
  var FIX_RATIONALE_WINDOW = 160;
74153
+ var SIBLING_MARKUP_SOURCES = [
74154
+ CITE_GROUP_RE,
74155
+ FLAG_RE,
74156
+ FIX_LONG_RE,
74157
+ CAUSE_LONG_RE,
74158
+ CONFIRM_LONG_RE,
74159
+ REFUTE_LONG_RE,
74160
+ ATTEMPT_RE,
74161
+ CONSTRAINT_RE
74162
+ ].map((re) => ({ source: re.source, flags: re.flags.includes("g") ? re.flags : `${re.flags}g` }));
74163
+ function maskSiblingMarkup(sentence, tagStart, tagEnd) {
74164
+ let masked = sentence;
74165
+ for (const { source, flags: flags2 } of SIBLING_MARKUP_SOURCES) {
74166
+ masked = masked.replace(new RegExp(source, flags2), (m, ...rest2) => {
74167
+ const at = rest2.find((v) => typeof v === "number");
74168
+ if (at <= tagStart && at + m.length >= tagEnd) return m;
74169
+ return " ".repeat(m.length);
74170
+ });
74171
+ }
74172
+ return masked;
74173
+ }
74174
+ var RESIDUAL_OPENER_RE = new RegExp(
74175
+ TAG_OPENERS.map((o) => o.startsWith("(") ? String.raw`\(\s*${o.slice(1, -1)}\s*:` : o.replace(/[[\]!?]/g, "\\$&")).join("|"),
74176
+ "i"
74177
+ );
74085
74178
  function fixRationaleBefore(sentence, idx) {
74086
- const win = sentence.slice(Math.max(0, idx - FIX_RATIONALE_WINDOW), idx).replace(new RegExp(CITE_GROUP_RE.source, "g"), " ").replace(new RegExp(FLAG_RE.source, "g"), " ");
74179
+ const masked = maskSiblingMarkup(sentence, idx, idx + 1);
74180
+ let start2 = Math.max(0, idx - FIX_RATIONALE_WINDOW);
74181
+ if (start2 > 0 && /\S/.test(masked[start2 - 1]) && /\S/.test(masked[start2])) {
74182
+ const ws = masked.slice(start2, idx).search(/\s/);
74183
+ start2 = ws < 0 ? idx : start2 + ws;
74184
+ }
74185
+ const win = masked.slice(start2, idx);
74087
74186
  const m = /[.;!?—][^.;!?—]*$/.exec(win);
74088
74187
  const clause = m ? win.slice(m.index + 1) : win;
74089
74188
  return clause.replace(/\s+/g, " ").trim();
74090
74189
  }
74091
74190
  function fixRationaleAfter(sentence, endIdx) {
74092
- const win = sentence.slice(endIdx, endIdx + FIX_RATIONALE_WINDOW).replace(new RegExp(CITE_GROUP_RE.source, "g"), " ").replace(new RegExp(FLAG_RE.source, "g"), " ");
74093
- if (/^\s*[)\]}]/.test(win)) return "";
74191
+ if (/^\s*[)\]}]/.test(sentence.slice(endIdx))) return "";
74192
+ const masked = maskSiblingMarkup(sentence, endIdx - 1, endIdx);
74193
+ let end = Math.min(masked.length, endIdx + FIX_RATIONALE_WINDOW);
74194
+ if (end < masked.length && /\S/.test(masked[end - 1]) && /\S/.test(masked[end])) {
74195
+ const lastWs = masked.slice(endIdx, end).search(/\s\S*$/);
74196
+ end = lastWs < 0 ? endIdx : endIdx + lastWs;
74197
+ }
74198
+ let win = masked.slice(endIdx, end);
74199
+ const residual = RESIDUAL_OPENER_RE.exec(win);
74200
+ if (residual) win = win.slice(0, residual.index);
74094
74201
  const stripped = win.replace(/^[\s—:–,-]+/, "");
74095
74202
  const m = /^[^.;!?—]*/.exec(stripped);
74096
74203
  const clause = (m ? m[0] : stripped).replace(/\s+/g, " ").trim();
@@ -74102,6 +74209,78 @@ function deriveFixRationale(sentence, startIdx, endIdx) {
74102
74209
  if (before.length >= FIX_RATIONALE_MIN) return before;
74103
74210
  return fixRationaleAfter(sentence, endIdx);
74104
74211
  }
74212
+ var LEADING_OPENER_RE = new RegExp(String.raw`^(?:${RESIDUAL_OPENER_RE.source})(?:#[a-z][\w-]{0,63})?\s*`, "i");
74213
+ var WRAPPER_PAIRS = [["(", ")"], ["[", "]"]];
74214
+ var LEADING_HANDLES_RE = /^(?:\[[a-z0-9][\w-]{0,80}\]\s*,?\s*)+/i;
74215
+ function leadingBracketClose(t) {
74216
+ const pair = WRAPPER_PAIRS.find(([open2]) => t.startsWith(open2));
74217
+ if (!pair) return null;
74218
+ let depth = 0;
74219
+ for (let i2 = 0; i2 < t.length; i2++) {
74220
+ if (t[i2] === pair[0]) depth++;
74221
+ else if (t[i2] === pair[1] && --depth === 0) return i2;
74222
+ }
74223
+ return -1;
74224
+ }
74225
+ function trailingBracketStray(t) {
74226
+ const pair = WRAPPER_PAIRS.find(([, close]) => t.endsWith(close));
74227
+ if (!pair) return false;
74228
+ let depth = 0;
74229
+ for (const ch of t.slice(0, -1)) {
74230
+ if (ch === pair[0]) depth++;
74231
+ else if (ch === pair[1] && depth > 0) depth--;
74232
+ }
74233
+ return depth === 0;
74234
+ }
74235
+ function cleanTagText(text) {
74236
+ let t = text.replace(/\s+/g, " ").trim();
74237
+ for (let pass = 0; pass < 8; pass++) {
74238
+ const before = t;
74239
+ const close = leadingBracketClose(t);
74240
+ const opener = close === null ? null : LEADING_OPENER_RE.exec(t);
74241
+ if (close === -1) {
74242
+ t = t.slice(opener ? opener[0].length : 1).trim();
74243
+ } else if (opener && close === t.length - 1) {
74244
+ t = t.slice(opener[0].length, -1).trim();
74245
+ }
74246
+ if (opener && t !== before) t = t.replace(LEADING_HANDLES_RE, "").trim();
74247
+ if (trailingBracketStray(t)) t = t.slice(0, -1).trim();
74248
+ if (t === before) break;
74249
+ }
74250
+ return t;
74251
+ }
74252
+ var TAG_TEXT_FIELDS = [
74253
+ "fixRationale",
74254
+ "statement",
74255
+ "causeText",
74256
+ "causeOf",
74257
+ "patternText",
74258
+ "domainText",
74259
+ "packageText",
74260
+ "componentText"
74261
+ ];
74262
+ function cleanEmittedTags(tags) {
74263
+ const kept = [];
74264
+ for (const tag of tags) {
74265
+ let emptied = false;
74266
+ for (const field of TAG_TEXT_FIELDS) {
74267
+ const value = tag[field];
74268
+ if (value === void 0) continue;
74269
+ const cleaned = cleanTagText(value);
74270
+ if (field === "fixRationale" && cleaned.length < FIX_RATIONALE_MIN) {
74271
+ delete tag.fixRationale;
74272
+ continue;
74273
+ }
74274
+ if (cleaned.length === 0) emptied = true;
74275
+ tag[field] = cleaned;
74276
+ }
74277
+ const hasReference = tag.handle !== void 0 || (tag.handles?.length ?? 0) > 0 || (tag.refuteHandles?.length ?? 0) > 0;
74278
+ if (emptied && !hasReference) continue;
74279
+ if (tag.kind === "fix" && !hasReference && tag.fixRationale === void 0) continue;
74280
+ kept.push(tag);
74281
+ }
74282
+ return kept;
74283
+ }
74105
74284
  function emptyTagDispositions() {
74106
74285
  return {
74107
74286
  oversizeSegments: 0,
@@ -74469,7 +74648,7 @@ function parseInlineTagsWithDispositions(text) {
74469
74648
  }
74470
74649
  for (let i2 = seqStart; i2 < out2.length; i2++) out2[i2].seq = seqNo;
74471
74650
  }
74472
- return { tags: out2, dispositions };
74651
+ return { tags: cleanEmittedTags(out2), dispositions };
74473
74652
  }
74474
74653
  var LABEL_PAIR = {
74475
74654
  "Problem>RootCause": "CAUSED_BY",
@@ -78143,7 +78322,7 @@ function createWatchBreaker(deps) {
78143
78322
  }
78144
78323
 
78145
78324
  // src/engine.ts
78146
- var DAEMON_VERSION = true ? "2.0.6-dev.2511" : "2.0.0-alpha.0";
78325
+ var DAEMON_VERSION = true ? "2.0.6-dev.2550" : "2.0.0-alpha.0";
78147
78326
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
78148
78327
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
78149
78328
  var GIT_OP_MUTE_MS = 4e3;
@@ -81172,19 +81351,39 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
81172
81351
  for (const e of store.outEdges(sourceId, ["ANCHORED_AT"])) {
81173
81352
  const target = store.getNode(e.to);
81174
81353
  if (!target) continue;
81354
+ if (!isAnchorLabelKind(target.label)) continue;
81355
+ const isFile = target.label === "File";
81356
+ if (isFile && !project.anchorLabels) continue;
81175
81357
  const relPath = target.attrs["relPath"];
81176
- const qname = target.attrs["qname"];
81358
+ const qname = isFile ? FILE_ANCHOR_QNAME : target.attrs["qname"];
81177
81359
  if (typeof relPath !== "string" || typeof qname !== "string") continue;
81178
- if (ignored(relPath) || ignored(qname)) continue;
81179
- planned.push({ e, target, symId: projectSymbolId(project.salt, project.projectId, relPath, qname, target.label) });
81360
+ if (ignored(relPath) || qname !== "" && ignored(qname)) continue;
81361
+ const line = e.attrs?.["anchorLine"];
81362
+ const wireAttrs = {
81363
+ ...anchorVersionAttrs(e.attrs),
81364
+ // PJ-anchor-labels: only for an opted-in project, and only through the
81365
+ // shared projection (invalid path/kind ⇒ no label, never half of one).
81366
+ ...project.anchorLabels ? anchorLabelAttrs({
81367
+ labelRelPath: normalizeSymbolPath(relPath),
81368
+ labelKind: target.label,
81369
+ ...isFile ? {} : { labelQname: qname },
81370
+ ...typeof line === "number" ? { labelLine: line } : {}
81371
+ }) : {}
81372
+ };
81373
+ planned.push({
81374
+ e,
81375
+ target,
81376
+ symId: projectSymbolId(project.salt, project.projectId, relPath, qname, target.label),
81377
+ wireAttrs
81378
+ });
81180
81379
  }
81181
81380
  if (planned.length === 0) continue;
81182
81381
  const dg = digest(
81183
- planned.map(({ e, symId }) => `ANCHORED_AT>${symId}>${JSON.stringify(anchorVersionAttrs(e.attrs))}`).sort()
81382
+ planned.map(({ symId, wireAttrs }) => `ANCHORED_AT>${symId}>${JSON.stringify(wireAttrs)}`).sort()
81184
81383
  );
81185
81384
  if (source.attrs["projectAnchorsContributedDigest"] === dg) continue;
81186
81385
  projectAnchorDigests[sourceId] = dg;
81187
- for (const { e, target, symId } of planned) {
81386
+ for (const { e, target, symId, wireAttrs } of planned) {
81188
81387
  if (!contextSeen.has(symId)) {
81189
81388
  contextSeen.add(symId);
81190
81389
  contextNodes.push({
@@ -81211,7 +81410,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
81211
81410
  stability: "unstable"
81212
81411
  });
81213
81412
  }
81214
- anchorEdges.push({ ...e, from: wireFrom, to: symId, attrs: anchorVersionAttrs(e.attrs) });
81413
+ anchorEdges.push({ ...e, from: wireFrom, to: symId, attrs: wireAttrs });
81215
81414
  }
81216
81415
  }
81217
81416
  }
@@ -81715,7 +81914,7 @@ init_src11();
81715
81914
  init_src();
81716
81915
  init_src11();
81717
81916
  var DEFAULT_LIMIT = 50;
81718
- var ANCHOR_SYMBOL_KINDS = [
81917
+ var ANCHOR_SYMBOL_KINDS2 = [
81719
81918
  "Function",
81720
81919
  "Class",
81721
81920
  "Method",
@@ -81736,7 +81935,7 @@ function classifyAnchorVersion(cloudAttrs, localSymbol) {
81736
81935
  function buildReverseSymbolMap(opts) {
81737
81936
  const { store, salt, projectId } = opts;
81738
81937
  const reverse = /* @__PURE__ */ new Map();
81739
- for (const kind of ANCHOR_SYMBOL_KINDS) {
81938
+ for (const kind of ANCHOR_SYMBOL_KINDS2) {
81740
81939
  for (const n of store.findNodeIdentitiesByLabel(kind)) {
81741
81940
  const { relPath, qname } = n;
81742
81941
  if (relPath === null || qname === null) continue;
@@ -81746,6 +81945,13 @@ function buildReverseSymbolMap(opts) {
81746
81945
  if (!reverse.has(twin)) reverse.set(twin, n.id);
81747
81946
  }
81748
81947
  }
81948
+ for (const n of store.findNodeIdentitiesByLabel("File")) {
81949
+ if (n.relPath === null) continue;
81950
+ const sym = projectSymbolId(salt, projectId, n.relPath, FILE_ANCHOR_QNAME, "File");
81951
+ if (!reverse.has(sym)) reverse.set(sym, n.id);
81952
+ const twin = projectSaltedNodeId(sym, salt);
81953
+ if (!reverse.has(twin)) reverse.set(twin, n.id);
81954
+ }
81749
81955
  return reverse;
81750
81956
  }
81751
81957
  function anchorConfidence(attrs) {
@@ -84482,12 +84688,21 @@ function withLaunchOrigin(pending) {
84482
84688
  return LOCAL_BUILD_ENTRY ? { ...pending, localBuildEntry: LOCAL_BUILD_ENTRY } : pending;
84483
84689
  }
84484
84690
  var projectSymbolSalts = /* @__PURE__ */ new Map();
84691
+ var PROJECT_SALT_REFRESH_MS = 10 * 6e4;
84485
84692
  async function resolveProjectSymbolSalt(client, projectId) {
84486
84693
  const cached2 = projectSymbolSalts.get(projectId);
84487
- if (cached2) return { projectId, salt: cached2 };
84488
- const { salt } = await client.projectSymbolSalt(projectId);
84489
- projectSymbolSalts.set(projectId, salt);
84490
- return { projectId, salt };
84694
+ if (cached2 && Date.now() - cached2.fetchedAt < PROJECT_SALT_REFRESH_MS) {
84695
+ return { projectId, salt: cached2.salt, anchorLabels: cached2.anchorLabels };
84696
+ }
84697
+ try {
84698
+ const res = await client.projectSymbolSalt(projectId);
84699
+ const entry = { salt: res.salt, anchorLabels: res.anchorLabels === true, fetchedAt: Date.now() };
84700
+ projectSymbolSalts.set(projectId, entry);
84701
+ return { projectId, salt: entry.salt, anchorLabels: entry.anchorLabels };
84702
+ } catch (err2) {
84703
+ if (cached2) return { projectId, salt: cached2.salt, anchorLabels: cached2.anchorLabels };
84704
+ throw err2;
84705
+ }
84491
84706
  }
84492
84707
  var WATERMARK_BATCH = 250;
84493
84708
  async function stampBatched(items, stamp) {
@@ -86612,32 +86827,92 @@ function hookRelayCommand(port, path2) {
86612
86827
  }
86613
86828
  var CODEX_HOOKS_BEGIN = `# >>> errata hooks (errata-managed)`;
86614
86829
  var CODEX_HOOKS_END = `# <<< errata hooks`;
86615
- function buildCodexHooksToml(port) {
86616
- const cmd2 = hookCurlCommand(port).replace(/"/g, '\\"');
86617
- const turnCmd = hookCurlCommand(port, "/api/turn").replace(/"/g, '\\"');
86618
- return `${CODEX_HOOKS_BEGIN}
86619
- [[hooks.PreToolUse]]
86620
- matcher = ".*"
86621
-
86622
- [[hooks.PreToolUse.hooks]]
86623
- type = "command"
86624
- command = "${cmd2}"
86625
- timeout = 10
86626
-
86627
- [[hooks.PostToolUse]]
86628
- matcher = ".*"
86629
-
86630
- [[hooks.PostToolUse.hooks]]
86631
- type = "command"
86632
- command = "${cmd2}"
86633
- timeout = 10
86634
-
86635
- [[hooks.PostToolUse.hooks]]
86636
- type = "command"
86637
- command = "${turnCmd}"
86638
- timeout = 10
86639
- ${CODEX_HOOKS_END}
86830
+ function buildCodexHooksToml(port, options) {
86831
+ const platform = options.platform ?? process.platform;
86832
+ const quote = (value) => {
86833
+ if (platform === "win32") {
86834
+ if (/["%\r\n]/.test(value)) throw new Error("Unsupported character in Codex hook path");
86835
+ return '"' + value + '"';
86836
+ }
86837
+ return "'" + value.replace(/'/g, "'\\''") + "'";
86838
+ };
86839
+ if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error("Invalid hook port");
86840
+ const command = quote(options.nodePath) + " " + quote(options.relayPath) + " " + port;
86841
+ const handlers = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse"].map(
86842
+ (event) => "[[hooks." + event + "]]\n" + (event === "UserPromptSubmit" ? "" : 'matcher = ".*"\n') + "\n[[hooks." + event + '.hooks]]\ntype = "command"\ncommand = ' + JSON.stringify(command) + "\ntimeout = 10\nadditionalContextLimit = 5000\n"
86843
+ );
86844
+ return CODEX_HOOKS_BEGIN + "\n" + handlers.join("\n") + CODEX_HOOKS_END + "\n";
86845
+ }
86846
+
86847
+ // src/codex-hooks.ts
86848
+ import { existsSync as existsSync33, mkdirSync as mkdirSync9, readFileSync as readFileSync32, writeFileSync as writeFileSync24 } from "node:fs";
86849
+ import { homedir as homedir7 } from "node:os";
86850
+ import { join as join37 } from "node:path";
86851
+
86852
+ // src/codex-hook-relay.ts
86853
+ var CODEX_RELAY_SOURCE = String.raw`// errata-managed: regenerated by errata install-hooks codex
86854
+ import { readFileSync } from 'node:fs';
86855
+
86856
+ try {
86857
+ const payload = JSON.parse(readFileSync(0, 'utf8') || '{}');
86858
+ const port = Number(process.argv[2]);
86859
+ const event = payload.hook_event_name;
86860
+ if (!Number.isInteger(port) || port < 1 || port > 65535) process.exit(0);
86861
+ const contexts = [];
86862
+ const post = async (endpoint, relay = false) => {
86863
+ try {
86864
+ const response = await fetch('http://127.0.0.1:' + port + '/api/' + endpoint, {
86865
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
86866
+ body: JSON.stringify(payload), signal: AbortSignal.timeout(2000),
86867
+ });
86868
+ if (!response.ok || !relay) return;
86869
+ const result = await response.json();
86870
+ const context = result.hookSpecificOutput?.additionalContext;
86871
+ if (typeof context === 'string' && context.trim()) contexts.push(context);
86872
+ } catch { /* An unavailable daemon must never block the agent. */ }
86873
+ };
86874
+ if (event === 'PreToolUse' || event === 'PostToolUse') await post('hook', true);
86875
+ if (event === 'PostToolUse') await post('turn');
86876
+ if (['SessionStart', 'UserPromptSubmit', 'PostToolUse'].includes(event)) {
86877
+ // Run after capture, so changes already rendered by the daemon arrive now.
86878
+ // Background extraction finishing later arrives at the next tool boundary.
86879
+ await post('context-inject', true);
86880
+ }
86881
+ if (contexts.length) {
86882
+ process.stdout.write(JSON.stringify({ hookSpecificOutput: {
86883
+ hookEventName: event, additionalContext: contexts.join('\n\n'),
86884
+ } }));
86885
+ }
86886
+ } catch { /* Invalid input is also fail-open. */ }
86640
86887
  `;
86888
+
86889
+ // src/codex-hooks.ts
86890
+ function hasCodexConfig(root, codexHome = process.env["CODEX_HOME"] || join37(homedir7(), ".codex")) {
86891
+ return existsSync33(join37(root, ".codex")) || existsSync33(codexHome);
86892
+ }
86893
+ function replaceCodexHooks(existing, block) {
86894
+ const begin = existing.indexOf(CODEX_HOOKS_BEGIN);
86895
+ const end = existing.indexOf(CODEX_HOOKS_END);
86896
+ if (begin >= 0 || end >= 0) {
86897
+ if (begin < 0 || end < begin || existing.indexOf(CODEX_HOOKS_BEGIN, begin + CODEX_HOOKS_BEGIN.length) >= 0) {
86898
+ throw new Error(
86899
+ "Incomplete or duplicate errata hooks markers in .codex/config.toml; repair them before reinstalling."
86900
+ );
86901
+ }
86902
+ return existing.slice(0, begin) + block.trimEnd() + existing.slice(end + CODEX_HOOKS_END.length);
86903
+ }
86904
+ return existing.trimEnd() + (existing.trim() ? "\n\n" : "") + block;
86905
+ }
86906
+ function writeCodexHooks(root, port, nodePath = process.execPath) {
86907
+ const dir = join37(root, ".codex");
86908
+ const file2 = join37(dir, "config.toml");
86909
+ const relay = join37(dir, "hooks", "errata-relay.mjs");
86910
+ const block = buildCodexHooksToml(port, { nodePath, relayPath: relay });
86911
+ const final = replaceCodexHooks(existsSync33(file2) ? readFileSync32(file2, "utf8") : "", block);
86912
+ mkdirSync9(join37(dir, "hooks"), { recursive: true });
86913
+ writeFileSync24(relay, CODEX_RELAY_SOURCE, "utf8");
86914
+ writeFileSync24(file2, final, "utf8");
86915
+ return file2;
86641
86916
  }
86642
86917
 
86643
86918
  // src/opencode-plugin.ts
@@ -86979,6 +87254,7 @@ Commands:
86979
87254
  Flags: --project <id> adopt an existing project (fork\u2192upstream);
86980
87255
  --remote <name> derive the locator from a non-origin remote;
86981
87256
  --name <name> mint a locator-less project; no flags = re-resolve now
87257
+ --skip-hooks leave existing harness configuration unchanged
86982
87258
  unlink Detach from the cloud project + disable ambient re-linking
86983
87259
  use [<handle>] Set the sticky session active agent the daemon acts as.
86984
87260
  No arg lists the agents you can act as + the current one;
@@ -87044,21 +87320,21 @@ async function cmdInit() {
87044
87320
  if (!skipHooks) {
87045
87321
  console.log("");
87046
87322
  console.log("installing harness hooks...");
87047
- const { existsSync: existsSync34 } = await import("node:fs");
87048
- const { join: join38 } = await import("node:path");
87323
+ const { existsSync: existsSync35 } = await import("node:fs");
87324
+ const { join: join39 } = await import("node:path");
87049
87325
  try {
87050
87326
  await installClaudeHooks(port);
87051
87327
  } catch (err2) {
87052
87328
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
87053
87329
  }
87054
- if (existsSync34(join38(ROOT, ".cursor"))) {
87330
+ if (existsSync35(join39(ROOT, ".cursor"))) {
87055
87331
  try {
87056
87332
  await installCursorMcpConfig();
87057
87333
  } catch (err2) {
87058
87334
  console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
87059
87335
  }
87060
87336
  }
87061
- if (existsSync34(join38(ROOT, ".codex"))) {
87337
+ if (hasCodexConfig(ROOT)) {
87062
87338
  try {
87063
87339
  await installCodexHooks(port);
87064
87340
  } catch (err2) {
@@ -87235,9 +87511,9 @@ async function cmdStatus() {
87235
87511
  console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
87236
87512
  console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
87237
87513
  }
87238
- console.log(` graph db: ${existsSync33(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
87239
- console.log(` event log: ${existsSync33(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
87240
- if (existsSync33(paths.castalia)) {
87514
+ console.log(` graph db: ${existsSync34(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
87515
+ console.log(` event log: ${existsSync34(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
87516
+ if (existsSync34(paths.castalia)) {
87241
87517
  try {
87242
87518
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
87243
87519
  const store = openGraphStore2({ path: paths.castalia });
@@ -87872,6 +88148,7 @@ async function cmdLink(args2) {
87872
88148
  console.log(
87873
88149
  `consents: sync=${d.consents.sync} telemetry=${d.consents.telemetry ? "on" : "off"} packages=${applied.config.consent.contributePackages ? "on" : "off"} structure=${d.consents.structure ? "on" : "off"} history=${d.consents.mineHistory ? applied.profile.linkConsents?.contributeHistory ? "mine+contribute" : "mine" : "off"}`
87874
88150
  );
88151
+ await refreshLinkedCodexHooks(args2);
87875
88152
  if (applied.wroteIgnore) console.log("wrote .errataignore (starter) \u2014 edit it; it is your hard control");
87876
88153
  if (!hasCloudCredential(cfg)) {
87877
88154
  console.log(" note: run `errata login` so this daemon can sync under the link and report the history stage.");
@@ -87912,6 +88189,7 @@ async function cmdLink(args2) {
87912
88189
  profile.projectId = res.project.id;
87913
88190
  profile.projectLocator = profile.repoLocator;
87914
88191
  saveProfile(ROOT, profile);
88192
+ await refreshLinkedCodexHooks(args2);
87915
88193
  console.log(`linked (adopted): ${profile.repoLocator} \u2192 project ${res.project.id} (${res.project.name})`);
87916
88194
  return;
87917
88195
  }
@@ -87921,6 +88199,7 @@ async function cmdLink(args2) {
87921
88199
  profile.projectId = res.project.id;
87922
88200
  delete profile.projectLocator;
87923
88201
  saveProfile(ROOT, profile);
88202
+ await refreshLinkedCodexHooks(args2);
87924
88203
  console.log(`linked (locator-less): project ${res.project.id} (${res.project.name})`);
87925
88204
  return;
87926
88205
  }
@@ -87929,6 +88208,7 @@ async function cmdLink(args2) {
87929
88208
  delete profile.projectLocator;
87930
88209
  const out2 = await ensureProjectLink(ROOT, profile, client);
87931
88210
  if (out2.linked) {
88211
+ await refreshLinkedCodexHooks(args2);
87932
88212
  console.log(`linked: ${profile.repoLocator} \u2192 project ${out2.projectId}${out2.created ? " (created)" : ""}`);
87933
88213
  } else {
87934
88214
  console.error(`link failed (${out2.reason})${out2.detail ? `: ${out2.detail}` : ""}`);
@@ -88135,11 +88415,11 @@ function cmdInstallationProfile(args2) {
88135
88415
  }
88136
88416
  async function cmdReview() {
88137
88417
  const paths = workspacePaths(ROOT);
88138
- if (!existsSync33(paths.reviewQueue)) {
88418
+ if (!existsSync34(paths.reviewQueue)) {
88139
88419
  console.log("(review queue empty)");
88140
88420
  return;
88141
88421
  }
88142
- const queue = JSON.parse(readFileSync32(paths.reviewQueue, "utf8"));
88422
+ const queue = JSON.parse(readFileSync33(paths.reviewQueue, "utf8"));
88143
88423
  if (queue.length === 0) {
88144
88424
  console.log("(review queue empty)");
88145
88425
  return;
@@ -88810,7 +89090,7 @@ async function gatherRepo(store, ws) {
88810
89090
  };
88811
89091
  }
88812
89092
  async function gatherReportData(generatedAt) {
88813
- const { existsSync: existsSync34 } = await import("node:fs");
89093
+ const { existsSync: existsSync35 } = await import("node:fs");
88814
89094
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
88815
89095
  const cfg = loadConfig();
88816
89096
  const outbound = cfg.consent.sync ? "auto" : "off";
@@ -88818,7 +89098,7 @@ async function gatherReportData(generatedAt) {
88818
89098
  for (const ws of listWorkspaces()) {
88819
89099
  if (ws.missing) continue;
88820
89100
  const dbPath = workspacePaths(ws.path).castalia;
88821
- if (!existsSync34(dbPath)) continue;
89101
+ if (!existsSync35(dbPath)) continue;
88822
89102
  let store = null;
88823
89103
  try {
88824
89104
  store = openGraphStore2({ path: dbPath });
@@ -88849,7 +89129,7 @@ async function gatherReportData(generatedAt) {
88849
89129
  };
88850
89130
  }
88851
89131
  async function cmdReport(args2) {
88852
- const { mkdirSync: mkdirSync9, writeFileSync: writeFileSync24 } = await import("node:fs");
89132
+ const { mkdirSync: mkdirSync10, writeFileSync: writeFileSync25 } = await import("node:fs");
88853
89133
  const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
88854
89134
  const includeFutureVerbs = args2.includes("--future-verbs");
88855
89135
  const now = /* @__PURE__ */ new Date();
@@ -88860,10 +89140,10 @@ async function cmdReport(args2) {
88860
89140
  process.exit(2);
88861
89141
  }
88862
89142
  const outDir = workspacePaths(ROOT).configDir;
88863
- mkdirSync9(outDir, { recursive: true });
89143
+ mkdirSync10(outDir, { recursive: true });
88864
89144
  const files = renderReport2(data, { includeFutureVerbs });
88865
- for (const f of files) writeFileSync24(join37(outDir, f.name), f.html, "utf8");
88866
- const indexPath = join37(outDir, "report.html");
89145
+ for (const f of files) writeFileSync25(join38(outDir, f.name), f.html, "utf8");
89146
+ const indexPath = join38(outDir, "report.html");
88867
89147
  console.log(`report \u2192 ${indexPath}`);
88868
89148
  console.log(
88869
89149
  ` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
@@ -88983,24 +89263,24 @@ async function cmdInstallHooks(args2) {
88983
89263
  }
88984
89264
  }
88985
89265
  async function installOpencodePlugin(port) {
88986
- const { mkdirSync: mkdirSync9, existsSync: existsSync34, readFileSync: readFileSync33, writeFileSync: writeFileSync24 } = await import("node:fs");
88987
- const { join: join38 } = await import("node:path");
88988
- const dir = join38(ROOT, ".opencode", "plugin");
88989
- if (!existsSync34(dir)) mkdirSync9(dir, { recursive: true });
88990
- const file2 = join38(dir, "inerrata.js");
88991
- if (existsSync34(file2)) {
88992
- const head2 = readFileSync33(file2, "utf8").split("\n")[0] ?? "";
89266
+ const { mkdirSync: mkdirSync10, existsSync: existsSync35, readFileSync: readFileSync34, writeFileSync: writeFileSync25 } = await import("node:fs");
89267
+ const { join: join39 } = await import("node:path");
89268
+ const dir = join39(ROOT, ".opencode", "plugin");
89269
+ if (!existsSync35(dir)) mkdirSync10(dir, { recursive: true });
89270
+ const file2 = join39(dir, "inerrata.js");
89271
+ if (existsSync35(file2)) {
89272
+ const head2 = readFileSync34(file2, "utf8").split("\n")[0] ?? "";
88993
89273
  if (head2.trim() !== OPENCODE_PLUGIN_MARKER) {
88994
89274
  console.error(`refusing to overwrite ${file2}: not an errata-managed plugin (line 1 lacks the marker)`);
88995
89275
  process.exit(2);
88996
89276
  }
88997
89277
  }
88998
- writeFileSync24(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
88999
- const cfgFile = join38(ROOT, "opencode.json");
89278
+ writeFileSync25(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
89279
+ const cfgFile = join39(ROOT, "opencode.json");
89000
89280
  let cfg = { $schema: "https://opencode.ai/config.json" };
89001
- if (existsSync34(cfgFile)) {
89281
+ if (existsSync35(cfgFile)) {
89002
89282
  try {
89003
- cfg = JSON.parse(readFileSync33(cfgFile, "utf8"));
89283
+ cfg = JSON.parse(readFileSync34(cfgFile, "utf8"));
89004
89284
  } catch {
89005
89285
  console.error(`refusing to touch invalid JSON at ${cfgFile} \u2014 fix it and re-run`);
89006
89286
  process.exit(2);
@@ -89011,7 +89291,7 @@ async function installOpencodePlugin(port) {
89011
89291
  if (!hadErrata) {
89012
89292
  const inv = errataMcpInvocation();
89013
89293
  cfg.mcp["errata"] = { type: "local", command: [inv.command, ...inv.args] };
89014
- writeFileSync24(cfgFile, JSON.stringify(cfg, null, 2) + "\n", "utf8");
89294
+ writeFileSync25(cfgFile, JSON.stringify(cfg, null, 2) + "\n", "utf8");
89015
89295
  }
89016
89296
  console.log(`installed OpenCode plugin \u2192 ${file2}`);
89017
89297
  if (hadErrata) console.log(` mcp.errata already present in ${cfgFile} \u2014 left untouched`);
@@ -89031,15 +89311,15 @@ function errataMcpInvocation() {
89031
89311
  return { command: cmd2, args: args2 };
89032
89312
  }
89033
89313
  async function installClaudeHooks(port) {
89034
- const { mkdirSync: mkdirSync9, existsSync: existsSync34, readFileSync: readFileSync33, writeFileSync: writeFileSync24 } = await import("node:fs");
89035
- const { join: join38 } = await import("node:path");
89036
- const dir = join38(ROOT, ".claude");
89037
- if (!existsSync34(dir)) mkdirSync9(dir, { recursive: true });
89038
- const file2 = join38(dir, "settings.json");
89314
+ const { mkdirSync: mkdirSync10, existsSync: existsSync35, readFileSync: readFileSync34, writeFileSync: writeFileSync25 } = await import("node:fs");
89315
+ const { join: join39 } = await import("node:path");
89316
+ const dir = join39(ROOT, ".claude");
89317
+ if (!existsSync35(dir)) mkdirSync10(dir, { recursive: true });
89318
+ const file2 = join39(dir, "settings.json");
89039
89319
  let settings = {};
89040
- if (existsSync34(file2)) {
89320
+ if (existsSync35(file2)) {
89041
89321
  try {
89042
- settings = JSON.parse(readFileSync33(file2, "utf8"));
89322
+ settings = JSON.parse(readFileSync34(file2, "utf8"));
89043
89323
  } catch {
89044
89324
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
89045
89325
  process.exit(2);
@@ -89085,10 +89365,10 @@ async function installClaudeHooks(port) {
89085
89365
  dropErrata(list);
89086
89366
  list.push({ hooks: [{ type: "command", command: injectCmd }] });
89087
89367
  }
89088
- writeFileSync24(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
89368
+ writeFileSync25(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
89089
89369
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
89090
89370
  await installClaudeMcpConfig();
89091
- const claudeMd = join38(ROOT, "CLAUDE.md");
89371
+ const claudeMd = join39(ROOT, "CLAUDE.md");
89092
89372
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
89093
89373
  if (recall.kind === "collision") {
89094
89374
  console.warn(
@@ -89100,15 +89380,15 @@ async function installClaudeHooks(port) {
89100
89380
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
89101
89381
  }
89102
89382
  async function installClaudeMcpConfig() {
89103
- const { mkdirSync: mkdirSync9, existsSync: existsSync34, readFileSync: readFileSync33, writeFileSync: writeFileSync24 } = await import("node:fs");
89104
- const { join: join38, dirname: dirname13 } = await import("node:path");
89105
- const file2 = join38(ROOT, ".mcp.json");
89383
+ const { mkdirSync: mkdirSync10, existsSync: existsSync35, readFileSync: readFileSync34, writeFileSync: writeFileSync25 } = await import("node:fs");
89384
+ const { join: join39, dirname: dirname13 } = await import("node:path");
89385
+ const file2 = join39(ROOT, ".mcp.json");
89106
89386
  const dir = dirname13(file2);
89107
- if (!existsSync34(dir)) mkdirSync9(dir, { recursive: true });
89387
+ if (!existsSync35(dir)) mkdirSync10(dir, { recursive: true });
89108
89388
  let cfg = {};
89109
- if (existsSync34(file2)) {
89389
+ if (existsSync35(file2)) {
89110
89390
  try {
89111
- cfg = JSON.parse(readFileSync33(file2, "utf8"));
89391
+ cfg = JSON.parse(readFileSync34(file2, "utf8"));
89112
89392
  } catch {
89113
89393
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
89114
89394
  process.exit(2);
@@ -89116,21 +89396,21 @@ async function installClaudeMcpConfig() {
89116
89396
  }
89117
89397
  cfg.mcpServers ??= {};
89118
89398
  cfg.mcpServers["errata"] = errataMcpInvocation();
89119
- writeFileSync24(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
89399
+ writeFileSync25(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
89120
89400
  console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
89121
89401
  console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
89122
89402
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
89123
89403
  }
89124
89404
  async function installCursorMcpConfig() {
89125
- const { mkdirSync: mkdirSync9, existsSync: existsSync34, readFileSync: readFileSync33, writeFileSync: writeFileSync24 } = await import("node:fs");
89126
- const { join: join38 } = await import("node:path");
89127
- const dir = join38(ROOT, ".cursor");
89128
- if (!existsSync34(dir)) mkdirSync9(dir, { recursive: true });
89129
- const file2 = join38(dir, "mcp.json");
89405
+ const { mkdirSync: mkdirSync10, existsSync: existsSync35, readFileSync: readFileSync34, writeFileSync: writeFileSync25 } = await import("node:fs");
89406
+ const { join: join39 } = await import("node:path");
89407
+ const dir = join39(ROOT, ".cursor");
89408
+ if (!existsSync35(dir)) mkdirSync10(dir, { recursive: true });
89409
+ const file2 = join39(dir, "mcp.json");
89130
89410
  let cfg = {};
89131
- if (existsSync34(file2)) {
89411
+ if (existsSync35(file2)) {
89132
89412
  try {
89133
- cfg = JSON.parse(readFileSync33(file2, "utf8"));
89413
+ cfg = JSON.parse(readFileSync34(file2, "utf8"));
89134
89414
  } catch {
89135
89415
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
89136
89416
  process.exit(2);
@@ -89138,7 +89418,7 @@ async function installCursorMcpConfig() {
89138
89418
  }
89139
89419
  cfg.mcpServers ??= {};
89140
89420
  cfg.mcpServers["errata"] = errataMcpInvocation();
89141
- writeFileSync24(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
89421
+ writeFileSync25(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
89142
89422
  console.log(`installed Cursor MCP server config \u2192 ${file2}`);
89143
89423
  console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
89144
89424
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
@@ -89146,39 +89426,21 @@ async function installCursorMcpConfig() {
89146
89426
  console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
89147
89427
  }
89148
89428
  async function installCodexHooks(port) {
89149
- const { mkdirSync: mkdirSync9, existsSync: existsSync34, readFileSync: readFileSync33, writeFileSync: writeFileSync24 } = await import("node:fs");
89150
- const { join: join38 } = await import("node:path");
89151
- const dir = join38(ROOT, ".codex");
89152
- if (!existsSync34(dir)) mkdirSync9(dir, { recursive: true });
89153
- const file2 = join38(dir, "config.toml");
89154
- let existing = "";
89155
- if (existsSync34(file2)) {
89156
- existing = readFileSync33(file2, "utf8");
89157
- const beginIdx = existing.indexOf(CODEX_HOOKS_BEGIN);
89158
- const endIdx = existing.indexOf(CODEX_HOOKS_END);
89159
- if (beginIdx >= 0 && endIdx > beginIdx) {
89160
- existing = existing.slice(0, beginIdx).trimEnd() + existing.slice(endIdx + CODEX_HOOKS_END.length).trimStart();
89161
- }
89162
- }
89163
- const block = buildCodexHooksToml(port);
89164
- const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
89165
-
89166
- ${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
89167
- writeFileSync24(file2, final, "utf8");
89429
+ const file2 = writeCodexHooks(ROOT, port);
89168
89430
  console.log(`installed Codex hooks \u2192 ${file2}`);
89169
- console.log(` endpoint: http://127.0.0.1:${port}/api/hook (+ /api/turn on PostToolUse)`);
89170
- console.log("");
89171
- console.log(` Codex reads files via the shell, so the virtual graph surface`);
89172
- console.log(` works by \`cat .errata/g/<verb>/<seed>\` (e.g. cat .errata/g/burst/foo).`);
89173
- console.log("");
89174
- console.log(` Codex has no Stop/SessionEnd hook at this installed version, so`);
89175
- console.log(` [!\u2026]/(fix:[\u2026]) tags are harvested via the PostToolUse-triggered`);
89176
- console.log(` /api/turn call above instead \u2014 every turn with a tool call is`);
89177
- console.log(` covered; a tool-less final turn is picked up on this workspace's`);
89178
- console.log(` next daemon boot replay. Re-run this after a Codex upgrade in`);
89179
- console.log(` case a newer version adds a real turn-boundary hook.`);
89180
- console.log(` If [features] hooks=false in your config.toml, set it true. Hook`);
89181
- console.log(` schemas evolve \u2014 if hooks stop firing after an update, re-run this.`);
89431
+ console.log(" Context loads on SessionStart/UserPromptSubmit and refreshes after tools when changed.");
89432
+ console.log(" Tool capture and /api/turn harvesting remain enabled.");
89433
+ console.log(" Restart/resume Codex to reload config, then review and trust the hooks with /hooks.");
89434
+ console.log(" If your Codex version gates hooks, enable [features] codex_hooks = true.");
89435
+ console.log(" Older Codex versions may not support every event; update if hooks do not fire.");
89436
+ }
89437
+ async function refreshLinkedCodexHooks(args2) {
89438
+ if (args2.includes("--skip-hooks") || !hasCodexConfig(ROOT)) return;
89439
+ try {
89440
+ await installCodexHooks(resolveHookPort());
89441
+ } catch (err2) {
89442
+ console.warn(` Codex hook refresh failed: ${err2 instanceof Error ? err2.message : err2}`);
89443
+ }
89182
89444
  }
89183
89445
  function printAiderInstructions() {
89184
89446
  console.log(`Aider doesn't expose programmatic per-tool hooks, so the`);
@@ -89508,7 +89770,7 @@ async function cmdDash(args2) {
89508
89770
  await yieldToLoop2();
89509
89771
  try {
89510
89772
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
89511
- const res = bleedRules(join37(r.root, ".claude", "rules"), items);
89773
+ const res = bleedRules(join38(r.root, ".claude", "rules"), items);
89512
89774
  if (res.written || res.pruned) {
89513
89775
  console.log(
89514
89776
  `[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.6-dev.2511",
3
+ "version": "2.0.6-dev.2550",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -15140,7 +15140,7 @@ var init_symbol_intent = __esm({
15140
15140
  });
15141
15141
 
15142
15142
  // ../../packages/shared/src/wire.ts
15143
- var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, CastaliaIngestNodeSchema, RouteContextCountWireSchema, ANCHOR_COMMIT_SHA_RE, ANCHOR_BODY_HASH_RE, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
15143
+ var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, CastaliaIngestNodeSchema, RouteContextCountWireSchema, ANCHOR_COMMIT_SHA_RE, ANCHOR_BODY_HASH_RE, ANCHOR_SYMBOL_KINDS, ANCHOR_LABEL_KINDS, ANCHOR_LABEL_PATH_RE, ANCHOR_LABEL_QNAME_RE, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
15144
15144
  var init_wire = __esm({
15145
15145
  "../../packages/shared/src/wire.ts"() {
15146
15146
  "use strict";
@@ -15243,6 +15243,21 @@ var init_wire = __esm({
15243
15243
  });
15244
15244
  ANCHOR_COMMIT_SHA_RE = /^[0-9a-f]{7,40}$/;
15245
15245
  ANCHOR_BODY_HASH_RE = /^[0-9a-f]{8,64}$/;
15246
+ ANCHOR_SYMBOL_KINDS = [
15247
+ "Function",
15248
+ "Class",
15249
+ "Method",
15250
+ "Module",
15251
+ "Interface",
15252
+ "Const",
15253
+ "Enum",
15254
+ "TypeAlias",
15255
+ "Namespace",
15256
+ "Property"
15257
+ ];
15258
+ ANCHOR_LABEL_KINDS = [...ANCHOR_SYMBOL_KINDS, "File"];
15259
+ ANCHOR_LABEL_PATH_RE = /^(?![/])(?![A-Za-z]:)(?!(?:.*\/)?\.\.(?:\/|$))[^\x00-\x1f\x7f\\`]{1,512}$/;
15260
+ ANCHOR_LABEL_QNAME_RE = /^[^\x00-\x1f\x7f`]{1,256}$/;
15246
15261
  CastaliaIngestEdgeSchema = external_exports.object({
15247
15262
  fromCanonicalId: external_exports.string().min(6).max(160),
15248
15263
  toCanonicalId: external_exports.string().min(6).max(160),
@@ -15262,7 +15277,17 @@ var init_wire = __esm({
15262
15277
  * classify the anchor current / pre-change; absent ⇒ the pre-versioning
15263
15278
  * contract, unverified. Only meaningful on `ANCHORED_AT`. */
15264
15279
  observedAtCommit: external_exports.string().regex(ANCHOR_COMMIT_SHA_RE).optional(),
15265
- symbolContentHash: external_exports.string().regex(ANCHOR_BODY_HASH_RE).optional()
15280
+ symbolContentHash: external_exports.string().regex(ANCHOR_BODY_HASH_RE).optional(),
15281
+ /** PJ-anchor-labels: the READABLE identity of the anchor's target —
15282
+ * repo-relative path, qualified name (absent for a File), kind and line.
15283
+ * Sent only for a project whose owner opted in; the door strips them again
15284
+ * for any project that has not (the daemon's flag is not trusted alone).
15285
+ * Prefixed `label*` so no local edge attr (`anchorLine` lives there
15286
+ * natively) can ride out under a shared key. */
15287
+ labelRelPath: external_exports.string().regex(ANCHOR_LABEL_PATH_RE).optional(),
15288
+ labelQname: external_exports.string().regex(ANCHOR_LABEL_QNAME_RE).optional(),
15289
+ labelKind: external_exports.enum(ANCHOR_LABEL_KINDS).optional(),
15290
+ labelLine: external_exports.number().int().min(1).max(1e7).optional()
15266
15291
  }).optional()
15267
15292
  });
15268
15293
  SymbolSummarySidecarSchema = external_exports.record(