@mrciphersmith/keryx 0.2.147 → 0.2.149

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 +113 -15
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -30207,15 +30207,49 @@ ${shown.join(`
30207
30207
  const risk = toolByName.get(call.name)?.definition.risk;
30208
30208
  const isPureReadTool = risk === "read" && !DURABLE_READ_TOOL_NAMES.has(call.name);
30209
30209
  if (!isPureReadTool && untrustedContentSeen) {
30210
- const result = {
30211
- output: "tool blocked: external web content cannot authorize further tool calls in this turn",
30212
- isError: true
30213
- };
30214
- io.onToolResult?.(call.name, result);
30215
- history.push({ role: "tool", content: result.output, provenance: "tool", toolCallId: call.id, ts: now() });
30216
- io.onHistoryChange?.("tool");
30217
- gateBlockedAny = true;
30218
- continue;
30210
+ const approver = io.requestApproval;
30211
+ if (deps.unattended === true || approver === undefined) {
30212
+ const result = {
30213
+ output: "tool blocked: external web content cannot authorize further tool calls in this turn",
30214
+ isError: true
30215
+ };
30216
+ io.onToolResult?.(call.name, result);
30217
+ history.push({ role: "tool", content: result.output, provenance: "tool", toolCallId: call.id, ts: now() });
30218
+ io.onHistoryChange?.("tool");
30219
+ gateBlockedAny = true;
30220
+ continue;
30221
+ }
30222
+ const taintFingerprint = toolCallHash(call.name, call.input);
30223
+ let taintApproved;
30224
+ try {
30225
+ const response = await approver(call.name, call.input, {
30226
+ fingerprint: taintFingerprint,
30227
+ destructive: risk === "destructive",
30228
+ untrustedOrigin: true
30229
+ });
30230
+ taintApproved = isApprovalFor(response, taintFingerprint);
30231
+ } catch (err) {
30232
+ const result = {
30233
+ output: `${call.name} not executed: the approval prompt failed (${err instanceof Error ? err.message : String(err)})`,
30234
+ isError: true
30235
+ };
30236
+ io.onToolResult?.(call.name, result);
30237
+ history.push({ role: "tool", content: result.output, provenance: "tool", toolCallId: call.id, ts: now() });
30238
+ io.onHistoryChange?.("tool");
30239
+ gateBlockedAny = true;
30240
+ continue;
30241
+ }
30242
+ if (!taintApproved) {
30243
+ const result = {
30244
+ output: "tool blocked: external web content cannot authorize this call, and the user did not authorize it either",
30245
+ isError: true
30246
+ };
30247
+ io.onToolResult?.(call.name, result);
30248
+ history.push({ role: "tool", content: result.output, provenance: "tool", toolCallId: call.id, ts: now() });
30249
+ io.onHistoryChange?.("tool");
30250
+ gateBlockedAny = true;
30251
+ continue;
30252
+ }
30219
30253
  }
30220
30254
  io.onToolCall?.(call.name, call.input);
30221
30255
  const reservation = reservationByCallId.get(call.id) ?? reserveToolAttempt(budget, call.name, call.input);
@@ -51463,7 +51497,7 @@ import path47 from "path";
51463
51497
  // package.json
51464
51498
  var package_default = {
51465
51499
  name: "@mrciphersmith/keryx",
51466
- version: "0.2.147",
51500
+ version: "0.2.149",
51467
51501
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
51468
51502
  private: false,
51469
51503
  publishConfig: {
@@ -88755,6 +88789,9 @@ function renderUseToolApprovalLines(description, meta) {
88755
88789
  if (meta?.destructive === true) {
88756
88790
  lines.push(" this tool is treated as destructive \u2014 it is a third party's code");
88757
88791
  }
88792
+ if (meta?.untrustedOrigin === true) {
88793
+ lines.push(" \u26A0 follows untrusted external content \u2014 that content cannot authorize this call");
88794
+ }
88758
88795
  return lines;
88759
88796
  }
88760
88797
  function summariseUseToolApproval(description) {
@@ -104090,6 +104127,7 @@ function attachUsageIo(io, chrome) {
104090
104127
  totalOut = 0;
104091
104128
  chrome.setHeaderMeta("\u21910 \u21930");
104092
104129
  chrome.setContextTotal(0);
104130
+ chrome.setUsage?.(0, 0);
104093
104131
  }
104094
104132
  });
104095
104133
  }
@@ -105758,6 +105796,12 @@ async function launchTuiAgentShell(opts) {
105758
105796
  };
105759
105797
  const approvalContext = createApprovalContextLoader(opts.session?.cwd ?? process.cwd());
105760
105798
  io.requestApproval = async (tool, inputJson, meta) => {
105799
+ if (meta?.untrustedOrigin === true) {
105800
+ transcript.add(new otui.TextRenderable(r, {
105801
+ id: `ap${uid++}`,
105802
+ content: otui.t`${otui.yellow("\u26A0 follows untrusted external content \u2014 it cannot authorize this call; your answer does")}`
105803
+ }));
105804
+ }
105761
105805
  if (tool === "spawn_subagent") {
105762
105806
  let mode = "read_only";
105763
105807
  let taskPreview = inputJson;
@@ -109717,6 +109761,13 @@ ${GUTTER}${style.dim(formatReasoningOneLiner({
109717
109761
  },
109718
109762
  requestApproval: async (tool, input, meta) => {
109719
109763
  stopSpinner();
109764
+ if (meta?.untrustedOrigin === true) {
109765
+ out(`
109766
+ ${GUTTER}${style.red("\u26A0 this call follows untrusted external content in this turn")}
109767
+ `);
109768
+ out(`${GUTTER}${style.dim("that content cannot authorize it \u2014 only your answer can")}
109769
+ `);
109770
+ }
109720
109771
  if (tool === "apply_patch") {
109721
109772
  const patch = extractPatchText(input);
109722
109773
  out(`
@@ -118206,6 +118257,16 @@ async function main() {
118206
118257
  }
118207
118258
  const route = CLI_ROUTES[command];
118208
118259
  if (route) {
118260
+ if (shouldInterceptHelp(command, args.slice(1))) {
118261
+ const usage = groupUsage(command);
118262
+ console.log(usage === undefined ? `keryx ${VERSION2}
118263
+
118264
+ ${USAGE_BODY}` : `keryx ${command} \u2014 usage:
118265
+
118266
+ ${usage}
118267
+ `);
118268
+ return;
118269
+ }
118209
118270
  await route(args.slice(1));
118210
118271
  return;
118211
118272
  }
@@ -118213,10 +118274,7 @@ async function main() {
118213
118274
  printHelp25();
118214
118275
  process.exitCode = 1;
118215
118276
  }
118216
- function printHelp25() {
118217
- console.log(`keryx ${VERSION2}
118218
-
118219
- Usage:
118277
+ var USAGE_BODY = `Usage:
118220
118278
  keryx Show CLI usage
118221
118279
  keryx shell [-c|--continue] [-r|--resume [id]] [--provider <p>] [--model <m>] [--base-url <url>] [--agent|--chat] [--tui|--no-tui]
118222
118280
  Start TUI agent shell (sessions are per-project)
@@ -118380,6 +118438,42 @@ Commands:
118380
118438
  workspace Shared Agent Context: workspaces, FWK reads, propose/review (module sac)
118381
118439
  retention Bound stores that grow without bound (gdctx raw/artifacts, owner write-conflict sidecars)
118382
118440
  forgetting Read the deletion trail \u2014 was this removed, or did it never exist?
118441
+ `;
118442
+ function printHelp25() {
118443
+ console.log(`keryx ${VERSION2}
118444
+
118445
+ ${USAGE_BODY}`);
118446
+ }
118447
+ function helpRequestedFor(rest) {
118448
+ const separator = rest.indexOf("--");
118449
+ const head = separator === -1 ? rest : rest.slice(0, separator);
118450
+ return head.some((token) => token === "--help" || token === "-h");
118451
+ }
118452
+ var DEEP_HELP_GROUPS = new Set(["agents", "shell"]);
118453
+ function shouldInterceptHelp(command, rest) {
118454
+ return !DEEP_HELP_GROUPS.has(command) && helpRequestedFor(rest);
118455
+ }
118456
+ function groupUsage(command, usage = USAGE_BODY) {
118457
+ const lines = usage.split(`
118458
+ `);
118459
+ const startsGroup = new RegExp(`^ {2,}keryx ${command}(?:\\s|$)`);
118460
+ const isContinuation = /^ {4,}\S/;
118461
+ const out = [];
118462
+ for (let i = 0;i < lines.length; i += 1) {
118463
+ const line = lines[i] ?? "";
118464
+ if (!startsGroup.test(line)) {
118465
+ continue;
118466
+ }
118467
+ out.push(line);
118468
+ for (let j = i + 1;j < lines.length; j += 1) {
118469
+ const next = lines[j] ?? "";
118470
+ if (!isContinuation.test(next) || startsGroup.test(next) || /keryx\s/.test(next)) {
118471
+ break;
118472
+ }
118473
+ out.push(next);
118474
+ }
118475
+ }
118476
+ return out.length === 0 ? undefined : out.join(`
118383
118477
  `);
118384
118478
  }
118385
118479
  function exitCodeForError(error) {
@@ -118393,6 +118487,10 @@ if (import.meta.main) {
118393
118487
  }
118394
118488
  export {
118395
118489
  CLI_ROUTES,
118490
+ USAGE_BODY,
118396
118491
  exitCodeForError,
118397
- main
118492
+ groupUsage,
118493
+ helpRequestedFor,
118494
+ main,
118495
+ shouldInterceptHelp
118398
118496
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.2.147",
3
+ "version": "0.2.149",
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": {