@mrciphersmith/keryx 0.3.26 → 0.3.27

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/dist/cli.js +128 -50
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -12991,7 +12991,7 @@ var package_default;
12991
12991
  var init_package = __esm(() => {
12992
12992
  package_default = {
12993
12993
  name: "@mrciphersmith/keryx",
12994
- version: "0.3.26",
12994
+ version: "0.3.27",
12995
12995
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
12996
12996
  private: false,
12997
12997
  publishConfig: {
@@ -71063,7 +71063,7 @@ ${shown.join(`
71063
71063
  result = precomputedResult;
71064
71064
  } else {
71065
71065
  try {
71066
- result = await executeCall(call, toolByName, io.requestApproval, io.permissionMode, io.readOnly, io.onAutoApproved, hasInvocationCapacity, reserveInvocation, invocationBudget.maxCalls, signal, deps.busLeases, deps.hardDeny === undefined ? undefined : { check: deps.hardDeny, onDenied: io.onUnattendedDenial }, deps.hooks, untrustedOrigin);
71066
+ result = await executeCall(call, toolByName, io.requestApproval, io.permissionMode, io.readOnly, io.onAutoApproved, hasInvocationCapacity, reserveInvocation, invocationBudget.maxCalls, signal, deps.busLeases, deps.hardDeny === undefined ? undefined : { check: deps.hardDeny, onDenied: io.onUnattendedDenial }, deps.hooks, untrustedOrigin, io.trustedMcpTools, io.mcpToolFingerprint);
71067
71067
  } catch (err) {
71068
71068
  const message = err instanceof Error ? err.message : String(err);
71069
71069
  result = { output: `${call.name} failed: ${message}`, isError: true };
@@ -71633,7 +71633,7 @@ function composeWithHook(toolName, rawDecision, hookResult, interactive) {
71633
71633
  }
71634
71634
  return { decision, hookTightened: true, hookAsked, ...denyMessage !== undefined ? { denyMessage } : {} };
71635
71635
  }
71636
- async function executeCall(call, toolByName, requestApproval, permissionMode, readOnly, onAutoApproved, hasInvocationCapacity, reserveInvocation, maxToolCalls, signal, busLeases, hardDeny, hooks, untrustedOrigin = false) {
71636
+ async function executeCall(call, toolByName, requestApproval, permissionMode, readOnly, onAutoApproved, hasInvocationCapacity, reserveInvocation, maxToolCalls, signal, busLeases, hardDeny, hooks, untrustedOrigin = false, trustedMcpTools, mcpToolFingerprint) {
71637
71637
  const tool = toolByName.get(call.name);
71638
71638
  if (tool === undefined) {
71639
71639
  return { output: `unknown tool: ${call.name}`, isError: true };
@@ -71694,13 +71694,20 @@ async function executeCall(call, toolByName, requestApproval, permissionMode, re
71694
71694
  publishLease
71695
71695
  });
71696
71696
  const gated = composeWithHook(call.name, rawDecision, hookResult, hookInteractive);
71697
+ const mcpFqn = call.name === "use_tool" && typeof input.tool_name === "string" ? input.tool_name : undefined;
71698
+ const currentMcpFingerprint = mcpFqn !== undefined ? mcpToolFingerprint?.(mcpFqn) : undefined;
71699
+ if (mcpFqn !== undefined && trustedMcpTools?.has(mcpFqn) === true && trustedMcpTools.get(mcpFqn) !== currentMcpFingerprint) {
71700
+ trustedMcpTools.delete(mcpFqn);
71701
+ }
71702
+ const trustedMcp = mode === "trust" && mcpFqn !== undefined && trustedMcpTools?.has(mcpFqn) === true;
71703
+ const mcpTrustEligible = mcpFqn !== undefined && mode === "trust" && !gated.hookAsked && currentMcpFingerprint !== undefined;
71697
71704
  if (gated.decision === "deny") {
71698
71705
  return {
71699
71706
  output: gated.hookTightened ? gated.denyMessage : `tool "${call.name}" is not permitted while read-only mode (/plan) is on`,
71700
71707
  isError: true
71701
71708
  };
71702
71709
  }
71703
- if (gated.decision === "auto" && !untrustedOrigin) {
71710
+ if (gated.decision === "auto" && !untrustedOrigin || trustedMcp && !untrustedOrigin && !gated.hookAsked && !isReadOnly) {
71704
71711
  onAutoApproved?.(call.name, call.input, { destructive, credentials });
71705
71712
  } else {
71706
71713
  const fingerprint = toolCallHash(call.name, call.input);
@@ -71711,11 +71718,15 @@ async function executeCall(call, toolByName, requestApproval, permissionMode, re
71711
71718
  ...publishLease ? { publishLease } : {},
71712
71719
  ...publishLease && publishLeaseHolder !== undefined ? { publishLeaseDetail: `held by @${publishLeaseHolder.name} \u2014 "${publishLeaseHolder.reason}"` } : {},
71713
71720
  ...gated.hookAsked ? { hookAsk: true } : {},
71714
- ...untrustedOrigin ? { untrustedOrigin: true } : {}
71721
+ ...untrustedOrigin ? { untrustedOrigin: true } : {},
71722
+ ...mcpTrustEligible ? untrustedOrigin ? { mcpTrustWithheld: true } : { mcpTrustAvailable: true } : {}
71715
71723
  });
71716
71724
  if (!isApprovalFor(response, fingerprint)) {
71717
71725
  return { output: untrustedOrigin ? untrustedDenial : "command not approved by the user; not executed", isError: true };
71718
71726
  }
71727
+ if (mcpFqn !== undefined && currentMcpFingerprint !== undefined && typeof response === "object" && response.trustMcpTool === true && mcpTrustEligible && !untrustedOrigin) {
71728
+ trustedMcpTools?.set(mcpFqn, currentMcpFingerprint);
71729
+ }
71719
71730
  }
71720
71731
  } else if (risk === "delegate") {
71721
71732
  const rawDecision = resolveApprovalDecision({
@@ -77704,6 +77715,26 @@ var init_workspace_lifecycle_tool = __esm(() => {
77704
77715
  });
77705
77716
 
77706
77717
  // src/mcp-servers/catalog.ts
77718
+ import { createHash as createHash54 } from "crypto";
77719
+ function canonicalJson3(value) {
77720
+ if (value === undefined)
77721
+ return "null";
77722
+ if (value === null || typeof value !== "object")
77723
+ return JSON.stringify(value);
77724
+ if (Array.isArray(value))
77725
+ return `[${value.map(canonicalJson3).join(",")}]`;
77726
+ const record = value;
77727
+ const keys = Object.keys(record).filter((key) => record[key] !== undefined).sort();
77728
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson3(record[key])}`).join(",")}}`;
77729
+ }
77730
+ function toolDefinitionFingerprint(entry) {
77731
+ const canonical = canonicalJson3({
77732
+ name: entry.fqn,
77733
+ description: entry.description ?? null,
77734
+ inputSchema: entry.inputSchema ?? null
77735
+ });
77736
+ return createHash54("sha256").update(canonical).digest("hex");
77737
+ }
77707
77738
  function buildFqn(server, rawName) {
77708
77739
  return `${server}${FQN_DELIMITER}${rawName}`;
77709
77740
  }
@@ -79640,7 +79671,7 @@ var init_shell_events = __esm(() => {
79640
79671
  // src/lib/shell-permissions.ts
79641
79672
  import { existsSync as existsSync32 } from "fs";
79642
79673
  import path192 from "path";
79643
- import { createHash as createHash54 } from "crypto";
79674
+ import { createHash as createHash55 } from "crypto";
79644
79675
  function validateShellPattern(pattern) {
79645
79676
  const trimmed = pattern.trim();
79646
79677
  if (trimmed.length === 0) {
@@ -79847,7 +79878,7 @@ function shellPermissionsFingerprint(dir) {
79847
79878
  if (!read.ok) {
79848
79879
  return "";
79849
79880
  }
79850
- return createHash54("sha256").update(read.text, "utf8").digest("hex");
79881
+ return createHash55("sha256").update(read.text, "utf8").digest("hex");
79851
79882
  } catch {
79852
79883
  return "";
79853
79884
  }
@@ -80716,11 +80747,23 @@ function renderUseToolApprovalLines(description, meta) {
80716
80747
  if (meta?.destructive === true) {
80717
80748
  lines.push(" this tool is treated as destructive \u2014 it is a third party's code");
80718
80749
  }
80719
- if (meta?.untrustedOrigin === true) {
80720
- lines.push(" \u26A0 follows untrusted external content \u2014 that content cannot authorize this call");
80750
+ for (const notice of untrustedOriginNotices(meta)) {
80751
+ lines.push(` ${notice}`);
80721
80752
  }
80722
80753
  return lines;
80723
80754
  }
80755
+ function untrustedOriginNotices(meta) {
80756
+ if (meta?.untrustedOrigin !== true)
80757
+ return [];
80758
+ const notices = ["\u26A0 follows untrusted external content \u2014 that content cannot authorize this call"];
80759
+ if (meta.mcpTrustWithheld === true) {
80760
+ notices.push("trust for this session is not offered: this turn contains external content");
80761
+ }
80762
+ return notices;
80763
+ }
80764
+ function mcpTrustOffered(meta, resolvable) {
80765
+ return meta?.mcpTrustAvailable === true && meta.untrustedOrigin !== true && meta.fingerprint !== undefined && resolvable;
80766
+ }
80724
80767
  function summariseUseToolApproval(description) {
80725
80768
  return `${description.tool} on ${description.server}`;
80726
80769
  }
@@ -80733,6 +80776,7 @@ function isApprovalYes(answer) {
80733
80776
  async function promptUseToolApproval(io, input, meta, resolve, style, gutter = "") {
80734
80777
  const paint = style ?? { yellow: (t) => t, dim: (t) => t, green: (t) => t, red: (t) => t };
80735
80778
  const described = describeUseToolApproval(input, resolve);
80779
+ const canTrust = mcpTrustOffered(meta, resolve?.(described.fqn) !== undefined);
80736
80780
  const lines = renderUseToolApprovalLines(described, meta);
80737
80781
  io.out(`
80738
80782
  `);
@@ -80741,19 +80785,29 @@ async function promptUseToolApproval(io, input, meta, resolve, style, gutter = "
80741
80785
  `);
80742
80786
  }
80743
80787
  io.out(`
80744
- ${gutter}${paint.dim("[y/N] ")}`);
80788
+ ${gutter}${paint.dim(canTrust ? "[y/N/T=trust this tool for session] " : "[y/N] ")}`);
80745
80789
  const answer = await io.readLine() ?? "";
80746
- const approved = isApprovalYes(answer);
80747
- io.out(approved ? paint.green(`approved
80790
+ const trust = canTrust && /^t(rust)?$/i.test(answer.trim());
80791
+ const approved = trust || isApprovalYes(answer);
80792
+ io.out(approved ? paint.green(trust ? `approved \xB7 trusted for this session
80793
+ ` : `approved
80748
80794
  `) : paint.red(`denied
80749
80795
  `));
80750
80796
  if (!approved)
80751
80797
  return false;
80752
- return meta?.fingerprint !== undefined ? { approved: true, fingerprint: meta.fingerprint } : true;
80798
+ return meta?.fingerprint !== undefined ? { approved: true, fingerprint: meta.fingerprint, ...trust ? { trustMcpTool: true } : {} } : true;
80753
80799
  }
