@bitkyc08/opencodex 2.6.11 → 2.6.12

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.
@@ -16,7 +16,7 @@
16
16
  } catch (e) {}
17
17
  })();
18
18
  </script>
19
- <script type="module" crossorigin src="/assets/index-DaRQZAM0.js"></script>
19
+ <script type="module" crossorigin src="/assets/index-CTjsL04v.js"></script>
20
20
  <link rel="stylesheet" crossorigin href="/assets/index-DIBiVVC0.css">
21
21
  </head>
22
22
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitkyc08/opencodex",
3
- "version": "2.6.11",
3
+ "version": "2.6.12",
4
4
  "description": "Universal provider proxy for OpenAI Codex — use any LLM with Codex CLI/App/SDK",
5
5
  "type": "module",
6
6
  "main": "./bin/package-main.mjs",
@@ -41,38 +41,75 @@ function collectAnnotation(ann: AnnotationLike | undefined, sources: WebSearchSo
41
41
  * answer text with that section stripped so the tool_result renderer doesn't double-print sources.
42
42
  *
43
43
  * Handles the per-line forms seen from the backend: `- title: url`, `- title (url)`,
44
- * `- [title](url)`, `- <url>`, `- url`, and numbered `1. ...` variants.
44
+ * `- [title](url)`, `- <url>`, `- url`, numbered `1. ...` variants, a markdown-prefixed header
45
+ * (`### Sources:`, `**Sources**`), a title line whose URL sits on the FOLLOWING line, and trailing
46
+ * URL punctuation (`;`, `,`, `)`, `]`, `.`). Prose that follows the source list is preserved.
45
47
  */
46
- const URL_RE = /https?:\/\/[^\s<>()\]]+/;
48
+ const URL_RE = /https?:\/\/[^\s<>()\[\]]+/;
49
+ // A "Sources:" / "Source:" header, allowing markdown prefixes (#, *, -, >) and bold/italic wrappers.
50
+ const SOURCES_HEADER_RE = /^\s*(?:#{1,6}\s*)?[-*>\s]*\**\s*sources?\s*\**\s*:?\s*\**\s*$/i;
51
+
52
+ /** Trim wrapping/trailing noise from a captured URL: angle brackets, then trailing punctuation. */
53
+ function cleanUrl(url: string): string {
54
+ return url.replace(/^<+/, "").replace(/[)>\].,;:]+$/, "");
55
+ }
56
+
57
+ /** Derive a human title from the list-item text preceding the URL (strip markers, md link, seps). */
58
+ function cleanTitle(prefix: string): string {
59
+ let title = prefix.replace(/^[-*>\d.)\s]+/, "").trim();
60
+ // `[title](` from a markdown link, or a leading `[`.
61
+ title = title.replace(/^\[/, "").replace(/\]\(?$/, "").replace(/[:\-—(<]\s*$/, "").trim();
62
+ return title;
63
+ }
64
+
47
65
  function extractTrailingSources(text: string): { text: string; sources: WebSearchSource[] } {
48
66
  const lines = text.split("\n");
49
- // Find the LAST line that is just a "Sources:" / "Source:" header (case-insensitive).
67
+ // Find the LAST line that is a "Sources:" header (markdown prefixes allowed).
50
68
  let headerIdx = -1;
51
69
  for (let i = lines.length - 1; i >= 0; i--) {
52
- if (/^\s*\**\s*sources?\s*:?\s*\**\s*$/i.test(lines[i])) { headerIdx = i; break; }
70
+ if (SOURCES_HEADER_RE.test(lines[i])) { headerIdx = i; break; }
53
71
  }
54
72
  if (headerIdx === -1) return { text, sources: [] };
55
73
  const sources: WebSearchSource[] = [];
56
74
  const seen = new Set<string>();
75
+ // Track the last line index actually consumed as part of the source list so trailing prose after
76
+ // the list survives (we strip the header through the last consumed source line, not to EOF).
77
+ let lastConsumed = headerIdx;
78
+ // A title line whose URL is expected on a following line (multiline entry).
79
+ let pendingTitle: string | null = null;
57
80
  for (let i = headerIdx + 1; i < lines.length; i++) {
58
81
  const raw = lines[i].trim();
59
- if (raw === "") continue;
60
- // Only consume list-ish lines that carry a URL; stop at the first non-source line so we don't
61
- // swallow trailing prose after the section.
82
+ if (raw === "") {
83
+ // Blank line between header and first entry is fine; a blank AFTER entries ends the list.
84
+ if (sources.length > 0 || pendingTitle !== null) break;
85
+ continue;
86
+ }
62
87
  const m = raw.match(URL_RE);
63
- if (!m) break;
64
- const url = m[0].replace(/[).,]+$/, "");
88
+ if (!m) {
89
+ // A list-ish line with no URL may be a title whose URL is on the next line. Only treat it as a
90
+ // pending title when it looks like a list item; otherwise it's prose → stop.
91
+ if (/^[-*>\d.)]/.test(raw) || pendingTitle === null) {
92
+ if (/^[-*>\d.)]/.test(raw)) { pendingTitle = raw; lastConsumed = i; continue; }
93
+ }
94
+ break;
95
+ }
96
+ const url = cleanUrl(m[0]);
97
+ if (!url) { break; }
98
+ lastConsumed = i;
99
+ // Title: text before the URL on this line, else a buffered title from a preceding line.
100
+ const inlinePrefix = raw.slice(0, m.index);
101
+ const title = cleanTitle(inlinePrefix) || (pendingTitle ? cleanTitle(pendingTitle) : "");
102
+ pendingTitle = null;
65
103
  if (seen.has(url)) continue;
66
104
  seen.add(url);
67
- // Derive a title from the text before the URL: strip list markers, [md](), and separators.
68
- let title = raw.slice(0, m.index).replace(/^[-*\d.)\s]+/, "").trim();
69
- title = title.replace(/^\[/, "").replace(/\]\(?$/, "").replace(/[:\-—(]\s*$/, "").trim();
70
105
  sources.push(title ? { url, title } : { url });
71
106
  }
72
107
  if (sources.length === 0) return { text, sources: [] };
73
- // Strip the Sources section (header + consumed lines) from the answer text.
74
- const stripped = lines.slice(0, headerIdx).join("\n").replace(/\s+$/, "");
75
- return { text: stripped, sources };
108
+ // Keep text before the header AND any prose after the consumed source lines.
109
+ const before = lines.slice(0, headerIdx).join("\n").replace(/\s+$/, "");
110
+ const after = lines.slice(lastConsumed + 1).join("\n").replace(/^\s+/, "");
111
+ const body = after ? (before ? `${before}\n\n${after}` : after) : before;
112
+ return { text: body, sources };
76
113
  }
77
114
 
78
115
  /** Pull final text + url_citation sources from a completed Responses `output[]` array. */