@mrciphersmith/keryx 0.3.55 → 0.3.56

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 +470 -141
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -20104,7 +20104,7 @@ var package_default;
20104
20104
  var init_package = __esm(() => {
20105
20105
  package_default = {
20106
20106
  name: "@mrciphersmith/keryx",
20107
- version: "0.3.55",
20107
+ version: "0.3.56",
20108
20108
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
20109
20109
  private: false,
20110
20110
  publishConfig: {
@@ -187340,6 +187340,9 @@ function createHttpBotApi(options) {
187340
187340
  if (params.messageThreadId !== undefined) {
187341
187341
  body.message_thread_id = params.messageThreadId;
187342
187342
  }
187343
+ if (params.parseMode !== undefined) {
187344
+ body.parse_mode = params.parseMode;
187345
+ }
187343
187346
  if (params.inlineKeyboard !== undefined) {
187344
187347
  body.reply_markup = { inline_keyboard: params.inlineKeyboard };
187345
187348
  }
@@ -187385,6 +187388,445 @@ var init_bot_api_http = __esm(() => {
187385
187388
  init_types11();
187386
187389
  });
187387
187390
 
187391
+ // src/remote/format.ts
187392
+ function fenceOpening(line) {
187393
+ const match = FENCE_LINE2.exec(line);
187394
+ if (match === null) {
187395
+ return;
187396
+ }
187397
+ const marker = match[1];
187398
+ const info = match[2].trim();
187399
+ if (marker.length > MAX_FENCE_MARKER || marker.startsWith("`") && info.includes("`")) {
187400
+ return;
187401
+ }
187402
+ return { marker, info };
187403
+ }
187404
+ function openingFence(line) {
187405
+ const opening = fenceOpening(line);
187406
+ if (opening === undefined) {
187407
+ return;
187408
+ }
187409
+ const { marker, info } = opening;
187410
+ return { marker, header: info.length > 0 && info.length <= MAX_FENCE_INFO ? `${marker}${info}` : marker };
187411
+ }
187412
+ function closesFence(line, fence) {
187413
+ const match = FENCE_LINE2.exec(line);
187414
+ if (match === null) {
187415
+ return false;
187416
+ }
187417
+ const run = match[1];
187418
+ return run[0] === fence.marker[0] && run.length >= fence.marker.length && match[2].trim().length === 0;
187419
+ }
187420
+ function fenceOverhead(fence) {
187421
+ return fence === undefined ? 0 : fence.header.length + 1 + (fence.marker.length + 1);
187422
+ }
187423
+ function cutAt(text, max) {
187424
+ if (text.length <= max) {
187425
+ return text.length;
187426
+ }
187427
+ for (let index = max;index > 0; index -= 1) {
187428
+ const ch = text[index - 1];
187429
+ if (ch === " " || ch === "\t") {
187430
+ return index;
187431
+ }
187432
+ }
187433
+ const code = text.charCodeAt(max - 1);
187434
+ return code >= 55296 && code <= 56319 ? max - 1 : max;
187435
+ }
187436
+ function toPieces(text, capacity) {
187437
+ const pieces = [];
187438
+ let fence;
187439
+ for (const raw of text.split(/(?<=\n)/)) {
187440
+ const line = raw.endsWith(`
187441
+ `) ? raw.slice(0, -1) : raw;
187442
+ const before = fence;
187443
+ if (fence === undefined) {
187444
+ fence = openingFence(line);
187445
+ } else if (closesFence(line, fence)) {
187446
+ fence = undefined;
187447
+ }
187448
+ const room = Math.max(8, capacity - Math.max(fenceOverhead(before), fenceOverhead(fence)));
187449
+ let rest = raw;
187450
+ while (rest.length > room) {
187451
+ const cut = cutAt(rest, room);
187452
+ pieces.push({ text: rest.slice(0, cut), fence: before ?? fence });
187453
+ rest = rest.slice(cut);
187454
+ }
187455
+ if (rest.length > 0) {
187456
+ pieces.push({ text: rest, fence });
187457
+ }
187458
+ }
187459
+ return pieces;
187460
+ }
187461
+ function pack(text, capacity) {
187462
+ const parts = [];
187463
+ let current = "";
187464
+ let hasContent = false;
187465
+ let open;
187466
+ const finish = () => {
187467
+ let body = current.trimEnd();
187468
+ if (!hasContent || body.length === 0) {
187469
+ current = "";
187470
+ hasContent = false;
187471
+ return;
187472
+ }
187473
+ if (open !== undefined) {
187474
+ body += `
187475
+ ${open.marker}`;
187476
+ }
187477
+ parts.push(body);
187478
+ current = open === undefined ? "" : `${open.header}
187479
+ `;
187480
+ hasContent = false;
187481
+ };
187482
+ for (const piece of toPieces(text, capacity)) {
187483
+ if (!hasContent && piece.text.trim().length === 0) {
187484
+ continue;
187485
+ }
187486
+ const closing = piece.fence === undefined ? 0 : piece.fence.marker.length + 1;
187487
+ if (hasContent && current.length + piece.text.length + closing > capacity) {
187488
+ finish();
187489
+ if (piece.text.trim().length === 0) {
187490
+ continue;
187491
+ }
187492
+ }
187493
+ current += piece.text;
187494
+ hasContent = true;
187495
+ open = piece.fence;
187496
+ }
187497
+ finish();
187498
+ return parts;
187499
+ }
187500
+ function formatReply(text, limit = TELEGRAM_MAX_TEXT) {
187501
+ if (limit < MIN_LIMIT) {
187502
+ throw new RangeError(`formatReply: limit must be at least ${MIN_LIMIT}`);
187503
+ }
187504
+ text = text.replace(/\r\n?/g, `
187505
+ `);
187506
+ if (text.trim().length === 0) {
187507
+ return [];
187508
+ }
187509
+ if (text.length <= limit) {
187510
+ return [text];
187511
+ }
187512
+ for (let digits = 1;digits <= 3; digits += 1) {
187513
+ const labelLength = 2 * digits + 4;
187514
+ const parts = pack(text, limit - labelLength);
187515
+ if (String(parts.length).length > digits) {
187516
+ continue;
187517
+ }
187518
+ if (parts.length <= 1) {
187519
+ return parts;
187520
+ }
187521
+ return parts.map((part, index) => `(${index + 1}/${parts.length})
187522
+ ${part}`);
187523
+ }
187524
+ const parts = pack(text, limit - 12).slice(0, 999);
187525
+ return parts.map((part, index) => `(${index + 1}/${parts.length})
187526
+ ${part}`);
187527
+ }
187528
+ var MIN_LIMIT = 64, MAX_FENCE_MARKER = 16, MAX_FENCE_INFO = 40, FENCE_LINE2;
187529
+ var init_format2 = __esm(() => {
187530
+ init_types11();
187531
+ FENCE_LINE2 = /^ {0,3}(`{3,}|~{3,})(.*)$/;
187532
+ });
187533
+
187534
+ // src/remote/format-html.ts
187535
+ function escapeHtml2(text) {
187536
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
187537
+ }
187538
+ function escapeAttribute(text) {
187539
+ return escapeHtml2(text).replace(/"/g, "&quot;");
187540
+ }
187541
+ function isWord(char) {
187542
+ return char !== undefined && WORD.test(char);
187543
+ }
187544
+ function isAlnum(char) {
187545
+ return char !== undefined && ALNUM.test(char);
187546
+ }
187547
+ function isSpace(char) {
187548
+ return char !== undefined && SPACE.test(char);
187549
+ }
187550
+ function codeSpan(text, start) {
187551
+ const run = backtickRun(text, start);
187552
+ let index = start + run;
187553
+ while (index < text.length) {
187554
+ if (text[index] === "`") {
187555
+ const next = backtickRun(text, index);
187556
+ if (next === run) {
187557
+ let content = text.slice(start + run, index);
187558
+ if (content.length > 2 && content.startsWith(" ") && content.endsWith(" ") && content.trim().length > 0) {
187559
+ content = content.slice(1, -1);
187560
+ }
187561
+ return content.length === 0 ? undefined : { content, end: index + run };
187562
+ }
187563
+ index += next;
187564
+ } else {
187565
+ index += 1;
187566
+ }
187567
+ }
187568
+ return;
187569
+ }
187570
+ function backtickRun(text, start) {
187571
+ let end = start;
187572
+ while (text[end] === "`") {
187573
+ end += 1;
187574
+ }
187575
+ return end - start;
187576
+ }
187577
+ function opens(text, index, marker) {
187578
+ const next = text[index + marker.length];
187579
+ const prev = text[index - 1];
187580
+ if (next === undefined || isSpace(next) || prev === "/" || prev === "\\") {
187581
+ return false;
187582
+ }
187583
+ const char = marker[0];
187584
+ if (marker.length === 1) {
187585
+ if (next === char || SINGLE_OPEN_BAD.test(next)) {
187586
+ return false;
187587
+ }
187588
+ return char === "*" ? !isAlnum(prev) : !isWord(prev);
187589
+ }
187590
+ return char === "_" ? !isWord(prev) : true;
187591
+ }
187592
+ function closes(text, index, marker) {
187593
+ const prev = text[index - 1];
187594
+ const after = text[index + marker.length];
187595
+ const char = marker[0];
187596
+ if (prev === undefined || isSpace(prev) || after === char) {
187597
+ return false;
187598
+ }
187599
+ if (marker.length === 1) {
187600
+ if (prev === char || SINGLE_CLOSE_BAD.test(prev)) {
187601
+ return false;
187602
+ }
187603
+ return char === "*" ? !isAlnum(after) : !isWord(after);
187604
+ }
187605
+ return char === "_" ? !isWord(after) : true;
187606
+ }
187607
+ function findCloser(text, from, marker) {
187608
+ let index = from;
187609
+ while (index < text.length) {
187610
+ if (text[index] === "`") {
187611
+ const span = codeSpan(text, index);
187612
+ index = span === undefined ? index + backtickRun(text, index) : span.end;
187613
+ continue;
187614
+ }
187615
+ if (text.startsWith(marker, index) && closes(text, index, marker)) {
187616
+ return index;
187617
+ }
187618
+ index += 1;
187619
+ }
187620
+ return -1;
187621
+ }
187622
+ function delimited(text, index, marker, flag, context) {
187623
+ if (!opens(text, index, marker)) {
187624
+ return;
187625
+ }
187626
+ const close = findCloser(text, index + marker.length + 1, marker);
187627
+ if (close < 0) {
187628
+ return;
187629
+ }
187630
+ const content = text.slice(index + marker.length, close);
187631
+ if (content.trim().length === 0 || marker === "__" && !/\s/.test(content.trim())) {
187632
+ return;
187633
+ }
187634
+ const inner = renderInline2(content, { ...context, [flag]: true });
187635
+ const html = context[flag] ? inner : `<${TAGS2[flag]}>${inner}</${TAGS2[flag]}>`;
187636
+ return { html, end: close + marker.length };
187637
+ }
187638
+ function link(text, index, context) {
187639
+ if (context.link) {
187640
+ return;
187641
+ }
187642
+ const middle = text.indexOf("](", index + 1);
187643
+ if (middle < 0) {
187644
+ return;
187645
+ }
187646
+ const label = text.slice(index + 1, middle);
187647
+ if (label.trim().length === 0 || label.includes("]")) {
187648
+ return;
187649
+ }
187650
+ let depth = 1;
187651
+ let end = middle + 2;
187652
+ while (end < text.length && depth > 0) {
187653
+ if (text[end] === "(") {
187654
+ depth += 1;
187655
+ } else if (text[end] === ")") {
187656
+ depth -= 1;
187657
+ }
187658
+ end += 1;
187659
+ }
187660
+ if (depth !== 0) {
187661
+ return;
187662
+ }
187663
+ const url = text.slice(middle + 2, end - 1);
187664
+ if (!HTTP_URL.test(url)) {
187665
+ return;
187666
+ }
187667
+ return { html: `<a href="${escapeAttribute(url)}">${renderInline2(label, { ...context, link: true })}</a>`, end };
187668
+ }
187669
+ function renderInline2(text, context) {
187670
+ let out = "";
187671
+ let index = 0;
187672
+ while (index < text.length) {
187673
+ const char = text[index];
187674
+ if (char === "`") {
187675
+ const span = context.link ? undefined : codeSpan(text, index);
187676
+ if (span === undefined) {
187677
+ const run = backtickRun(text, index);
187678
+ out += text.slice(index, index + run);
187679
+ index += run;
187680
+ } else {
187681
+ out += context.bold || context.italic || context.strike ? escapeHtml2(span.content) : `<code>${escapeHtml2(span.content)}</code>`;
187682
+ index = span.end;
187683
+ }
187684
+ continue;
187685
+ }
187686
+ if (char === "[") {
187687
+ const found = link(text, index, context);
187688
+ if (found !== undefined) {
187689
+ out += found.html;
187690
+ index = found.end;
187691
+ continue;
187692
+ }
187693
+ } else if (text.startsWith("**", index) || text.startsWith("__", index) || text.startsWith("~~", index)) {
187694
+ const marker = text.slice(index, index + 2);
187695
+ const found = delimited(text, index, marker, marker === "~~" ? "strike" : "bold", context);
187696
+ if (found === undefined) {
187697
+ out += marker;
187698
+ index += 2;
187699
+ } else {
187700
+ out += found.html;
187701
+ index = found.end;
187702
+ }
187703
+ continue;
187704
+ } else if (char === "*" || char === "_") {
187705
+ const found = delimited(text, index, char, "italic", context);
187706
+ if (found !== undefined) {
187707
+ out += found.html;
187708
+ index = found.end;
187709
+ continue;
187710
+ }
187711
+ }
187712
+ out += escapeHtml2(char);
187713
+ index += 1;
187714
+ }
187715
+ return out;
187716
+ }
187717
+ function renderTelegramHtml(part) {
187718
+ const lines = part.replace(/\r\n?/g, `
187719
+ `).split(`
187720
+ `);
187721
+ let out = "";
187722
+ let first = true;
187723
+ let afterBlock = false;
187724
+ const push = (html, block) => {
187725
+ if (!first && !afterBlock) {
187726
+ out += `
187727
+ `;
187728
+ }
187729
+ out += html;
187730
+ first = false;
187731
+ afterBlock = block;
187732
+ };
187733
+ let index = 0;
187734
+ while (index < lines.length) {
187735
+ const line = lines[index];
187736
+ const fence = fenceOpening(line);
187737
+ if (fence !== undefined) {
187738
+ const body = [];
187739
+ let cursor = index + 1;
187740
+ while (cursor < lines.length && !closesFence(lines[cursor], fence)) {
187741
+ body.push(lines[cursor]);
187742
+ cursor += 1;
187743
+ }
187744
+ const closed = cursor < lines.length;
187745
+ const code = body.join(`
187746
+ `);
187747
+ if (code.trim().length === 0) {
187748
+ push(escapeHtml2(lines.slice(index, closed ? cursor + 1 : cursor).join(`
187749
+ `)), false);
187750
+ } else {
187751
+ const language = fence.info.split(/\s+/)[0];
187752
+ const open = LANGUAGE.test(language) ? `<pre><code class="language-${escapeAttribute(language)}">` : "<pre><code>";
187753
+ push(`${open}${escapeHtml2(code)}</code></pre>`, true);
187754
+ }
187755
+ index = closed ? cursor + 1 : cursor;
187756
+ continue;
187757
+ }
187758
+ const quote = QUOTE.exec(line);
187759
+ if (quote !== null) {
187760
+ const quoted = [];
187761
+ while (index < lines.length) {
187762
+ const next = QUOTE.exec(lines[index]);
187763
+ if (next === null) {
187764
+ break;
187765
+ }
187766
+ quoted.push(next[1] ?? "");
187767
+ index += 1;
187768
+ }
187769
+ if (quoted.every((entry) => entry.trim().length === 0)) {
187770
+ push(escapeHtml2(lines.slice(index - quoted.length, index).join(`
187771
+ `)), false);
187772
+ } else {
187773
+ const tag = quoted.length >= EXPANDABLE_QUOTE_LINES ? "blockquote expandable" : "blockquote";
187774
+ push(`<${tag}>${quoted.map((entry) => renderInline2(entry, OUTSIDE)).join(`
187775
+ `)}</blockquote>`, true);
187776
+ }
187777
+ continue;
187778
+ }
187779
+ index += 1;
187780
+ const heading = HEADING2.exec(line);
187781
+ if (heading !== null && heading[1].trim().length > 0) {
187782
+ push(`<b>${renderInline2(heading[1], { ...OUTSIDE, bold: true })}</b>`, false);
187783
+ continue;
187784
+ }
187785
+ const bullet = BULLET.exec(line);
187786
+ if (bullet !== null) {
187787
+ push(`${bullet[1]}\u2022 ${renderInline2(bullet[2], OUTSIDE)}`, false);
187788
+ continue;
187789
+ }
187790
+ push(renderInline2(line, OUTSIDE), false);
187791
+ }
187792
+ return out;
187793
+ }
187794
+ function isEntityParseError(error) {
187795
+ return isBotApiError(error) && error.kind === "rejected" && error.status === 400 && /can't parse entities/i.test(error.message);
187796
+ }
187797
+ async function sendHtml(api, params, onFallback) {
187798
+ const { parseMode: _ignored, ...plain } = params;
187799
+ try {
187800
+ return await api.sendMessage({ ...plain, text: renderTelegramHtml(params.text), parseMode: "HTML" });
187801
+ } catch (error) {
187802
+ if (!isEntityParseError(error)) {
187803
+ throw error;
187804
+ }
187805
+ try {
187806
+ onFallback?.(error);
187807
+ } catch {}
187808
+ return api.sendMessage(plain);
187809
+ }
187810
+ }
187811
+ var OUTSIDE, WORD, ALNUM, SPACE, SINGLE_OPEN_BAD, SINGLE_CLOSE_BAD, HTTP_URL, LANGUAGE, EXPANDABLE_QUOTE_LINES = 8, TAGS2, HEADING2, BULLET, QUOTE, SIMPLE_TAGS;
187812
+ var init_format_html = __esm(() => {
187813
+ init_format2();
187814
+ init_types11();
187815
+ OUTSIDE = { bold: false, italic: false, strike: false, link: false };
187816
+ WORD = /[\p{L}\p{N}_]/u;
187817
+ ALNUM = /[\p{L}\p{N}]/u;
187818
+ SPACE = /\s/;
187819
+ SINGLE_OPEN_BAD = /[.,;:!?)\]}/\\|]/;
187820
+ SINGLE_CLOSE_BAD = /[([{/\\|]/;
187821
+ HTTP_URL = /^https?:\/\/[^\s<>"'`]+$/i;
187822
+ LANGUAGE = /^[A-Za-z0-9_+#.-]{1,32}$/;
187823
+ TAGS2 = { bold: "b", italic: "i", strike: "s" };
187824
+ HEADING2 = /^ {0,3}#{1,6}[ \t]+(.*?)(?:[ \t]+#+)?[ \t]*$/;
187825
+ BULLET = /^([ \t]*)[-*][ \t]+(.*)$/;
187826
+ QUOTE = /^ {0,3}>(?: (.*))?$/;
187827
+ SIMPLE_TAGS = new Set(["b", "strong", "i", "em", "u", "ins", "s", "strike", "del"]);
187828
+ });
187829
+
187388
187830
  // src/remote/durable-log.ts
187389
187831
  import { renameSync as renameSync6 } from "fs";
187390
187832
 
@@ -187699,139 +188141,6 @@ var init_journal2 = __esm(() => {
187699
188141
  init_paths4();
187700
188142
  });
187701
188143
 
187702
- // src/remote/format.ts
187703
- function openingFence(line) {
187704
- const match = FENCE_LINE2.exec(line);
187705
- if (match === null) {
187706
- return;
187707
- }
187708
- const marker = match[1];
187709
- const info = match[2].trim();
187710
- if (marker.length > MAX_FENCE_MARKER || marker.startsWith("`") && info.includes("`")) {
187711
- return;
187712
- }
187713
- return { marker, header: info.length > 0 && info.length <= MAX_FENCE_INFO ? `${marker}${info}` : marker };
187714
- }
187715
- function closesFence(line, fence) {
187716
- const match = FENCE_LINE2.exec(line);
187717
- if (match === null) {
187718
- return false;
187719
- }
187720
- const run = match[1];
187721
- return run[0] === fence.marker[0] && run.length >= fence.marker.length && match[2].trim().length === 0;
187722
- }
187723
- function fenceOverhead(fence) {
187724
- return fence === undefined ? 0 : fence.header.length + 1 + (fence.marker.length + 1);
187725
- }
187726
- function cutAt(text, max) {
187727
- if (text.length <= max) {
187728
- return text.length;
187729
- }
187730
- for (let index = max;index > 0; index -= 1) {
187731
- const ch = text[index - 1];
187732
- if (ch === " " || ch === "\t") {
187733
- return index;
187734
- }
187735
- }
187736
- const code = text.charCodeAt(max - 1);
187737
- return code >= 55296 && code <= 56319 ? max - 1 : max;
187738
- }
187739
- function toPieces(text, capacity) {
187740
- const pieces = [];
187741
- let fence;
187742
- for (const raw of text.split(/(?<=\n)/)) {
187743
- const line = raw.endsWith(`
187744
- `) ? raw.slice(0, -1) : raw;
187745
- const before = fence;
187746
- if (fence === undefined) {
187747
- fence = openingFence(line);
187748
- } else if (closesFence(line, fence)) {
187749
- fence = undefined;
187750
- }
187751
- const room = Math.max(8, capacity - Math.max(fenceOverhead(before), fenceOverhead(fence)));
187752
- let rest = raw;
187753
- while (rest.length > room) {
187754
- const cut = cutAt(rest, room);
187755
- pieces.push({ text: rest.slice(0, cut), fence: before ?? fence });
187756
- rest = rest.slice(cut);
187757
- }
187758
- if (rest.length > 0) {
187759
- pieces.push({ text: rest, fence });
187760
- }
187761
- }
187762
- return pieces;
187763
- }
187764
- function pack(text, capacity) {
187765
- const parts = [];
187766
- let current = "";
187767
- let hasContent = false;
187768
- let open;
187769
- const finish = () => {
187770
- let body = current.trimEnd();
187771
- if (!hasContent || body.length === 0) {
187772
- current = "";
187773
- hasContent = false;
187774
- return;
187775
- }
187776
- if (open !== undefined) {
187777
- body += `
187778
- ${open.marker}`;
187779
- }
187780
- parts.push(body);
187781
- current = open === undefined ? "" : `${open.header}
187782
- `;
187783
- hasContent = false;
187784
- };
187785
- for (const piece of toPieces(text, capacity)) {
187786
- if (!hasContent && piece.text.trim().length === 0) {
187787
- continue;
187788
- }
187789
- const closing = piece.fence === undefined ? 0 : piece.fence.marker.length + 1;
187790
- if (hasContent && current.length + piece.text.length + closing > capacity) {
187791
- finish();
187792
- if (piece.text.trim().length === 0) {
187793
- continue;
187794
- }
187795
- }
187796
- current += piece.text;
187797
- hasContent = true;
187798
- open = piece.fence;
187799
- }
187800
- finish();
187801
- return parts;
187802
- }
187803
- function formatReply(text, limit = TELEGRAM_MAX_TEXT) {
187804
- if (limit < MIN_LIMIT) {
187805
- throw new RangeError(`formatReply: limit must be at least ${MIN_LIMIT}`);
187806
- }
187807
- if (text.trim().length === 0) {
187808
- return [];
187809
- }
187810
- if (text.length <= limit) {
187811
- return [text];
187812
- }
187813
- for (let digits = 1;digits <= 3; digits += 1) {
187814
- const labelLength = 2 * digits + 4;
187815
- const parts = pack(text, limit - labelLength);
187816
- if (String(parts.length).length > digits) {
187817
- continue;
187818
- }
187819
- if (parts.length <= 1) {
187820
- return parts;
187821
- }
187822
- return parts.map((part, index) => `(${index + 1}/${parts.length})
187823
- ${part}`);
187824
- }
187825
- const parts = pack(text, limit - 12).slice(0, 999);
187826
- return parts.map((part, index) => `(${index + 1}/${parts.length})
187827
- ${part}`);
187828
- }
187829
- var MIN_LIMIT = 64, MAX_FENCE_MARKER = 16, MAX_FENCE_INFO = 40, FENCE_LINE2;
187830
- var init_format2 = __esm(() => {
187831
- init_types11();
187832
- FENCE_LINE2 = /^ {0,3}(`{3,}|~{3,})(.*)$/;
187833
- });
187834
-
187835
188144
  // src/remote/outbound-queue.ts
187836
188145
  import { randomUUID as randomUUID48 } from "crypto";
187837
188146
  import path356 from "path";
@@ -187857,6 +188166,7 @@ class OutboundQueue {
187857
188166
  now;
187858
188167
  log;
187859
188168
  onDrop;
188169
+ onFallback;
187860
188170
  retryDelayMs;
187861
188171
  blockedUntil = 0;
187862
188172
  flushing;
@@ -187866,6 +188176,9 @@ class OutboundQueue {
187866
188176
  this.onDrop = options.onDrop ?? (() => {
187867
188177
  return;
187868
188178
  });
188179
+ this.onFallback = options.onFallback ?? (() => {
188180
+ return;
188181
+ });
187869
188182
  this.retryDelayMs = options.retryDelayMs ?? 5000;
187870
188183
  const directory = ensureRemoteDir(options.dir);
187871
188184
  this.log = new DurableLog({
@@ -187934,12 +188247,12 @@ class OutboundQueue {
187934
188247
  return { sent, dropped, remaining: this.log.size, retryInMs: wait, stoppedBy: "rate limited" };
187935
188248
  }
187936
188249
  try {
187937
- await this.api.sendMessage({
188250
+ await sendHtml(this.api, {
187938
188251
  chatId: entry.chatId,
187939
188252
  text: entry.text,
187940
188253
  ...entry.threadId === undefined ? {} : { messageThreadId: entry.threadId },
187941
188254
  ...entry.keyboard === undefined ? {} : { inlineKeyboard: entry.keyboard }
187942
- });
188255
+ }, () => this.onFallback(entry));
187943
188256
  this.log.ack(entry.id);
187944
188257
  sent += 1;
187945
188258
  } catch (error) {
@@ -187968,6 +188281,7 @@ var init_outbound_queue = __esm(() => {
187968
188281
  init_durable_log();
187969
188282
  init_paths4();
187970
188283
  init_format2();
188284
+ init_format_html();
187971
188285
  init_types11();
187972
188286
  });
187973
188287
 
@@ -188275,7 +188589,8 @@ class RemoteHub {
188275
188589
  api: this.api,
188276
188590
  ...options.dir === undefined ? {} : { dir: options.dir },
188277
188591
  now: this.now,
188278
- onDrop: (entry, reason) => this.event("outbound-dropped", `${reason}${entry.threadId === undefined ? "" : ` (topic ${entry.threadId})`}`)
188592
+ onDrop: (entry, reason) => this.event("outbound-dropped", `${reason}${entry.threadId === undefined ? "" : ` (topic ${entry.threadId})`}`),
188593
+ onFallback: (entry) => this.event("format-fallback", `Telegram refused the formatting; sent as plain text${entry.threadId === undefined ? "" : ` (topic ${entry.threadId})`}`)
188279
188594
  });
188280
188595
  this.journal = new RejectedJournal({ ...options.dir === undefined ? {} : { dir: options.dir }, now: this.now });
188281
188596
  this.offset = new PollerState(options.dir === undefined ? {} : { dir: options.dir });
@@ -188402,7 +188717,7 @@ class RemoteHub {
188402
188717
  });
188403
188718
  }
188404
188719
  async sendGeneral(text) {
188405
- await this.api.sendMessage({ chatId: this.config.chatId, text });
188720
+ await sendHtml(this.api, { chatId: this.config.chatId, text }, () => this.event("format-fallback", "Telegram refused the formatting; sent as plain text (General)"));
188406
188721
  }
188407
188722
  heartbeat(sessionId) {
188408
188723
  return this.serial(async () => {
@@ -188753,6 +189068,7 @@ var realTimers, MAX_EVENTS = 50, ANSWER_CALLBACK_TIMEOUT_MS = 5000;
188753
189068
  var init_hub = __esm(() => {
188754
189069
  init_service2();
188755
189070
  init_lease();
189071
+ init_format_html();
188756
189072
  init_inbound();
188757
189073
  init_journal2();
188758
189074
  init_naming();
@@ -189199,7 +189515,7 @@ class RemoteHttpSurface {
189199
189515
  timer: this.timers.setTimeout(() => this.expireApproval(approvalId), timeoutMs)
189200
189516
  });
189201
189517
  const sent = await hub.send(sessionId, `Approval needed:
189202
- ${redactSensitiveText(value.prompt)}`, {
189518
+ ${asCodeBlock(redactSensitiveText(value.prompt))}`, {
189203
189519
  keyboard: [
189204
189520
  [
189205
189521
  { text: "Allow", callback_data: approvalCallbackData(approvalId, "allow") },
@@ -189414,7 +189730,16 @@ ${redactSensitiveText(value.prompt)}`, {
189414
189730
  }
189415
189731
  }
189416
189732
  }
189417
- var MAX_REPLY_CHARS = 20000, MAX_PENDING_APPROVALS_PER_SESSION = 8, MAX_REMEMBERED_IDS_PER_SESSION = 512, MAX_PROJECT_NAME_CHARS = 128, CONTROL_CHARS2, JSON_HEADERS2;
189733
+ function asCodeBlock(text) {
189734
+ const safe = (text.trim().length === 0 ? "(empty)" : text).replace(/\r\n?/g, `
189735
+ `).replace(/`{9,}/g, (run) => run.match(/`{1,8}/g).join("\u200B"));
189736
+ const longest = Math.max(0, ...(safe.match(/`+/g) ?? []).map((run) => run.length));
189737
+ const fence = "`".repeat(Math.max(3, Math.min(longest, MAX_BACKTICK_RUN) + 1));
189738
+ return `${fence}
189739
+ ${safe}
189740
+ ${fence}`;
189741
+ }
189742
+ var MAX_REPLY_CHARS = 20000, MAX_PENDING_APPROVALS_PER_SESSION = 8, MAX_REMEMBERED_IDS_PER_SESSION = 512, MAX_PROJECT_NAME_CHARS = 128, CONTROL_CHARS2, JSON_HEADERS2, MAX_BACKTICK_RUN = 8;
189418
189743
  var init_http_surface = __esm(() => {
189419
189744
  init_service2();
189420
189745
  init_hub();
@@ -189629,7 +189954,10 @@ class Pairing {
189629
189954
  this.state = "waiting-for-group";
189630
189955
  this.expiresAt = this.now() + this.ttlMs;
189631
189956
  this.armExpiryTimer();
189632
- await this.options.api.sendMessage({ chatId: message.chat.id, text: "Paired. Now add me to your group (a group with Topics turned on) and make me an administrator." }).catch(() => {
189957
+ await sendHtml(this.options.api, {
189958
+ chatId: message.chat.id,
189959
+ text: "Paired. Now add me to your group (a group with Topics turned on) and make me an administrator."
189960
+ }).catch(() => {
189633
189961
  return;
189634
189962
  });
189635
189963
  const early = [...this.earlyGroups.values()];
@@ -189743,6 +190071,7 @@ class Pairing {
189743
190071
  var PAIRING_CODE_TTL_MS, CODE_ALPHABET = "ABCDEFGHJKMNPQRSTUVWXYZ23456789", CODE_LENGTH = 8, FINAL, EARLY_GROUP_EVENTS = 20;
189744
190072
  var init_pairing = __esm(() => {
189745
190073
  init_service2();
190074
+ init_format_html();
189746
190075
  init_hub();
189747
190076
  init_poller();
189748
190077
  init_types11();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.3.55",
3
+ "version": "0.3.56",
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": {