80754
80800
  function isDockApproval(id) {
80755
80801
  return id === APPROVAL_ALLOW_ID;
80756
80802
  }
80803
+ function mcpDockVerdict(id, canTrust, fingerprint) {
80804
+ if (isDockApproval(id))
80805
+ return true;
80806
+ if (id === "trust-mcp" && canTrust && fingerprint !== undefined) {
80807
+ return { approved: true, fingerprint, trustMcpTool: true };
80808
+ }
80809
+ return false;
80810
+ }
80757
80811
  function catalogResolver(catalog) {
80758
80812
  return (fqn) => {
80759
80813
  if (catalog === undefined)
@@ -80762,8 +80816,15 @@ function catalogResolver(catalog) {
80762
80816
  return entry === undefined ? undefined : { server: entry.server, tool: entry.rawName };
80763
80817
  };
80764
80818
  }
80819
+ function catalogFingerprintResolver(catalog) {
80820
+ return (fqn) => {
80821
+ const entry = catalog?.entries.find((candidate) => candidate.fqn === fqn);
80822
+ return entry === undefined ? undefined : toolDefinitionFingerprint(entry);
80823
+ };
80824
+ }
80765
80825
  var FQN_SEPARATOR = "__", MAX_ARGUMENT_CHARS = 400, MAX_ARGUMENT_KEYS = 40, MAX_IDENTIFIER_CHARS = 80, APPROVAL_ALLOW_ID = "allow";
80766
80826
  var init_approval_render = __esm(() => {
80827
+ init_catalog4();
80767
80828
  init_config9();
80768
80829
  init_tools2();
80769
80830
  });
@@ -81793,7 +81854,7 @@ var init_child_model_request = __esm(() => {
81793
81854
  });
81794
81855
 
81795
81856
  // src/harness/tool/builtin/spawn-subagent-tool.ts
81796
- import { createHash as createHash55, randomUUID as randomUUID24 } from "crypto";
81857
+ import { createHash as createHash56, randomUUID as randomUUID24 } from "crypto";
81797
81858
  import { execFile as execFile7 } from "child_process";
81798
81859
  import { lstat as lstat13, mkdtemp as mkdtemp2, readFile as readFile91, realpath as realpath14, rm as rm13 } from "fs/promises";
81799
81860
  import { tmpdir as tmpdir6 } from "os";
@@ -81871,7 +81932,7 @@ function readExternalRuntimeRequest(input) {
81871
81932
  return raw.kind === "external" ? raw : undefined;
81872
81933
  }
81873
81934
  function sha2568(text) {
81874
- return createHash55("sha256").update(text).digest("hex");
81935
+ return createHash56("sha256").update(text).digest("hex");
81875
81936
  }
81876
81937
  async function resolveSubagentCwd(rawCwd, parentCwd) {
81877
81938
  if (rawCwd === undefined) {
@@ -87253,7 +87314,7 @@ var init_http_headers = __esm(() => {
87253
87314
  });
87254
87315
 
87255
87316
  // src/mcp-servers/trust.ts
87256
- import { createHash as createHash56 } from "crypto";
87317
+ import { createHash as createHash57 } from "crypto";
87257
87318
  import path203 from "path";
87258
87319
  function trustFile(configDir) {
87259
87320
  return path203.join(configDir ?? ensureKeryxConfigDir(), "mcp-servers-trust.json");
@@ -87276,7 +87337,7 @@ function serverFingerprint(server) {
87276
87337
  }
87277
87338
  }
87278
87339
  });
87279
- return createHash56("sha256").update(material).digest("hex").slice(0, 32);
87340
+ return createHash57("sha256").update(material).digest("hex").slice(0, 32);
87280
87341
  }
