paperclip/ui/src/lib/issue-reference.ts

154 lines
4.7 KiB
TypeScript
Raw Normal View History

type MarkdownNode = {
type: string;
value?: string;
url?: string;
children?: MarkdownNode[];
};
const BARE_ISSUE_IDENTIFIER_RE = /^[A-Z][A-Z0-9]+-\d+$/i;
[codex] Improve issue detail and issue-list UX (#3678) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - A core part of that is the operator experience around reading issue state, agent chat, and sub-task structure > - The current branch had a long run of issue-detail and issue-list UX fixes that all improve how humans follow and steer active work > - Those changes mostly live in the UI/chat surface and should be reviewed together instead of mixed with workspace/runtime work > - This pull request packages the issue-detail, chat, markdown, and sub-issue list improvements into one standalone change > - The benefit is a cleaner, less jumpy, more reliable issue workflow on desktop and mobile without coupling it to unrelated server/runtime refactors ## What Changed - Stabilized issue chat runtime wiring, optimistic comment handling, queued-comment cancellation, and composer anchoring during live updates - Fixed several issue-detail rendering and navigation regressions including placeholder bleed, local polling scope, mobile inbox-to-issue transitions, and visible refresh resets - Improved markdown and rich-content handling with advisory image normalization, editor fallback behavior, touch mention recovery, and `issue:` quicklook links - Refined sub-issue behavior with parent-derived defaults, current-user inheritance fixes, empty-state cleanup, and a reusable issue-list presentation for sub-issues - Added targeted UI tests for the new issue-detail, chat scroll/message, placeholder-data, markdown, and issue-list behaviors ## Verification - `pnpm vitest run ui/src/components/IssueChatThread.test.tsx ui/src/components/MarkdownEditor.test.tsx ui/src/components/IssuesList.test.tsx ui/src/context/LiveUpdatesProvider.test.tsx ui/src/lib/issue-chat-messages.test.ts ui/src/lib/issue-chat-scroll.test.ts ui/src/lib/issue-detail-subissues.test.ts ui/src/lib/query-placeholder-data.test.tsx ui/src/hooks/usePaperclipIssueRuntime.test.tsx` ## Risks - Medium: this branch touches the highest-traffic issue-detail UI paths, so regressions would show up as chat/thread or sub-issue UX glitches - The changes are UI-heavy and would benefit from reviewer screenshots or a quick manual browser pass before merge ## Model Used - OpenAI Codex coding agent (GPT-5-class runtime in Codex CLI; exact deployed model ID is not exposed in this environment), reasoning enabled, tool use and local code execution enabled ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-14 12:50:48 -05:00
const ISSUE_SCHEME_RE = /^issue:\/\/:?([^?#\s]+)(?:[?#].*)?$/i;
[codex] Refine markdown issue reference rendering (#4382) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - Task references are a core part of how operators understand issue relationships across the UI > - Those references appear both in markdown bodies and in sidebar relationship panels > - The rendering had drifted between surfaces, and inline markdown pills were reading awkwardly inside prose and lists > - This pull request unifies the underlying issue-reference treatment, routes issue descriptions through `MarkdownBody`, and switches inline markdown references to a cleaner text-link presentation > - The benefit is more consistent issue-reference UX with better readability in markdown-heavy views ## What Changed - unified sidebar and markdown issue-reference rendering around the shared issue-reference components - routed resting issue descriptions through `MarkdownBody` so description previews inherit the richer issue-reference treatment - replaced inline markdown pill chrome with a cleaner inline reference presentation for prose contexts - added and updated UI tests for `MarkdownBody` and `InlineEditor` ## Verification - `pnpm exec vitest run --project @paperclipai/ui ui/src/components/MarkdownBody.test.tsx ui/src/components/InlineEditor.test.tsx` ## Risks - Moderate UI risk: issue-reference rendering now differs intentionally between inline markdown and relationship sidebars, so regressions would show up as styling or hover-preview mismatches > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex GPT-5-based coding agent with tool use and code execution in the Codex CLI environment ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-24 09:39:21 -05:00
const ISSUE_REFERENCE_TOKEN_RE = /issue:\/\/:?[^\s<>()]+|https?:\/\/[^\s<>()]+|\/(?:[^\s<>()/]+\/)*issues\/[A-Z][A-Z0-9]+-\d+(?=$|[\s<>)\],.;!?:])|\b[A-Z][A-Z0-9]+-\d+\b/gi;
export function parseIssuePathIdFromPath(pathOrUrl: string | null | undefined): string | null {
if (!pathOrUrl) return null;
Fix external issue URL rewriting in markdown (#4558) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies. > - Issue and comment rendering is part of the board UI where humans supervise and inspect agent work. > - External Paperclip issue URLs can appear in comments as references to other runs, review threads, or remote test environments. > - Those links must preserve their full destination, including origin, port, and `#comment-...` fragments, or the operator is taken to the wrong place. > - The bug here was that absolute `http(s)` issue URLs were being normalized into internal `/issues/...` routes in the markdown path. > - This pull request stops rewriting absolute URLs while keeping internal issue-reference behavior for relative paths and identifiers. > - The benefit is that authored external links now navigate exactly where the operator expects, especially for remote test and comment-deep-link workflows. ## What Changed - Stopped `ui/src/lib/issue-reference.ts` from treating absolute `http(s)` URLs as internal issue paths. - Added defense-in-depth in `ui/src/lib/mention-chips.ts` so absolute `http(s)` URLs are never reclassified as issue mention chips. - Updated `ui/src/lib/issue-reference.test.ts` to cover absolute Paperclip URLs with preserved origin, port, and comment hash. - Updated `ui/src/components/MarkdownBody.test.tsx` to assert the reported URL renders as an external link, not an internal `/issues/...` href. ## Verification - `pnpm exec vitest run ui/src/lib/issue-reference.test.ts ui/src/components/MarkdownBody.test.tsx` - Expected result: `2` files passed, `37` tests passed. - Manual spot-check from the issue report path: a URL like `http://remote.example.test:3103/PAPA/issues/PAPA-115#comment-...` should remain an external link with its full destination preserved. ## Risks - Low risk. The change narrows when Paperclip rewrites URLs, so the main risk is if some existing workflow depended on absolute `http(s)` Paperclip URLs being converted into internal issue links. The added regression coverage is aimed at preventing that from regressing silently. ## Model Used - OpenAI Codex local agent via Paperclip `codex_local` - Backing model family: GPT-5-based Codex runtime - Exact backend model ID/version: not exposed by this adapter/runtime surface - Context window: not exposed by this adapter/runtime surface - Capabilities used: tool use, shell command execution, code editing, git operations, and local test execution ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] I will address all Greptile and reviewer comments before requesting merge
2026-04-26 17:19:23 -07:00
const pathname = pathOrUrl.trim();
if (!pathname) return null;
Fix external issue URL rewriting in markdown (#4558) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies. > - Issue and comment rendering is part of the board UI where humans supervise and inspect agent work. > - External Paperclip issue URLs can appear in comments as references to other runs, review threads, or remote test environments. > - Those links must preserve their full destination, including origin, port, and `#comment-...` fragments, or the operator is taken to the wrong place. > - The bug here was that absolute `http(s)` issue URLs were being normalized into internal `/issues/...` routes in the markdown path. > - This pull request stops rewriting absolute URLs while keeping internal issue-reference behavior for relative paths and identifiers. > - The benefit is that authored external links now navigate exactly where the operator expects, especially for remote test and comment-deep-link workflows. ## What Changed - Stopped `ui/src/lib/issue-reference.ts` from treating absolute `http(s)` URLs as internal issue paths. - Added defense-in-depth in `ui/src/lib/mention-chips.ts` so absolute `http(s)` URLs are never reclassified as issue mention chips. - Updated `ui/src/lib/issue-reference.test.ts` to cover absolute Paperclip URLs with preserved origin, port, and comment hash. - Updated `ui/src/components/MarkdownBody.test.tsx` to assert the reported URL renders as an external link, not an internal `/issues/...` href. ## Verification - `pnpm exec vitest run ui/src/lib/issue-reference.test.ts ui/src/components/MarkdownBody.test.tsx` - Expected result: `2` files passed, `37` tests passed. - Manual spot-check from the issue report path: a URL like `http://remote.example.test:3103/PAPA/issues/PAPA-115#comment-...` should remain an external link with its full destination preserved. ## Risks - Low risk. The change narrows when Paperclip rewrites URLs, so the main risk is if some existing workflow depended on absolute `http(s)` Paperclip URLs being converted into internal issue links. The added regression coverage is aimed at preventing that from regressing silently. ## Model Used - OpenAI Codex local agent via Paperclip `codex_local` - Backing model family: GPT-5-based Codex runtime - Exact backend model ID/version: not exposed by this adapter/runtime surface - Context window: not exposed by this adapter/runtime surface - Capabilities used: tool use, shell command execution, code editing, git operations, and local test execution ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] I will address all Greptile and reviewer comments before requesting merge
2026-04-26 17:19:23 -07:00
if (/^https?:\/\//i.test(pathname)) return null;
const segments = pathname.split("/").filter(Boolean);
const issueIndex = segments.findIndex((segment) => segment === "issues");
if (issueIndex === -1 || issueIndex === segments.length - 1) return null;
Sync/master post pap1497 followups 2026 04 15 (#3779) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - The board depends on issue, inbox, cost, and company-skill surfaces to stay accurate and fast while agents are actively working > - The PAP-1497 follow-up branch exposed a few rough edges in those surfaces: stale active-run state on completed issues, missing creator filters, oversized issue payload scans, and placeholder issue-route parsing > - Those gaps make the control plane harder to trust because operators can see misleading run state, miss the right subset of work, or pay extra query/render cost on large issue records > - This pull request tightens those follow-ups across server and UI code, and adds regression coverage for the affected paths > - The benefit is a more reliable issue workflow, safer high-volume cost aggregation, and clearer board/operator navigation ## What Changed - Added the `v2026.415.0` release changelog entry. - Fixed stale issue-run presentation after completion and reused the shared issue-path parser so literal route placeholders no longer become issue links. - Added creator filters to the Issues page and Inbox, including persisted filter-state normalization and regression coverage. - Bounded issue detail/list project-mention scans and trimmed large issue-list payload fields to keep issue reads lighter. - Hardened company-skill list projection and cost/finance aggregation so large markdown blobs and large summed values do not leak into list responses or overflow 32-bit casts. - Added targeted server/UI regression tests for company skills, costs/finance, issue mention scanning, creator filters, inbox normalization, and issue reference parsing. ## Verification - `pnpm exec vitest run server/src/__tests__/company-skills-service.test.ts server/src/__tests__/costs-service.test.ts server/src/__tests__/issues-goal-context-routes.test.ts server/src/__tests__/issues-service.test.ts ui/src/lib/inbox.test.ts ui/src/lib/issue-filters.test.ts ui/src/lib/issue-reference.test.ts` - `gh pr checks 3779` Current pass set on the PR head: `policy`, `verify`, `e2e`, `security/snyk (cryppadotta)`, `Greptile Review` ## Risks - Creator filter options are derived from the currently loaded issue/agent data, so very sparse result sets may not surface every historical creator until they appear in the active dataset. - Cost/finance aggregate casts now use `double precision`; that removes the current overflow risk, but future schema changes should keep large-value aggregation behavior under review. - Issue detail mention scanning now skips comment-body scans on the detail route, so any consumer that relied on comment-only project mentions there would need to fetch them separately. ## Model Used - OpenAI Codex, GPT-5-based coding agent with terminal tool use and local code execution in the Paperclip workspace. Exact internal model ID/context-window exposure is not surfaced in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-15 21:13:56 -05:00
const issuePathId = decodeURIComponent(segments[issueIndex + 1] ?? "");
if (!issuePathId || issuePathId.startsWith(":")) return null;
[codex] Refine markdown issue reference rendering (#4382) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - Task references are a core part of how operators understand issue relationships across the UI > - Those references appear both in markdown bodies and in sidebar relationship panels > - The rendering had drifted between surfaces, and inline markdown pills were reading awkwardly inside prose and lists > - This pull request unifies the underlying issue-reference treatment, routes issue descriptions through `MarkdownBody`, and switches inline markdown references to a cleaner text-link presentation > - The benefit is more consistent issue-reference UX with better readability in markdown-heavy views ## What Changed - unified sidebar and markdown issue-reference rendering around the shared issue-reference components - routed resting issue descriptions through `MarkdownBody` so description previews inherit the richer issue-reference treatment - replaced inline markdown pill chrome with a cleaner inline reference presentation for prose contexts - added and updated UI tests for `MarkdownBody` and `InlineEditor` ## Verification - `pnpm exec vitest run --project @paperclipai/ui ui/src/components/MarkdownBody.test.tsx ui/src/components/InlineEditor.test.tsx` ## Risks - Moderate UI risk: issue-reference rendering now differs intentionally between inline markdown and relationship sidebars, so regressions would show up as styling or hover-preview mismatches > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex GPT-5-based coding agent with tool use and code execution in the Codex CLI environment ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-24 09:39:21 -05:00
return BARE_ISSUE_IDENTIFIER_RE.test(issuePathId) ? issuePathId.toUpperCase() : issuePathId;
}
export function parseIssueReferenceFromHref(href: string | null | undefined) {
if (!href) return null;
[codex] Improve issue detail and issue-list UX (#3678) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - A core part of that is the operator experience around reading issue state, agent chat, and sub-task structure > - The current branch had a long run of issue-detail and issue-list UX fixes that all improve how humans follow and steer active work > - Those changes mostly live in the UI/chat surface and should be reviewed together instead of mixed with workspace/runtime work > - This pull request packages the issue-detail, chat, markdown, and sub-issue list improvements into one standalone change > - The benefit is a cleaner, less jumpy, more reliable issue workflow on desktop and mobile without coupling it to unrelated server/runtime refactors ## What Changed - Stabilized issue chat runtime wiring, optimistic comment handling, queued-comment cancellation, and composer anchoring during live updates - Fixed several issue-detail rendering and navigation regressions including placeholder bleed, local polling scope, mobile inbox-to-issue transitions, and visible refresh resets - Improved markdown and rich-content handling with advisory image normalization, editor fallback behavior, touch mention recovery, and `issue:` quicklook links - Refined sub-issue behavior with parent-derived defaults, current-user inheritance fixes, empty-state cleanup, and a reusable issue-list presentation for sub-issues - Added targeted UI tests for the new issue-detail, chat scroll/message, placeholder-data, markdown, and issue-list behaviors ## Verification - `pnpm vitest run ui/src/components/IssueChatThread.test.tsx ui/src/components/MarkdownEditor.test.tsx ui/src/components/IssuesList.test.tsx ui/src/context/LiveUpdatesProvider.test.tsx ui/src/lib/issue-chat-messages.test.ts ui/src/lib/issue-chat-scroll.test.ts ui/src/lib/issue-detail-subissues.test.ts ui/src/lib/query-placeholder-data.test.tsx ui/src/hooks/usePaperclipIssueRuntime.test.tsx` ## Risks - Medium: this branch touches the highest-traffic issue-detail UI paths, so regressions would show up as chat/thread or sub-issue UX glitches - The changes are UI-heavy and would benefit from reviewer screenshots or a quick manual browser pass before merge ## Model Used - OpenAI Codex coding agent (GPT-5-class runtime in Codex CLI; exact deployed model ID is not exposed in this environment), reasoning enabled, tool use and local code execution enabled ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-14 12:50:48 -05:00
const trimmed = href.trim();
const issueSchemeMatch = trimmed.match(ISSUE_SCHEME_RE);
if (issueSchemeMatch?.[1]) {
const issuePathId = decodeURIComponent(issueSchemeMatch[1]);
return {
issuePathId,
href: `/issues/${encodeURIComponent(issuePathId)}`,
};
}
const pathId = parseIssuePathIdFromPath(href);
if (pathId) {
return {
issuePathId: pathId,
href: `/issues/${encodeURIComponent(pathId)}`,
};
}
if (!BARE_ISSUE_IDENTIFIER_RE.test(trimmed)) return null;
const normalized = trimmed.toUpperCase();
return {
issuePathId: normalized,
href: `/issues/${encodeURIComponent(normalized)}`,
};
}
function splitTrailingPunctuation(token: string) {
let core = token;
let trailing = "";
while (core.length > 0) {
const lastChar = core.at(-1);
[codex] Refine markdown issue reference rendering (#4382) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - Task references are a core part of how operators understand issue relationships across the UI > - Those references appear both in markdown bodies and in sidebar relationship panels > - The rendering had drifted between surfaces, and inline markdown pills were reading awkwardly inside prose and lists > - This pull request unifies the underlying issue-reference treatment, routes issue descriptions through `MarkdownBody`, and switches inline markdown references to a cleaner text-link presentation > - The benefit is more consistent issue-reference UX with better readability in markdown-heavy views ## What Changed - unified sidebar and markdown issue-reference rendering around the shared issue-reference components - routed resting issue descriptions through `MarkdownBody` so description previews inherit the richer issue-reference treatment - replaced inline markdown pill chrome with a cleaner inline reference presentation for prose contexts - added and updated UI tests for `MarkdownBody` and `InlineEditor` ## Verification - `pnpm exec vitest run --project @paperclipai/ui ui/src/components/MarkdownBody.test.tsx ui/src/components/InlineEditor.test.tsx` ## Risks - Moderate UI risk: issue-reference rendering now differs intentionally between inline markdown and relationship sidebars, so regressions would show up as styling or hover-preview mismatches > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex GPT-5-based coding agent with tool use and code execution in the Codex CLI environment ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-24 09:39:21 -05:00
if (!lastChar || !/[),.;!?:\]]/.test(lastChar)) break;
if (lastChar === ")") {
const openCount = (core.match(/\(/g) ?? []).length;
const closeCount = (core.match(/\)/g) ?? []).length;
if (closeCount <= openCount) break;
}
[codex] Refine markdown issue reference rendering (#4382) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - Task references are a core part of how operators understand issue relationships across the UI > - Those references appear both in markdown bodies and in sidebar relationship panels > - The rendering had drifted between surfaces, and inline markdown pills were reading awkwardly inside prose and lists > - This pull request unifies the underlying issue-reference treatment, routes issue descriptions through `MarkdownBody`, and switches inline markdown references to a cleaner text-link presentation > - The benefit is more consistent issue-reference UX with better readability in markdown-heavy views ## What Changed - unified sidebar and markdown issue-reference rendering around the shared issue-reference components - routed resting issue descriptions through `MarkdownBody` so description previews inherit the richer issue-reference treatment - replaced inline markdown pill chrome with a cleaner inline reference presentation for prose contexts - added and updated UI tests for `MarkdownBody` and `InlineEditor` ## Verification - `pnpm exec vitest run --project @paperclipai/ui ui/src/components/MarkdownBody.test.tsx ui/src/components/InlineEditor.test.tsx` ## Risks - Moderate UI risk: issue-reference rendering now differs intentionally between inline markdown and relationship sidebars, so regressions would show up as styling or hover-preview mismatches > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex GPT-5-based coding agent with tool use and code execution in the Codex CLI environment ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-24 09:39:21 -05:00
if (lastChar === "]") {
const openCount = (core.match(/\[/g) ?? []).length;
const closeCount = (core.match(/\]/g) ?? []).length;
if (closeCount <= openCount) break;
}
trailing = `${lastChar}${trailing}`;
core = core.slice(0, -1);
}
return { core, trailing };
}
function createIssueLinkNode(value: string, href: string, childType: "text" | "inlineCode" = "text"): MarkdownNode {
return {
type: "link",
url: href,
children: [{ type: childType, value }],
};
}
function linkifyIssueReferencesInText(value: string): MarkdownNode[] | null {
const nodes: MarkdownNode[] = [];
let cursor = 0;
let matched = false;
for (const match of value.matchAll(ISSUE_REFERENCE_TOKEN_RE)) {
const raw = match[0];
if (!raw) continue;
const start = match.index ?? 0;
const end = start + raw.length;
const { core, trailing } = splitTrailingPunctuation(raw);
const issueRef = parseIssueReferenceFromHref(core);
if (!issueRef) continue;
matched = true;
if (start > cursor) {
nodes.push({ type: "text", value: value.slice(cursor, start) });
}
nodes.push(createIssueLinkNode(core, issueRef.href));
if (trailing) {
nodes.push({ type: "text", value: trailing });
}
cursor = end;
}
if (!matched) return null;
if (cursor < value.length) {
nodes.push({ type: "text", value: value.slice(cursor) });
}
return nodes;
}
function rewriteMarkdownTree(node: MarkdownNode) {
if (!Array.isArray(node.children) || node.children.length === 0) return;
if (node.type === "link" || node.type === "linkReference" || node.type === "code" || node.type === "definition" || node.type === "html") {
return;
}
const nextChildren: MarkdownNode[] = [];
for (const child of node.children) {
if (child.type === "inlineCode" && typeof child.value === "string") {
const issueRef = parseIssueReferenceFromHref(child.value);
if (issueRef) {
nextChildren.push(createIssueLinkNode(child.value, issueRef.href, "inlineCode"));
continue;
}
}
if (child.type === "text" && typeof child.value === "string") {
const linked = linkifyIssueReferencesInText(child.value);
if (linked) {
nextChildren.push(...linked);
continue;
}
}
rewriteMarkdownTree(child);
nextChildren.push(child);
}
node.children = nextChildren;
}
export function remarkLinkIssueReferences() {
return (tree: MarkdownNode) => {
rewriteMarkdownTree(tree);
};
}