akm-cli 0.10.261019 → 0.10.261021

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.
@@ -495,7 +495,10 @@ export async function fetchWithTimeout(url, opts, timeoutMs = 30_000, signal) {
495
495
  try {
496
496
  if (controller.signal.aborted)
497
497
  throw controller.signal.reason ?? new Error(`Request aborted: ${url}`);
498
- return await fetch(url, { ...opts, signal: controller.signal });
498
+ // `timeout: false` turns off Bun's independent five-minute socket-idle timer,
499
+ // which would otherwise cut a longer AKM deadline short. The AbortController
500
+ // signal (deadline + caller cancel) remains the only bound on the request.
501
+ return await fetch(url, { ...opts, signal: controller.signal, timeout: false });
499
502
  }
500
503
  catch (err) {
501
504
  if (err instanceof DOMException && err.name === "AbortError") {
@@ -875,9 +875,9 @@ function isMarkdownFenceClosing(line, fence) {
875
875
  * Version of what {@link projectMarkdownContent} indexes. It is part of every
876
876
  * directory's index fingerprint, so bumping it makes the next `akm index`
877
877
  * re-project every directory once instead of keeping the old text for
878
- * unchanged files. 2: identifiers from fenced code (akm#1260).
878
+ * unchanged files. 3: count each fenced identifier once per document (akm#1284).
879
879
  */
880
- export const CONTENT_PROJECTION_VERSION = 2;
880
+ export const CONTENT_PROJECTION_VERSION = 3;
881
881
  /** At or above this length a token with a digit reads as a key or hash, not a name. */
882
882
  const TOKEN_LIKE_MIN_LENGTH = 20;
883
883
  /**
@@ -1114,7 +1114,7 @@ export function projectMarkdownContent(body, truncationInfo) {
1114
1114
  const innerBlock = findInnerFrontmatterBlock(lines);
1115
1115
  const start = innerBlock && isFrontmatterShaped(lines, innerBlock) ? innerBlock.close + 1 : 0;
1116
1116
  const projected = [];
1117
- const fenced = [];
1117
+ const fenced = new Map();
1118
1118
  forEachVisibleMarkdownLine(lines, start, (_index, visible) => {
1119
1119
  let trimmed = visible.trim();
1120
1120
  if (!trimmed || /^(-{3,}|\*{3,}|_{3,}|=+)$/.test(trimmed))
@@ -1135,11 +1135,13 @@ export function projectMarkdownContent(body, truncationInfo) {
1135
1135
  projected.push(trimmed);
1136
1136
  }, (_index, fencedLine) => {
1137
1137
  const identifiers = fencedCodeIdentifiers(fencedLine);
1138
- if (identifiers)
1139
- fenced.push(identifiers);
1138
+ for (const identifier of identifiers.split(/\s+/)) {
1139
+ if (identifier)
1140
+ fenced.set(identifier.toLowerCase(), identifier);
1141
+ }
1140
1142
  });
1141
1143
  // Fenced identifiers follow the prose, so a head-truncated embedding input keeps the prose first.
1142
- const text = [...projected, ...fenced].join(" ").replace(/\s+/g, " ").trim();
1144
+ const text = [...projected, ...fenced.values()].join(" ").replace(/\s+/g, " ").trim();
1143
1145
  if (!text)
1144
1146
  return undefined;
1145
1147
  if (truncationInfo)
@@ -194,6 +194,16 @@ function classifyByParentDirHint(ctx) {
194
194
  }
195
195
  return matchDirectoryHint(parentDir, ctx, 15);
196
196
  }
197
+ /**
198
+ * The type a file's location declares, from the same directory rules the
199
+ * indexer applies: parent-directory hint (specificity 15) over the outermost
200
+ * typed ancestor (10), each honouring the rule's extension predicate, the
201
+ * `README.md` documentation exception and nested skill resources. `undefined`
202
+ * when no directory rule claims the file. Path fields only; no bytes are read.
203
+ */
204
+ export function declaredTypeForPath(ctx) {
205
+ return (classifyByParentDirHint(ctx) ?? classifyByDirectory(ctx))?.type;
206
+ }
197
207
  function classifyBySmartMd(ctx) {
198
208
  if (ctx.ext !== ".md")
199
209
  return null;
@@ -680,11 +680,15 @@ function formatUpgradePluginLines(r) {
680
680
  }
681
681
  const plugins = Array.isArray(r.plugins) ? r.plugins : [];
682
682
  for (const p of plugins) {
683
- if (p.outcome === "current" || p.outcome === "skipped")
683
+ if ((p.outcome === "current" || p.outcome === "skipped") &&
684
+ (r.updateAvailable === undefined || !p.channel) &&
685
+ !p.channelMismatch &&
686
+ !p.targetChannel)
684
687
  continue;
685
688
  const versions = p.from && p.to && p.from !== p.to ? ` v${p.from} → v${p.to}` : "";
689
+ const channel = p.channel ? ` [channel ${p.channel}${p.channelMismatch ? "; differs from CLI" : ""}]` : "";
686
690
  const note = p.message ? ` (${p.message})` : "";
687
- lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${note}`);
691
+ lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${channel}${note}`);
688
692
  }
689
693
  return lines;
690
694
  }
@@ -698,8 +702,11 @@ function formatUpgradeHead(r) {
698
702
  if (r.upgraded === true) {
699
703
  return `akm upgraded: v${r.currentVersion} → v${r.newVersion}`;
700
704
  }
705
+ if (r.targetChannel && r.latestVersion && r.latestVersion !== r.currentVersion && r.updateAvailable === false) {
706
+ return `akm v${r.currentVersion} → v${r.latestVersion} requires --allow-downgrade (run 'akm upgrade --channel ${r.targetChannel} --allow-downgrade' to install)`;
707
+ }
701
708
  if (r.updateAvailable === true) {
702
- return `akm v${r.currentVersion} → v${r.latestVersion} available (run 'akm upgrade${r.channel === "next" ? " --next" : ""}' to install)`;
709
+ return `akm v${r.currentVersion} → v${r.latestVersion} available (run 'akm upgrade${r.targetChannel ? ` --channel ${r.targetChannel}` : r.channel === "next" ? " --next" : ""}' to install)`;
703
710
  }
704
711
  if (r.updateAvailable === false && r.latestVersion) {
705
712
  return `akm v${r.currentVersion} is already the latest version`;
@@ -34812,7 +34812,7 @@ function projectMarkdownContent(body, truncationInfo) {
34812
34812
  const innerBlock = findInnerFrontmatterBlock(lines);
34813
34813
  const start = innerBlock && isFrontmatterShaped(lines, innerBlock) ? innerBlock.close + 1 : 0;
34814
34814
  const projected = [];
34815
- const fenced = [];
34815
+ const fenced = new Map;
34816
34816
  forEachVisibleMarkdownLine(lines, start, (_index, visible) => {
34817
34817
  let trimmed = visible.trim();
34818
34818
  if (!trimmed || /^(-{3,}|\*{3,}|_{3,}|=+)$/.test(trimmed))
@@ -34832,10 +34832,12 @@ function projectMarkdownContent(body, truncationInfo) {
34832
34832
  projected.push(trimmed);
34833
34833
  }, (_index, fencedLine) => {
34834
34834
  const identifiers = fencedCodeIdentifiers(fencedLine);
34835
- if (identifiers)
34836
- fenced.push(identifiers);
34835
+ for (const identifier of identifiers.split(/\s+/)) {
34836
+ if (identifier)
34837
+ fenced.set(identifier.toLowerCase(), identifier);
34838
+ }
34837
34839
  });
34838
- const text2 = [...projected, ...fenced].join(" ").replace(/\s+/g, " ").trim();
34840
+ const text2 = [...projected, ...fenced.values()].join(" ").replace(/\s+/g, " ").trim();
34839
34841
  if (!text2)
34840
34842
  return;
34841
34843
  if (truncationInfo)
@@ -37169,12 +37171,24 @@ function keyLooksSecret(key) {
37169
37171
  const lower = key.toLowerCase();
37170
37172
  return SECRET_KEY_HINTS.some((hint) => lower.includes(hint));
37171
37173
  }
37174
+ function segmentLooksSecret(seg) {
37175
+ if (SECRET_VALUE_PREFIX.test(seg))
37176
+ return true;
37177
+ const eq = seg.indexOf("=");
37178
+ if (eq > 0 && keyLooksSecret(seg.slice(0, eq)) && seg.length - eq > 8)
37179
+ return true;
37180
+ if (seg.length >= 32 && !UUID.test(seg) && /^[A-Za-z0-9+_=-]+$/.test(seg) && /\d/.test(seg) && /[a-zA-Z]/.test(seg))
37181
+ return true;
37182
+ return seg.length >= 20 && /^[A-Za-z0-9]+$/.test(seg) && /[a-z]/.test(seg) && /[A-Z]/.test(seg) && /\d/.test(seg);
37183
+ }
37172
37184
  function valueLooksSecret(value) {
37173
37185
  const s = value.trim();
37174
37186
  if (s.length < 20 || /\s/.test(s))
37175
37187
  return false;
37176
37188
  if (SECRET_VALUE_PREFIX.test(s))
37177
37189
  return true;
37190
+ if (PATH_LIKE.test(s))
37191
+ return s.split(/[/\\?&#]/).some(segmentLooksSecret);
37178
37192
  const classes = [/[a-z]/, /[A-Z]/, /[0-9]/, /[^A-Za-z0-9]/].filter((re) => re.test(s)).length;
37179
37193
  if (s.length >= 24 && classes >= 3)
37180
37194
  return true;
@@ -37216,7 +37230,7 @@ function walkSecretShaped(params, hit) {
37216
37230
  for (const [k, v] of Object.entries(params))
37217
37231
  walk(v, k, k);
37218
37232
  }
37219
- var SECRET_KEY_HINTS, SECRET_VALUE_PREFIX, MOVE_TO_ENV;
37233
+ var SECRET_KEY_HINTS, SECRET_VALUE_PREFIX, PATH_LIKE, UUID, MOVE_TO_ENV;
37220
37234
  var init_param_secrets = __esm(() => {
37221
37235
  SECRET_KEY_HINTS = [
37222
37236
  "secret",
@@ -37237,6 +37251,8 @@ var init_param_secrets = __esm(() => {
37237
37251
  "client_secret"
37238
37252
  ];
37239
37253
  SECRET_VALUE_PREFIX = /^(sk-|rk-|ghp_|gho_|ghu_|ghs_|ghr_|github_pat_|xox[baprs]-|AKIA|ASIA|AIza|ya29\.|-----BEGIN)/;
37254
+ PATH_LIKE = /^(\/|\.{1,2}[\\/]|~[\\/]|[A-Za-z]:[\\/]|\\\\)|^[\w.-]+[\\/][^?#]*\.[A-Za-z0-9]{1,8}$/;
37255
+ UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
37240
37256
  MOVE_TO_ENV = "Workflow params are copied verbatim into every native unit execution context and returned in `akm workflow run` and " + "`akm workflow status` output — move secrets to an env binding (`env:` ref), whose value native execution resolves " + "only at dispatch instead of storing it as a run param.";
37241
37257
  });
37242
37258
 
@@ -41922,10 +41938,10 @@ var init_marked_esm = __esm(() => {
41922
41938
 
41923
41939
  // src/core/asset/markdown-link-targets.ts
41924
41940
  function markdownLinkTargets(body, references) {
41925
- const tokens = markdown.lexer(body);
41941
+ const tokens2 = markdown.lexer(body);
41926
41942
  const definitions = new Map;
41927
41943
  if (references) {
41928
- markdown.walkTokens(tokens, (token) => {
41944
+ markdown.walkTokens(tokens2, (token) => {
41929
41945
  if (token.type !== "def")
41930
41946
  return;
41931
41947
  const definition = /^\s*\[([^\]]+)\]:\s*(\S+)/.exec(token.raw);
@@ -41934,7 +41950,7 @@ function markdownLinkTargets(body, references) {
41934
41950
  });
41935
41951
  }
41936
41952
  const targets = [];
41937
- markdown.walkTokens(tokens, (token) => {
41953
+ markdown.walkTokens(tokens2, (token) => {
41938
41954
  if (token.type !== "link" && token.type !== "image")
41939
41955
  return;
41940
41956
  const inline = /^!?\[[\s\S]*\]\(/.test(token.raw);
@@ -62448,7 +62464,7 @@ var require_HTMLParser = __commonJS((exports, module) => {
62448
62464
  }
62449
62465
  }
62450
62466
  htmlparser.testTokenizer = function(input2, initialState, lastStartTag, charbychar) {
62451
- var tokens = [];
62467
+ var tokens2 = [];
62452
62468
  switch (initialState) {
62453
62469
  case "PCDATA state":
62454
62470
  tokenizer = data_state;
@@ -62470,16 +62486,16 @@ var require_HTMLParser = __commonJS((exports, module) => {
62470
62486
  flushText();
62471
62487
  switch (t) {
62472
62488
  case 1:
62473
- if (tokens.length > 0 && tokens[tokens.length - 1][0] === "Character") {
62474
- tokens[tokens.length - 1][1] += value;
62489
+ if (tokens2.length > 0 && tokens2[tokens2.length - 1][0] === "Character") {
62490
+ tokens2[tokens2.length - 1][1] += value;
62475
62491
  } else
62476
- tokens.push(["Character", value]);
62492
+ tokens2.push(["Character", value]);
62477
62493
  break;
62478
62494
  case 4:
62479
- tokens.push(["Comment", value]);
62495
+ tokens2.push(["Comment", value]);
62480
62496
  break;
62481
62497
  case 5:
62482
- tokens.push([
62498
+ tokens2.push([
62483
62499
  "DOCTYPE",
62484
62500
  value,
62485
62501
  arg3 === undefined ? null : arg3,
@@ -62500,10 +62516,10 @@ var require_HTMLParser = __commonJS((exports, module) => {
62500
62516
  var token = ["StartTag", value, attrs];
62501
62517
  if (arg4)
62502
62518
  token.push(true);
62503
- tokens.push(token);
62519
+ tokens2.push(token);
62504
62520
  break;
62505
62521
  case 3:
62506
- tokens.push(["EndTag", value]);
62522
+ tokens2.push(["EndTag", value]);
62507
62523
  break;
62508
62524
  case -1:
62509
62525
  break;
@@ -62517,7 +62533,7 @@ var require_HTMLParser = __commonJS((exports, module) => {
62517
62533
  }
62518
62534
  this.parse("", true);
62519
62535
  }
62520
- return tokens;
62536
+ return tokens2;
62521
62537
  };
62522
62538
  return htmlparser;
62523
62539
  }
@@ -68891,18 +68907,25 @@ function sourceFacts(counts) {
68891
68907
  const entries = Object.entries(counts);
68892
68908
  return entries.length === 0 ? "-" : entries.map(([k, v]) => `${k}=${v}`).join(" ");
68893
68909
  }
68910
+ function tokens(n, a) {
68911
+ return a.calls > 0 && a.usageCalls === 0 ? "unknown" : int(n);
68912
+ }
68913
+ function usageCoverage(a) {
68914
+ return a.usageCalls === undefined ? "-" : `${a.usageCalls}/${a.calls}`;
68915
+ }
68894
68916
  function llmRows(group) {
68895
68917
  return Object.entries(group).map(([name, a]) => [
68896
68918
  name,
68897
68919
  int(a.calls),
68898
68920
  int(a.failures),
68899
- int(a.promptTokens),
68900
- int(a.completionTokens),
68901
- int(a.totalTokens),
68921
+ tokens(a.promptTokens, a),
68922
+ tokens(a.completionTokens, a),
68923
+ tokens(a.totalTokens, a),
68924
+ usageCoverage(a),
68902
68925
  ms(a.totalDurationMs)
68903
68926
  ]);
68904
68927
  }
68905
- var LLM_HEADERS = ["name", "calls", "failed", "prompt", "completion", "total", "time"];
68928
+ var LLM_HEADERS = ["name", "calls", "failed", "prompt", "completion", "total", "calls with usage", "time"];
68906
68929
  function buildMetricsView(r, detail) {
68907
68930
  const brief = detail === "brief";
68908
68931
  const cut = (items) => brief ? items.slice(0, BRIEF_LIST_LIMIT) : items;
@@ -68916,7 +68939,8 @@ function buildMetricsView(r, detail) {
68916
68939
  ["shows", int(usage.totals.shows)],
68917
68940
  ["curates", int(usage.totals.curates)],
68918
68941
  ["selects", int(usage.totals.selects)],
68919
- ["select rate", pct(usage.selectRate)],
68942
+ ["searches with hits", int(usage.totals.searchesWithHits)],
68943
+ ["selects per search with hits", fixed(usage.selectsPerSearch, 2)],
68920
68944
  [
68921
68945
  "zero-result searches",
68922
68946
  `${usage.totals.zeroResultSearches} (${pct(searches === 0 ? null : usage.totals.zeroResultSearches / searches)})`
@@ -69023,10 +69047,11 @@ function buildMetricsView(r, detail) {
69023
69047
  facts: [
69024
69048
  ["calls", int(llm.calls)],
69025
69049
  ["failed", int(llm.failures)],
69026
- ["prompt tokens", int(llm.promptTokens)],
69027
- ["completion tokens", int(llm.completionTokens)],
69028
- ["reasoning tokens", int(llm.reasoningTokens)],
69029
- ["total tokens", int(llm.totalTokens)],
69050
+ ["calls with token usage", usageCoverage(llm)],
69051
+ ["prompt tokens", tokens(llm.promptTokens, llm)],
69052
+ ["completion tokens", tokens(llm.completionTokens, llm)],
69053
+ ["reasoning tokens", llm.calls > 0 && llm.reasoningCalls === 0 ? "unknown" : tokens(llm.reasoningTokens, llm)],
69054
+ ["total tokens", tokens(llm.totalTokens, llm)],
69030
69055
  ["time", ms(llm.totalDurationMs)]
69031
69056
  ],
69032
69057
  tables: [
@@ -70528,11 +70553,12 @@ function formatUpgradePluginLines(r) {
70528
70553
  }
70529
70554
  const plugins = Array.isArray(r.plugins) ? r.plugins : [];
70530
70555
  for (const p of plugins) {
70531
- if (p.outcome === "current" || p.outcome === "skipped")
70556
+ if ((p.outcome === "current" || p.outcome === "skipped") && (r.updateAvailable === undefined || !p.channel) && !p.channelMismatch && !p.targetChannel)
70532
70557
  continue;
70533
70558
  const versions = p.from && p.to && p.from !== p.to ? ` v${p.from} → v${p.to}` : "";
70559
+ const channel = p.channel ? ` [channel ${p.channel}${p.channelMismatch ? "; differs from CLI" : ""}]` : "";
70534
70560
  const note = p.message ? ` (${p.message})` : "";
70535
- lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${note}`);
70561
+ lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${channel}${note}`);
70536
70562
  }
70537
70563
  return lines;
70538
70564
  }
@@ -70547,8 +70573,11 @@ function formatUpgradeHead(r) {
70547
70573
  if (r.upgraded === true) {
70548
70574
  return `akm upgraded: v${r.currentVersion} → v${r.newVersion}`;
70549
70575
  }
70576
+ if (r.targetChannel && r.latestVersion && r.latestVersion !== r.currentVersion && r.updateAvailable === false) {
70577
+ return `akm v${r.currentVersion} → v${r.latestVersion} requires --allow-downgrade (run 'akm upgrade --channel ${r.targetChannel} --allow-downgrade' to install)`;
70578
+ }
70550
70579
  if (r.updateAvailable === true) {
70551
- return `akm v${r.currentVersion} → v${r.latestVersion} available (run 'akm upgrade${r.channel === "next" ? " --next" : ""}' to install)`;
70580
+ return `akm v${r.currentVersion} → v${r.latestVersion} available (run 'akm upgrade${r.targetChannel ? ` --channel ${r.targetChannel}` : r.channel === "next" ? " --next" : ""}' to install)`;
70552
70581
  }
70553
70582
  if (r.updateAvailable === false && r.latestVersion) {
70554
70583
  return `akm v${r.currentVersion} is already the latest version`;
@@ -72913,15 +72942,15 @@ var SHELL_ASSIGNMENT_WORD = /^[A-Za-z_][A-Za-z0-9_]*=/;
72913
72942
  function shellStableV2Executable(executable) {
72914
72943
  return executable === "akm" || executable.includes("/");
72915
72944
  }
72916
- function skipEnvAssignmentPrefix(tokens) {
72917
- if (tokens[0] !== "env")
72918
- return { tokens, envWrapped: false };
72945
+ function skipEnvAssignmentPrefix(tokens2) {
72946
+ if (tokens2[0] !== "env")
72947
+ return { tokens: tokens2, envWrapped: false };
72919
72948
  let index = 1;
72920
- while (index < tokens.length && SHELL_ASSIGNMENT_WORD.test(tokens[index]))
72949
+ while (index < tokens2.length && SHELL_ASSIGNMENT_WORD.test(tokens2[index]))
72921
72950
  index += 1;
72922
- if (index >= tokens.length)
72923
- return { tokens, envWrapped: false };
72924
- return { tokens: tokens.slice(index), envWrapped: true };
72951
+ if (index >= tokens2.length)
72952
+ return { tokens: tokens2, envWrapped: false };
72953
+ return { tokens: tokens2.slice(index), envWrapped: true };
72925
72954
  }
72926
72955
  var KNOWN_PROMPT_REF_FAMILIES = new Set([
72927
72956
  "agents",
@@ -73353,16 +73382,16 @@ function migratedObject(data) {
73353
73382
  const command = exactString(data.command, "command", true).trim();
73354
73383
  if (/['"\\]/.test(command))
73355
73384
  return "shell-quoting-changes-v2-whitespace-split-semantics";
73356
- const tokens = command.split(/\s+/).filter(Boolean);
73357
- if (tokens.length === 0 || tokens.some((token) => !SAFE_V2_COMMAND_TOKEN.test(token))) {
73385
+ const tokens2 = command.split(/\s+/).filter(Boolean);
73386
+ if (tokens2.length === 0 || tokens2.some((token) => !SAFE_V2_COMMAND_TOKEN.test(token))) {
73358
73387
  return "shell-operators-change-v2-literal-argv-semantics";
73359
73388
  }
73360
- const { tokens: targetTokens, envWrapped } = skipEnvAssignmentPrefix(tokens);
73389
+ const { tokens: targetTokens, envWrapped } = skipEnvAssignmentPrefix(tokens2);
73361
73390
  const executable = targetTokens[0];
73362
73391
  if (SHELL_ASSIGNMENT_WORD.test(executable) || !envWrapped && !shellStableV2Executable(executable)) {
73363
73392
  return "shell-command-resolution-changes-v2-literal-argv-semantics";
73364
73393
  }
73365
- output2.run = tokens.join(" ");
73394
+ output2.run = tokens2.join(" ");
73366
73395
  addSharedNonPromptOverrides(data, akm);
73367
73396
  }
73368
73397
  output2.akm = akm;
@@ -34811,7 +34811,7 @@ function projectMarkdownContent(body, truncationInfo) {
34811
34811
  const innerBlock = findInnerFrontmatterBlock(lines);
34812
34812
  const start = innerBlock && isFrontmatterShaped(lines, innerBlock) ? innerBlock.close + 1 : 0;
34813
34813
  const projected = [];
34814
- const fenced = [];
34814
+ const fenced = new Map;
34815
34815
  forEachVisibleMarkdownLine(lines, start, (_index, visible) => {
34816
34816
  let trimmed = visible.trim();
34817
34817
  if (!trimmed || /^(-{3,}|\*{3,}|_{3,}|=+)$/.test(trimmed))
@@ -34831,10 +34831,12 @@ function projectMarkdownContent(body, truncationInfo) {
34831
34831
  projected.push(trimmed);
34832
34832
  }, (_index, fencedLine) => {
34833
34833
  const identifiers = fencedCodeIdentifiers(fencedLine);
34834
- if (identifiers)
34835
- fenced.push(identifiers);
34834
+ for (const identifier of identifiers.split(/\s+/)) {
34835
+ if (identifier)
34836
+ fenced.set(identifier.toLowerCase(), identifier);
34837
+ }
34836
34838
  });
34837
- const text2 = [...projected, ...fenced].join(" ").replace(/\s+/g, " ").trim();
34839
+ const text2 = [...projected, ...fenced.values()].join(" ").replace(/\s+/g, " ").trim();
34838
34840
  if (!text2)
34839
34841
  return;
34840
34842
  if (truncationInfo)
@@ -37168,12 +37170,24 @@ function keyLooksSecret(key) {
37168
37170
  const lower = key.toLowerCase();
37169
37171
  return SECRET_KEY_HINTS.some((hint) => lower.includes(hint));
37170
37172
  }
37173
+ function segmentLooksSecret(seg) {
37174
+ if (SECRET_VALUE_PREFIX.test(seg))
37175
+ return true;
37176
+ const eq = seg.indexOf("=");
37177
+ if (eq > 0 && keyLooksSecret(seg.slice(0, eq)) && seg.length - eq > 8)
37178
+ return true;
37179
+ if (seg.length >= 32 && !UUID.test(seg) && /^[A-Za-z0-9+_=-]+$/.test(seg) && /\d/.test(seg) && /[a-zA-Z]/.test(seg))
37180
+ return true;
37181
+ return seg.length >= 20 && /^[A-Za-z0-9]+$/.test(seg) && /[a-z]/.test(seg) && /[A-Z]/.test(seg) && /\d/.test(seg);
37182
+ }
37171
37183
  function valueLooksSecret(value) {
37172
37184
  const s = value.trim();
37173
37185
  if (s.length < 20 || /\s/.test(s))
37174
37186
  return false;
37175
37187
  if (SECRET_VALUE_PREFIX.test(s))
37176
37188
  return true;
37189
+ if (PATH_LIKE.test(s))
37190
+ return s.split(/[/\\?&#]/).some(segmentLooksSecret);
37177
37191
  const classes = [/[a-z]/, /[A-Z]/, /[0-9]/, /[^A-Za-z0-9]/].filter((re) => re.test(s)).length;
37178
37192
  if (s.length >= 24 && classes >= 3)
37179
37193
  return true;
@@ -37215,7 +37229,7 @@ function walkSecretShaped(params, hit) {
37215
37229
  for (const [k, v] of Object.entries(params))
37216
37230
  walk(v, k, k);
37217
37231
  }
37218
- var SECRET_KEY_HINTS, SECRET_VALUE_PREFIX, MOVE_TO_ENV;
37232
+ var SECRET_KEY_HINTS, SECRET_VALUE_PREFIX, PATH_LIKE, UUID, MOVE_TO_ENV;
37219
37233
  var init_param_secrets = __esm(() => {
37220
37234
  SECRET_KEY_HINTS = [
37221
37235
  "secret",
@@ -37236,6 +37250,8 @@ var init_param_secrets = __esm(() => {
37236
37250
  "client_secret"
37237
37251
  ];
37238
37252
  SECRET_VALUE_PREFIX = /^(sk-|rk-|ghp_|gho_|ghu_|ghs_|ghr_|github_pat_|xox[baprs]-|AKIA|ASIA|AIza|ya29\.|-----BEGIN)/;
37253
+ PATH_LIKE = /^(\/|\.{1,2}[\\/]|~[\\/]|[A-Za-z]:[\\/]|\\\\)|^[\w.-]+[\\/][^?#]*\.[A-Za-z0-9]{1,8}$/;
37254
+ UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
37239
37255
  MOVE_TO_ENV = "Workflow params are copied verbatim into every native unit execution context and returned in `akm workflow run` and " + "`akm workflow status` output \u2014 move secrets to an env binding (`env:` ref), whose value native execution resolves " + "only at dispatch instead of storing it as a run param.";
37240
37256
  });
37241
37257
 
@@ -41921,10 +41937,10 @@ var init_marked_esm = __esm(() => {
41921
41937
 
41922
41938
  // src/core/asset/markdown-link-targets.ts
41923
41939
  function markdownLinkTargets(body, references) {
41924
- const tokens = markdown.lexer(body);
41940
+ const tokens2 = markdown.lexer(body);
41925
41941
  const definitions = new Map;
41926
41942
  if (references) {
41927
- markdown.walkTokens(tokens, (token) => {
41943
+ markdown.walkTokens(tokens2, (token) => {
41928
41944
  if (token.type !== "def")
41929
41945
  return;
41930
41946
  const definition = /^\s*\[([^\]]+)\]:\s*(\S+)/.exec(token.raw);
@@ -41933,7 +41949,7 @@ function markdownLinkTargets(body, references) {
41933
41949
  });
41934
41950
  }
41935
41951
  const targets = [];
41936
- markdown.walkTokens(tokens, (token) => {
41952
+ markdown.walkTokens(tokens2, (token) => {
41937
41953
  if (token.type !== "link" && token.type !== "image")
41938
41954
  return;
41939
41955
  const inline = /^!?\[[\s\S]*\]\(/.test(token.raw);
@@ -62447,7 +62463,7 @@ var require_HTMLParser = __commonJS((exports, module) => {
62447
62463
  }
62448
62464
  }
62449
62465
  htmlparser.testTokenizer = function(input2, initialState, lastStartTag, charbychar) {
62450
- var tokens = [];
62466
+ var tokens2 = [];
62451
62467
  switch (initialState) {
62452
62468
  case "PCDATA state":
62453
62469
  tokenizer = data_state;
@@ -62469,16 +62485,16 @@ var require_HTMLParser = __commonJS((exports, module) => {
62469
62485
  flushText();
62470
62486
  switch (t) {
62471
62487
  case 1:
62472
- if (tokens.length > 0 && tokens[tokens.length - 1][0] === "Character") {
62473
- tokens[tokens.length - 1][1] += value;
62488
+ if (tokens2.length > 0 && tokens2[tokens2.length - 1][0] === "Character") {
62489
+ tokens2[tokens2.length - 1][1] += value;
62474
62490
  } else
62475
- tokens.push(["Character", value]);
62491
+ tokens2.push(["Character", value]);
62476
62492
  break;
62477
62493
  case 4:
62478
- tokens.push(["Comment", value]);
62494
+ tokens2.push(["Comment", value]);
62479
62495
  break;
62480
62496
  case 5:
62481
- tokens.push([
62497
+ tokens2.push([
62482
62498
  "DOCTYPE",
62483
62499
  value,
62484
62500
  arg3 === undefined ? null : arg3,
@@ -62499,10 +62515,10 @@ var require_HTMLParser = __commonJS((exports, module) => {
62499
62515
  var token = ["StartTag", value, attrs];
62500
62516
  if (arg4)
62501
62517
  token.push(true);
62502
- tokens.push(token);
62518
+ tokens2.push(token);
62503
62519
  break;
62504
62520
  case 3:
62505
- tokens.push(["EndTag", value]);
62521
+ tokens2.push(["EndTag", value]);
62506
62522
  break;
62507
62523
  case -1:
62508
62524
  break;
@@ -62516,7 +62532,7 @@ var require_HTMLParser = __commonJS((exports, module) => {
62516
62532
  }
62517
62533
  this.parse("", true);
62518
62534
  }
62519
- return tokens;
62535
+ return tokens2;
62520
62536
  };
62521
62537
  return htmlparser;
62522
62538
  }
@@ -68889,18 +68905,25 @@ function sourceFacts(counts) {
68889
68905
  const entries = Object.entries(counts);
68890
68906
  return entries.length === 0 ? "-" : entries.map(([k, v]) => `${k}=${v}`).join(" ");
68891
68907
  }
68908
+ function tokens(n, a) {
68909
+ return a.calls > 0 && a.usageCalls === 0 ? "unknown" : int(n);
68910
+ }
68911
+ function usageCoverage(a) {
68912
+ return a.usageCalls === undefined ? "-" : `${a.usageCalls}/${a.calls}`;
68913
+ }
68892
68914
  function llmRows(group) {
68893
68915
  return Object.entries(group).map(([name, a]) => [
68894
68916
  name,
68895
68917
  int(a.calls),
68896
68918
  int(a.failures),
68897
- int(a.promptTokens),
68898
- int(a.completionTokens),
68899
- int(a.totalTokens),
68919
+ tokens(a.promptTokens, a),
68920
+ tokens(a.completionTokens, a),
68921
+ tokens(a.totalTokens, a),
68922
+ usageCoverage(a),
68900
68923
  ms(a.totalDurationMs)
68901
68924
  ]);
68902
68925
  }
68903
- var LLM_HEADERS = ["name", "calls", "failed", "prompt", "completion", "total", "time"];
68926
+ var LLM_HEADERS = ["name", "calls", "failed", "prompt", "completion", "total", "calls with usage", "time"];
68904
68927
  function buildMetricsView(r, detail) {
68905
68928
  const brief = detail === "brief";
68906
68929
  const cut = (items) => brief ? items.slice(0, BRIEF_LIST_LIMIT) : items;
@@ -68914,7 +68937,8 @@ function buildMetricsView(r, detail) {
68914
68937
  ["shows", int(usage.totals.shows)],
68915
68938
  ["curates", int(usage.totals.curates)],
68916
68939
  ["selects", int(usage.totals.selects)],
68917
- ["select rate", pct(usage.selectRate)],
68940
+ ["searches with hits", int(usage.totals.searchesWithHits)],
68941
+ ["selects per search with hits", fixed(usage.selectsPerSearch, 2)],
68918
68942
  [
68919
68943
  "zero-result searches",
68920
68944
  `${usage.totals.zeroResultSearches} (${pct(searches === 0 ? null : usage.totals.zeroResultSearches / searches)})`
@@ -69021,10 +69045,11 @@ function buildMetricsView(r, detail) {
69021
69045
  facts: [
69022
69046
  ["calls", int(llm.calls)],
69023
69047
  ["failed", int(llm.failures)],
69024
- ["prompt tokens", int(llm.promptTokens)],
69025
- ["completion tokens", int(llm.completionTokens)],
69026
- ["reasoning tokens", int(llm.reasoningTokens)],
69027
- ["total tokens", int(llm.totalTokens)],
69048
+ ["calls with token usage", usageCoverage(llm)],
69049
+ ["prompt tokens", tokens(llm.promptTokens, llm)],
69050
+ ["completion tokens", tokens(llm.completionTokens, llm)],
69051
+ ["reasoning tokens", llm.calls > 0 && llm.reasoningCalls === 0 ? "unknown" : tokens(llm.reasoningTokens, llm)],
69052
+ ["total tokens", tokens(llm.totalTokens, llm)],
69028
69053
  ["time", ms(llm.totalDurationMs)]
69029
69054
  ],
69030
69055
  tables: [
@@ -70526,11 +70551,12 @@ function formatUpgradePluginLines(r) {
70526
70551
  }
70527
70552
  const plugins = Array.isArray(r.plugins) ? r.plugins : [];
70528
70553
  for (const p of plugins) {
70529
- if (p.outcome === "current" || p.outcome === "skipped")
70554
+ if ((p.outcome === "current" || p.outcome === "skipped") && (r.updateAvailable === undefined || !p.channel) && !p.channelMismatch && !p.targetChannel)
70530
70555
  continue;
70531
70556
  const versions = p.from && p.to && p.from !== p.to ? ` v${p.from} \u2192 v${p.to}` : "";
70557
+ const channel = p.channel ? ` [channel ${p.channel}${p.channelMismatch ? "; differs from CLI" : ""}]` : "";
70532
70558
  const note = p.message ? ` (${p.message})` : "";
70533
- lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${note}`);
70559
+ lines.push(`${HARNESS_LABELS[String(p.harness)] ?? p.harness} plugin ${p.outcome}${versions}${channel}${note}`);
70534
70560
  }
70535
70561
  return lines;
70536
70562
  }
@@ -70545,8 +70571,11 @@ function formatUpgradeHead(r) {
70545
70571
  if (r.upgraded === true) {
70546
70572
  return `akm upgraded: v${r.currentVersion} \u2192 v${r.newVersion}`;
70547
70573
  }
70574
+ if (r.targetChannel && r.latestVersion && r.latestVersion !== r.currentVersion && r.updateAvailable === false) {
70575
+ return `akm v${r.currentVersion} \u2192 v${r.latestVersion} requires --allow-downgrade (run 'akm upgrade --channel ${r.targetChannel} --allow-downgrade' to install)`;
70576
+ }
70548
70577
  if (r.updateAvailable === true) {
70549
- return `akm v${r.currentVersion} \u2192 v${r.latestVersion} available (run 'akm upgrade${r.channel === "next" ? " --next" : ""}' to install)`;
70578
+ return `akm v${r.currentVersion} \u2192 v${r.latestVersion} available (run 'akm upgrade${r.targetChannel ? ` --channel ${r.targetChannel}` : r.channel === "next" ? " --next" : ""}' to install)`;
70550
70579
  }
70551
70580
  if (r.updateAvailable === false && r.latestVersion) {
70552
70581
  return `akm v${r.currentVersion} is already the latest version`;
@@ -72876,15 +72905,15 @@ var SHELL_ASSIGNMENT_WORD = /^[A-Za-z_][A-Za-z0-9_]*=/;
72876
72905
  function shellStableV2Executable(executable) {
72877
72906
  return executable === "akm" || executable.includes("/");
72878
72907
  }
72879
- function skipEnvAssignmentPrefix(tokens) {
72880
- if (tokens[0] !== "env")
72881
- return { tokens, envWrapped: false };
72908
+ function skipEnvAssignmentPrefix(tokens2) {
72909
+ if (tokens2[0] !== "env")
72910
+ return { tokens: tokens2, envWrapped: false };
72882
72911
  let index = 1;
72883
- while (index < tokens.length && SHELL_ASSIGNMENT_WORD.test(tokens[index]))
72912
+ while (index < tokens2.length && SHELL_ASSIGNMENT_WORD.test(tokens2[index]))
72884
72913
  index += 1;
72885
- if (index >= tokens.length)
72886
- return { tokens, envWrapped: false };
72887
- return { tokens: tokens.slice(index), envWrapped: true };
72914
+ if (index >= tokens2.length)
72915
+ return { tokens: tokens2, envWrapped: false };
72916
+ return { tokens: tokens2.slice(index), envWrapped: true };
72888
72917
  }
72889
72918
  var KNOWN_PROMPT_REF_FAMILIES = new Set([
72890
72919
  "agents",
@@ -73316,16 +73345,16 @@ function migratedObject(data) {
73316
73345
  const command = exactString(data.command, "command", true).trim();
73317
73346
  if (/['"\\]/.test(command))
73318
73347
  return "shell-quoting-changes-v2-whitespace-split-semantics";
73319
- const tokens = command.split(/\s+/).filter(Boolean);
73320
- if (tokens.length === 0 || tokens.some((token) => !SAFE_V2_COMMAND_TOKEN.test(token))) {
73348
+ const tokens2 = command.split(/\s+/).filter(Boolean);
73349
+ if (tokens2.length === 0 || tokens2.some((token) => !SAFE_V2_COMMAND_TOKEN.test(token))) {
73321
73350
  return "shell-operators-change-v2-literal-argv-semantics";
73322
73351
  }
73323
- const { tokens: targetTokens, envWrapped } = skipEnvAssignmentPrefix(tokens);
73352
+ const { tokens: targetTokens, envWrapped } = skipEnvAssignmentPrefix(tokens2);
73324
73353
  const executable = targetTokens[0];
73325
73354
  if (SHELL_ASSIGNMENT_WORD.test(executable) || !envWrapped && !shellStableV2Executable(executable)) {
73326
73355
  return "shell-command-resolution-changes-v2-literal-argv-semantics";
73327
73356
  }
73328
- output2.run = tokens.join(" ");
73357
+ output2.run = tokens2.join(" ");
73329
73358
  addSharedNonPromptOverrides(data, akm);
73330
73359
  }
73331
73360
  output2.akm = akm;