87281
87342
  function sortedKeys(values) {
87282
87343
  return Object.entries(values ?? {}).sort(([a], [b]) => a.localeCompare(b));
@@ -114162,12 +114223,12 @@ var init_config11 = __esm(() => {
114162
114223
  });
114163
114224
 
114164
114225
  // src/wiki/deep-enrich.ts
114165
- import { randomUUID as randomUUID31, createHash as createHash57 } from "crypto";
114226
+ import { randomUUID as randomUUID31, createHash as createHash58 } from "crypto";
114166
114227
  function errorMessage2(cause) {
114167
114228
  return cause instanceof Error ? cause.message : String(cause);
114168
114229
  }
114169
114230
  function sha256Hex7(text) {
114170
- return createHash57("sha256").update(text).digest("hex");
114231
+ return createHash58("sha256").update(text).digest("hex");
114171
114232
  }
114172
114233
  function buildDeepEnrichTools(port) {
114173
114234
  const deepOps = METAPROJECT_OPERATIONS.filter((op) => DEEP_ENRICH_OPS.includes(op.name));
@@ -115768,7 +115829,10 @@ function createForegroundAgentIoFacade(owner, token, io) {
115768
115829
  if (accepts())
115769
115830
  io.onAutoApproved?.(tool, input, meta);
115770
115831
  },
115771
- permissionMode: () => accepts() ? io.permissionMode?.() ?? "ask" : "ask"
115832
+ permissionMode: () => accepts() ? io.permissionMode?.() ?? "ask" : "ask",
115833
+ ...io.trustedMcpTools === undefined ? {} : { trustedMcpTools: io.trustedMcpTools },
115834
+ ...io.mcpToolFingerprint === undefined ? {} : { mcpToolFingerprint: io.mcpToolFingerprint },
115835
+ readOnly: () => !accepts() || (io.readOnly?.() ?? false)
115772
115836
  };
115773
115837
  }
115774
115838
 
@@ -126594,6 +126658,7 @@ async function launchTuiAgentShell(opts) {
126594
126658
  }
126595
126659
  if (isMcpToolCall(tool)) {
126596
126660
  const described = describeUseToolApproval(inputJson, catalogResolver(deps.mcpRuntime?.()?.catalog()));
126661
+ const canTrustMcp = mcpTrustOffered(meta, catalogResolver(deps.mcpRuntime?.()?.catalog())(described.fqn) !== undefined);
126597
126662
  transcript.add(new otui.TextRenderable(r, {
126598
126663
  id: `ap${uid++}`,
126599
126664
  content: otui.t`${roleChunk(otui, "attention", `\u2699 ${described.server} wants to run ${described.tool}`)}`
@@ -126607,6 +126672,9 @@ async function launchTuiAgentShell(opts) {
126607
126672
  content: otui.t`${dimChunk(otui, ` \u2026 arguments truncated at ${MAX_ARGUMENT_CHARS} characters`)}`
126608
126673
  }));
126609
126674
  }
126675
+ for (const notice of untrustedOriginNotices(meta)) {
126676
+ transcript.add(new otui.TextRenderable(r, { id: `ap${uid++}`, content: otui.t`${dimChunk(otui, ` ${notice}`)}` }));
126677
+ }
126610
126678
  chrome.hideMenu();
126611
126679
  setMainAgent("blocked", "approval");
126612
126680
  const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
@@ -126617,17 +126685,19 @@ async function launchTuiAgentShell(opts) {
126617
126685
  signal: foregroundOperation.signal,
126618
126686
  options: [
126619
126687
  { id: APPROVAL_ALLOW_ID, label: "Approve", description: `run ${described.tool} on ${described.server}` },
126688
+ ...canTrustMcp ? [{ id: "trust-mcp", label: "Trust this tool (this session)", description: `Skip future approvals for ${described.fqn} in trust mode` }] : [],
126620
126689
  { id: "deny", label: "Deny", description: "the tool call is refused", recommended: true }
126621
126690
  ]
126622
126691
  }));
126623
126692
  input.focus();
126624
- const allowed = isDockApproval(id);
126693
+ const verdict = mcpDockVerdict(id, canTrustMcp, meta?.fingerprint);
126694
+ const allowed = verdict !== false;
126625
126695
  setMainAgent("running", allowed ? "write" : "denied");
126626
126696
  transcript.add(new otui.TextRenderable(r, {
126627
126697
  id: `ap${uid++}`,
126628
126698
  content: allowed ? otui.t`${roleChunk(otui, "ok", `\u25C7 ${described.fqn} approved`)}` : otui.t`${roleChunk(otui, "error", `\u25C7 ${described.fqn} denied`)}`
126629
126699
  }));
126630
- return allowed;
126700
+ return verdict;
126631
126701
  }
126632
126702
  if (tool.startsWith(MCP_ELICITATION_TOOL_PREFIX)) {
126633
126703
  const described = describeElicitationPrompt(tool, inputJson) ?? { message: inputJson, command: undefined };
@@ -126826,6 +126896,8 @@ async function launchTuiAgentShell(opts) {
126826
126896
  const sessionCwd = opts.session?.cwd ?? process.cwd();
126827
126897
  let permissionMode = opts.initialPermissionMode ?? getProjectPermissionMode(sessionCwd) ?? DEFAULT_PERMISSION_MODE;
126828
126898
  io.permissionMode = () => permissionMode;
126899
+ io.trustedMcpTools = new Map;
126900
+ io.mcpToolFingerprint = (fqn) => catalogFingerprintResolver(deps.mcpRuntime?.()?.catalog())(fqn);
126829
126901
  let readOnly = false;
126830
126902
  io.readOnly = () => readOnly;
126831
126903
  const paintModeRow = () => {
@@ -126872,6 +126944,7 @@ async function launchTuiAgentShell(opts) {
126872
126944
  splash?.removeIfShown();
126873
126945
  }
126874
126946
  liveSession = opened.handle;
126947
+ io.trustedMcpTools?.clear();
126875
126948
  history = previewHistory === true ? opened.history.slice(-SESSION_PREVIEW_MESSAGE_COUNT) : opened.history;
126876
126949
  archive = opened.archive.length > 0 ? [...opened.archive] : [...opened.history];
126877
126950
  nextArchiveIndex = history.length;
@@ -131492,6 +131565,8 @@ ${text.trim()}`;
131492
131565
  const sessionsOn = sessionOpts !== undefined && sessionOpts.enabled !== false;
131493
131566
  let permissionMode = initialPermissionMode ?? getProjectPermissionMode(sessionCwd) ?? DEFAULT_PERMISSION_MODE;
131494
131567
  agentIo.permissionMode = () => permissionMode;
131568
+ agentIo.trustedMcpTools = new Map;
131569
+ agentIo.mcpToolFingerprint = (fqn) => catalogFingerprintResolver(deps.mcpRuntime?.()?.catalog())(fqn);
131495
131570
  let reasoningSessionOverride;
131496
131571
  let readOnly = false;
131497
131572
  agentIo.readOnly = () => readOnly;
@@ -131549,6 +131624,7 @@ ${text.trim()}`;
131549
131624
  try {
131550
131625
  const next = switchLeasedSession(lease, () => openLeased({ cwd: sessionCwd, provider: deps.providerId, model: deps.modelId }));
131551
131626
  holdLease(next.lease);
131627
+ agentIo.trustedMcpTools?.clear();
131552
131628
  return next.handle;
131553
131629
  } catch (cause) {
131554
131630
  agentIo.onSystem?.(`${cause instanceof Error ? cause.message : String(cause)}
@@ -131893,6 +131969,7 @@ ${GUTTER}${turnSeparator()}
131893
131969
  } else {
131894
131970
  history = [];
131895
131971
  archive = [];
131972
+ agentIo.trustedMcpTools?.clear();
131896
131973
  agentIo.onSystem?.(`Conversation cleared.
131897
131974
  `);
131898
131975
  }
@@ -132822,6 +132899,7 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
132822
132899
  }),
132823
132900
  idSeq: () => randomUUID34(),
132824
132901
  askUser: invokeAskUserHost,
132902
+ mcpRuntime: () => mcpRuntime,
132825
132903
  sweepBackgroundJobs: () => jobRegistry.sweepAll(),
132826
132904
  ...resetSubagentBudget !== undefined ? { resetSubagentBudget } : {},
132827
132905
  ...Object.keys(initialModelParams).length > 0 ? { modelParams: initialModelParams } : {},
@@ -133361,7 +133439,7 @@ var init_retired_rules = __esm(() => {
133361
133439
  // src/gdskills/guarded-fs-ops.ts
133362
133440
  import { cp, lstat as lstat14, readFile as readFile129, readdir as readdir44, realpath as realpath15, unlink as unlink2 } from "fs/promises";
133363
133441
  import { existsSync as existsSync42 } from "fs";
133364
- import { createHash as createHash58 } from "crypto";
133442
+ import { createHash as createHash59 } from "crypto";
133365
133443
  import path258 from "path";
133366
133444
  import { fileURLToPath as fileURLToPath5 } from "url";
133367
133445
  function isErrnoException(error) {
@@ -133555,7 +133633,7 @@ async function removeUnmodifiedRetiredRules(rulesTarget, fsOps = { unlink: unlin
133555
133633
  }
133556
133634
  stage = "read";
133557
133635
  const content = await readFile129(installedPath);
133558
- const hash = createHash58("sha256").update(normalizeRetiredRuleContent(content)).digest("hex");
133636
+ const hash = createHash59("sha256").update(normalizeRetiredRuleContent(content)).digest("hex");
133559
133637
  if (retired.shippedSha256.includes(hash)) {
133560
133638
  stage = "unlink";
133561
133639
  await fsOps.unlink(installedPath);
@@ -144007,7 +144085,7 @@ var init_authoring_lint = __esm(() => {
144007
144085
  });
144008
144086
 
144009
144087
  // src/gdskills/governance/stocktake.ts
144010
- import { createHash as createHash59 } from "crypto";
144088
+ import { createHash as createHash60 } from "crypto";
144011
144089
  import { existsSync as existsSync46, readdirSync as readdirSync11, readFileSync as readFileSync22, statSync as statSync16 } from "fs";
144012
144090
  import path279 from "path";
144013
144091
  function cacheKeyMatches(cached, inputs, quick) {
@@ -144015,7 +144093,7 @@ function cacheKeyMatches(cached, inputs, quick) {
144015
144093
  }
144016
144094
  function catalogFingerprint(catalog) {
144017
144095
  const parts = [...catalog].map((entry) => `${entry.id}:${entry.sha256}`).sort();
144018
- return createHash59("sha256").update(parts.join(`
144096
+ return createHash60("sha256").update(parts.join(`
144019
144097
  `)).digest("hex");
144020
144098
  }
144021
144099
  function verificationReportHash(root, entry) {
@@ -144023,7 +144101,7 @@ function verificationReportHash(root, entry) {
144023
144101
  if (!existsSync46(reportPath))
144024
144102
  return null;
144025
144103
  try {
144026
- return createHash59("sha256").update(readFileSync22(reportPath, "utf8")).digest("hex");
144104
+ return createHash60("sha256").update(readFileSync22(reportPath, "utf8")).digest("hex");
144027
144105
  } catch {
144028
144106
  return null;
144029
144107
  }
@@ -144045,7 +144123,7 @@ function referencesHash(entry) {
144045
144123
  }
144046
144124
  };
144047
144125
  walk(referencesDir, "");
144048
- const hash = createHash59("sha256");
144126
+ const hash = createHash60("sha256");
144049
144127
  for (const rel of files) {
144050
144128
  hash.update(rel);
144051
144129
  hash.update("\x00");
@@ -145492,7 +145570,7 @@ var init_glob = __esm(() => {
145492
145570
  });
145493
145571
 
145494
145572
  // src/gdskills/manifest/plan.ts
145495
- import { createHash as createHash60 } from "crypto";
145573
+ import { createHash as createHash61 } from "crypto";
145496
145574
  import path283 from "path";
145497
145575
  function destinationRootsForTarget(target) {
145498
145576
  if (target === "claude")
@@ -145504,7 +145582,7 @@ function destinationRootsForTarget(target) {
145504
145582
  }
145505
145583
  function stackInputsSha256(stack) {
145506
145584
  const { detectedAt: _detectedAt, ...rest } = stack;
145507
- return createHash60("sha256").update(stableStringify3(rest)).digest("hex");
145585
+ return createHash61("sha256").update(stableStringify3(rest)).digest("hex");
145508
145586
  }
145509
145587
  function stableStringify3(value) {
145510
145588
  if (Array.isArray(value)) {
@@ -163952,7 +164030,7 @@ var init_detect3 = __esm(() => {
163952
164030
  });
163953
164031
 
163954
164032
  // src/stack/service.ts
163955
- import { createHash as createHash61 } from "crypto";
164033
+ import { createHash as createHash62 } from "crypto";
163956
164034
  import { readFile as readFile162 } from "fs/promises";
163957
164035
  import path316 from "path";
163958
164036
  function stackJsonPath(root) {
@@ -163978,7 +164056,7 @@ function serializeStackDetection(doc) {
163978
164056
  }
163979
164057
  function fingerprintOf(core) {
163980
164058
  const canonical = JSON.stringify(canonicalize2(core));
163981
- return createHash61("sha256").update(canonical, "utf8").digest("hex");
164059
+ return createHash62("sha256").update(canonical, "utf8").digest("hex");
163982
164060
  }
163983
164061
  async function readStackDetection(root) {
163984
164062
  try {
@@ -164252,9 +164330,9 @@ function evaluateCompletion(input, deps) {
164252
164330
  var SCHEMA_VERSION3 = 1;
164253
164331
 
164254
164332
  // src/harness/evidence/redaction.ts
164255
- import { createHash as createHash62 } from "crypto";
164333
+ import { createHash as createHash63 } from "crypto";
164256
164334
  function hashContent(content) {
164257
- return createHash62("sha256").update(content, "utf8").digest("hex");
164335
+ return createHash63("sha256").update(content, "utf8").digest("hex");
164258
164336
  }
164259
164337
  function redactForPersistence(content, deps) {
164260
164338
  const scan = deps.scan(content);
@@ -164304,7 +164382,7 @@ async function metaprojectBlastRadius(port, target) {
164304
164382
  }
164305
164383
 
164306
164384
  // src/harness/session/session.ts
164307
- import { createHash as createHash63 } from "crypto";
164385
+ import { createHash as createHash64 } from "crypto";
164308
164386
  function canonicalStringify(value) {
164309
164387
  if (Array.isArray(value)) {
164310
164388
  return `[${value.map(canonicalStringify).join(",")}]`;
@@ -164317,7 +164395,7 @@ function canonicalStringify(value) {
164317
164395
  return JSON.stringify(value) ?? "null";
164318
164396
  }
164319
164397
  function sha2569(input) {
164320
- return createHash63("sha256").update(input, "utf8").digest("hex");
164398
+ return createHash64("sha256").update(input, "utf8").digest("hex");
164321
164399
  }
164322
164400
  function deepFreeze(value) {
164323
164401
  if (value !== null && typeof value === "object") {
@@ -164461,7 +164539,7 @@ var init_startup = __esm(() => {
164461
164539
  });
164462
164540
 
164463
164541
  // src/harness/run/run.ts
164464
- import { createHash as createHash64 } from "crypto";
164542
+ import { createHash as createHash65 } from "crypto";
164465
164543
  function aliasRunHookToolName(keryxToolName) {
164466
164544
  return RUN_HOOK_TOOL_NAME_ALIASES[keryxToolName] ?? keryxToolName;
164467
164545
  }
@@ -164477,7 +164555,7 @@ function canonicalize3(value) {
164477
164555
  return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalize3(record[key])}`).join(",")}}`;
164478
164556
  }
164479
164557
  function sha25610(input) {
164480
- return createHash64("sha256").update(input, "utf8").digest("hex");
164558
+ return createHash65("sha256").update(input, "utf8").digest("hex");
164481
164559
  }
164482
164560
  function uniqueInOrder2(values) {
164483
164561
  const seen = new Set;
@@ -165052,7 +165130,7 @@ var init_replay = __esm(() => {
165052
165130
  });
165053
165131
 
165054
165132
  // src/harness/tool/registry.ts
165055
- import { createHash as createHash65 } from "crypto";
165133
+ import { createHash as createHash66 } from "crypto";
165056
165134
  function canonicalize4(value) {
165057
165135
  if (value === null || typeof value !== "object") {
165058
165136
  return JSON.stringify(value) ?? "null";
@@ -165066,7 +165144,7 @@ function canonicalize4(value) {
165066
165144
  return `{${entries.join(",")}}`;
165067
165145
  }
165068
165146
  function sha25611(input) {
165069
- return createHash65("sha256").update(input, "utf8").digest("hex");
165147
+ return createHash66("sha256").update(input, "utf8").digest("hex");
165070
165148
  }
165071
165149
  function definitionHash(definition) {
165072
165150
  return sha25611(canonicalize4(definition));
@@ -165219,9 +165297,9 @@ var init_executor = __esm(() => {
165219
165297
 
165220
165298
  // src/harness/process/real-process-adapter.ts
165221
165299
  import { spawnSync as spawnSync8 } from "child_process";
165222
- import { createHash as createHash66 } from "crypto";
165300
+ import { createHash as createHash67 } from "crypto";
165223
165301
  function sha256Hex8(input) {
165224
- return createHash66("sha256").update(input, "utf8").digest("hex");
165302
+ return createHash67("sha256").update(input, "utf8").digest("hex");
165225
165303
  }
165226
165304
  function byteLength2(chunk) {
165227
165305
  if (chunk === null || chunk === undefined)
@@ -166979,7 +167057,7 @@ var init_session3 = __esm(() => {
166979
167057
  });
166980
167058
 
166981
167059
  // src/acp/session-mcp.ts
166982
- import { createHash as createHash67 } from "crypto";
167060
+ import { createHash as createHash68 } from "crypto";
166983
167061
  function isRecord6(value) {
166984
167062
  return typeof value === "object" && value !== null && !Array.isArray(value);
166985
167063
  }
@@ -167106,7 +167184,7 @@ function acpMcpSetKey(parsed) {
167106
167184
  })),
167107
167185
  refused: parsed.refused
167108
167186
  };
167109
- return createHash67("sha256").update(JSON.stringify(canonical)).digest("hex");
167187
+ return createHash68("sha256").update(JSON.stringify(canonical)).digest("hex");
167110
167188
  }
167111
167189
  function startAcpSessionMcp(parsed, options = {}) {
167112
167190
  const refused = parsed.refused.map((problem) => ({ name: problem.name, reason: scrub(problem.reason, parsed.secrets) }));
@@ -168985,7 +169063,7 @@ var init_modules = __esm(() => {
168985
169063
  });
168986
169064
 
168987
169065
  // src/lib/serve-credential.ts
168988
- import { createHash as createHash68, randomBytes as randomBytes11, randomUUID as randomUUID43 } from "crypto";
169066
+ import { createHash as createHash69, randomBytes as randomBytes11, randomUUID as randomUUID43 } from "crypto";
168989
169067
  import {
168990
169068
  chmodSync as chmodSync5,
168991
169069
  closeSync as closeSync7,
@@ -169012,10 +169090,10 @@ function constantTimeEqual(a, b) {
169012
169090
  return difference === 0;
169013
169091
  }
169014
169092
  function hashToken(salt, token) {
169015
- return createHash68("sha256").update(Buffer.from(salt, "hex")).update(Buffer.from(token, "utf8")).digest("hex");
169093
+ return createHash69("sha256").update(Buffer.from(salt, "hex")).update(Buffer.from(token, "utf8")).digest("hex");
169016
169094
  }
169017
169095
  function credentialFingerprint(record) {
169018
- return createHash68("sha256").update(`keryx-serve-fingerprint:${record.hash}`).digest("hex").slice(0, 8);
169096
+ return createHash69("sha256").update(`keryx-serve-fingerprint:${record.hash}`).digest("hex").slice(0, 8);
169019
169097
  }
169020
169098
  function isValidRecord(value) {
169021
169099
  if (typeof value !== "object" || value === null) {
@@ -169229,7 +169307,7 @@ var init_serve_throttle = __esm(() => {
169229
169307
  });
169230
169308
 
169231
169309
  // src/lib/serve-turn-store.ts
169232
- import { createHash as createHash69 } from "crypto";
169310
+ import { createHash as createHash70 } from "crypto";
169233
169311
  import { existsSync as existsSync50, readdirSync as readdirSync12, rmSync as rmSync4 } from "fs";
169234
169312
  import path321 from "path";
169235
169313
  function turnsRoot(dir) {
@@ -169240,11 +169318,11 @@ function turnDir(turnId, dir) {
169240
169318
  }
169241
169319
  function keyPath(project, idempotencyKey, dir) {
169242
169320
  const projectBytes = Buffer.byteLength(project, "utf8");
169243
- const digest = createHash69("sha256").update(`${projectBytes}:${project}\x00${idempotencyKey}`, "utf8").digest("hex");
169321
+ const digest = createHash70("sha256").update(`${projectBytes}:${project}\x00${idempotencyKey}`, "utf8").digest("hex");
169244
169322
  return path321.join(turnsRoot(dir), "keys", `${digest}.json`);
169245
169323
  }
169246
169324
  function legacyKeyPath(idempotencyKey, dir) {
169247
- const digest = createHash69("sha256").update(idempotencyKey, "utf8").digest("hex");
169325
+ const digest = createHash70("sha256").update(idempotencyKey, "utf8").digest("hex");
169248
169326
  return path321.join(turnsRoot(dir), "keys", `${digest}.json`);
169249
169327
  }
169250
169328
  function adoptLegacyClaim(project, idempotencyKey, dir) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.3.26",
3
+ "version": "0.3.27",
4
4
  "description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
5
5
  "private": false,
6
6
  "publishConfig": {