Conversation
- add .github/copilot-instructions.md for GitHub Copilot (Codex) - add .claude/CLAUDE.md and symlink skills for Claude Code - add opencode.jsonc for OpenCode - fix subtrack/CLAUDE.md (better-sqlite3 -> sql.js) - add Node.js 24, type checking, and audit to CI - add --provenance flag to release workflow - add subtrack export csv command with BOM, tag filter, currency conversion - add subtrack export md command with formatted markdown tables
|
Warning Review limit reached
More reviews will be available in 40 minutes and 19 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds ChangesExport CLI feature (csv/md)
AI tooling, documentation, and CI
Sequence Diagram(s)sequenceDiagram
actor User
participant index.ts
participant handleExport
participant fetchFxRates as fetchFxRates (display.ts)
participant exportCsv_exportMd as exportCsv / exportMd (display.ts)
User->>index.ts: subtrack export csv --currency EUR --tags saas
index.ts->>handleExport: handleExport("csv", {currency:"EUR", tags:"saas"})
handleExport->>handleExport: validate format, filter subs by tag "saas"
handleExport->>fetchFxRates: fetchFxRates()
fetchFxRates-->>handleExport: FxRates map
handleExport->>handleExport: convertPrice(sub.price, EUR) for each sub
handleExport->>exportCsv_exportMd: exportCsv(convertedSubs)
exportCsv_exportMd-->>handleExport: BOM + CSV string
handleExport-->>User: consola.log(csv output)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
subtrack/CLAUDE.md (1)
65-76:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winDocument
subtrack export mdin the commands tableLine 75 documents
subtrack export csv, but the CLI also supportssubtrack export md; omitting it makes the command reference incomplete.Suggested fix
| `subtrack payment [period]` | Show payment totals | | `subtrack export csv` | Export subscriptions as CSV | +| `subtrack export md` | Export subscriptions as Markdown |🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@subtrack/CLAUDE.md` around lines 65 - 76, The Commands table in the documentation is incomplete and missing the `subtrack export md` command. Add a new row to the commands table after the `subtrack export csv` row that documents the `subtrack export md` command with an appropriate description indicating it exports subscriptions as Markdown format. This will ensure the documentation accurately reflects all available export options in the CLI.
🧹 Nitpick comments (2)
.github/workflows/app-ci.yml (1)
56-58: ⚡ Quick winUse
pnpmx/pnpm execinstead ofnpxfor type-check step.Line 58 currently uses
npx tsc --noEmit. Please switch topnpm exec tsc --noEmit(orpnpmx tsc --noEmit) to keep tool execution aligned with the repo’s package-manager convention.Based on learnings: "Use pnpmx instead of npx or bunx for running packages".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/app-ci.yml around lines 56 - 58, In the Type check step of the workflow, replace the npx command with pnpm exec to align with the repository's package manager convention. Change the run command from using npx tsc --noEmit to using pnpm exec tsc --noEmit (or alternatively pnpmx tsc --noEmit) to ensure consistent tool execution across the CI pipeline.Source: Learnings
subtrack/src/display.test.ts (1)
257-345: ⚡ Quick winAdd tests for escaping-critical branches in both exporters.
Current cases miss high-risk paths: CSV tags containing comma/quote/newline, and Markdown cells containing
|/newline. These are critical serialization branches and should be explicitly covered.As per coding guidelines,
**/*.test.{js,ts,jsx,tsx}requires unit tests for all functions and critical code paths.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@subtrack/src/display.test.ts` around lines 257 - 345, Add additional test cases to cover critical escaping scenarios that are currently missing. For the exportCsv function, add new tests that verify proper handling when tags contain commas, quotes, or newlines. For the exportMd function, add new tests that verify proper handling when subscription names or other fields contain pipe characters (|) or newlines, as these are critical delimiters in markdown tables. These tests should use the existing makeSub helper to create test data with these edge-case characters and verify that the output properly escapes or formats them according to CSV and Markdown specifications.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.claude/CLAUDE.md:
- Around line 7-15: The fenced code block displaying the directory structure
(starting with the `.` symbol and containing the subtrack/, docs/, .agents/,
.claude/, flake.nix, and pnpm-workspace.yaml entries) is missing a language
identifier tag, which violates the MD040 rule. Add "text" as the language
identifier immediately after the opening triple backticks (```) of this code
fence to properly indicate the code block type and satisfy the markdown linting
requirement.
In @.github/workflows/app-ci.yml:
- Around line 80-85: The GitHub Action reference for crate-ci/typos in the
"Spell check with typos" step uses a mutable version tag reference (v1.47.2)
instead of being pinned to a specific commit SHA. Replace the version tag
reference in the uses field with the full commit SHA of the v1.47.2 release to
strengthen supply-chain security and ensure the exact version of the action is
always used, preventing unexpected changes from tag mutations.
In `@opencode.jsonc`:
- Around line 7-12: In the opencode.jsonc file, replace the absolute
machine-specific paths in the location fields for the "subtrack-rules" and
"subtrack-commit" skills. Instead of using the full absolute path starting with
/home/nazozokc/ghq/github.com/nazozokc/subtrack/, use repository-relative paths
starting with ./.agents/skills/ (e.g., ./.agents/skills/subtrack-rules/SKILL.md
and ./.agents/skills/subtrack-commit/SKILL.md) to ensure the configuration works
across different machines and CI environments.
In `@subtrack/src/commands.ts`:
- Around line 238-242: The price conversion in the map function that processes
subscriptions is not accounting for the smallest-unit integer representation
required by the contract. Before passing sub.price to the convertPrice function,
normalize it from smallest-unit integers to whole currency units by dividing by
the appropriate decimal places for sub.currency. After convertPrice returns the
converted amount in whole units, normalize it back to smallest-unit integers by
multiplying by the decimal places of the target currency (options.currency).
Apply Math.round to the final result to ensure an integer value is stored in the
price field.
In `@subtrack/src/display.ts`:
- Around line 288-290: The tags field is being escaped at the individual tag
level before joining, but the entire joined tags string needs to be escaped as a
complete CSV field to properly handle special CSV characters. Modify the code
around line 288 to first join the raw tags with semicolons, then apply escapeCsv
to the entire joined result as a single field rather than escaping each tag
individually before joining.
- Around line 302-305: The Markdown table construction in the anonymous function
return statement is injecting raw values like s.name, s.cycle, tags, price, and
s.currency without escaping special characters. Values containing pipe
characters (|) or newlines will break the table structure. Before interpolating
these values into the template string, escape pipe characters and newlines by
replacing them with safe alternatives (for example, pipe characters can be
replaced with a space or backslash-escaped). Apply the escaping to all values
being interpolated in the return statement to ensure table integrity.
- Around line 17-23: The fetchFxRates function performs an external network call
without a timeout, which can cause indefinite blocking on network stalls. Add a
timeout mechanism using AbortController to the fetch call. Create an
AbortController instance, set a timeout (e.g., 5 seconds) that aborts the
controller, pass the abort signal to the fetch request via the options
parameter, and handle the AbortError appropriately in the error handling logic.
---
Outside diff comments:
In `@subtrack/CLAUDE.md`:
- Around line 65-76: The Commands table in the documentation is incomplete and
missing the `subtrack export md` command. Add a new row to the commands table
after the `subtrack export csv` row that documents the `subtrack export md`
command with an appropriate description indicating it exports subscriptions as
Markdown format. This will ensure the documentation accurately reflects all
available export options in the CLI.
---
Nitpick comments:
In @.github/workflows/app-ci.yml:
- Around line 56-58: In the Type check step of the workflow, replace the npx
command with pnpm exec to align with the repository's package manager
convention. Change the run command from using npx tsc --noEmit to using pnpm
exec tsc --noEmit (or alternatively pnpmx tsc --noEmit) to ensure consistent
tool execution across the CI pipeline.
In `@subtrack/src/display.test.ts`:
- Around line 257-345: Add additional test cases to cover critical escaping
scenarios that are currently missing. For the exportCsv function, add new tests
that verify proper handling when tags contain commas, quotes, or newlines. For
the exportMd function, add new tests that verify proper handling when
subscription names or other fields contain pipe characters (|) or newlines, as
these are critical delimiters in markdown tables. These tests should use the
existing makeSub helper to create test data with these edge-case characters and
verify that the output properly escapes or formats them according to CSV and
Markdown specifications.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 286462dd-45be-4b37-8e0a-810f7435b4f5
📒 Files selected for processing (11)
.claude/CLAUDE.md.claude/skills.github/copilot-instructions.md.github/workflows/app-ci.yml.github/workflows/release.ymlopencode.jsoncsubtrack/CLAUDE.mdsubtrack/src/commands.tssubtrack/src/display.test.tssubtrack/src/display.tssubtrack/src/index.ts
| ``` | ||
| . | ||
| ├── subtrack/ # CLI tool (Node.js/TypeScript, published as npm package) | ||
| ├── docs/ # Documentation site (SvelteKit) | ||
| ├── .agents/ # OpenCode agent and skill definitions | ||
| ├── .claude/ # Claude Code configuration | ||
| ├── flake.nix # Nix devShell / CI shell | ||
| └── pnpm-workspace.yaml | ||
| ``` |
There was a problem hiding this comment.
Add a language tag to the fenced code block
The code fence starting at Line 7 has no language identifier (MD040).
Suggested fix
-```
+```text
.
├── subtrack/ # CLI tool (Node.js/TypeScript, published as npm package)
├── docs/ # Documentation site (SvelteKit)
├── .agents/ # OpenCode agent and skill definitions
├── .claude/ # Claude Code configuration
├── flake.nix # Nix devShell / CI shell
└── pnpm-workspace.yaml</details>
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.22.1)</summary>
[warning] 7-7: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.claude/CLAUDE.md around lines 7 - 15, The fenced code block displaying the
directory structure (starting with the . symbol and containing the subtrack/,
docs/, .agents/, .claude/, flake.nix, and pnpm-workspace.yaml entries) is
missing a language identifier tag, which violates the MD040 rule. Add "text" as
the language identifier immediately after the opening triple backticks (```) of
this code fence to properly indicate the code block type and satisfy the
markdown linting requirement.
</details>
<!-- fingerprinting:phantom:poseidon:hawk -->
<!-- cr-comment:v1:13f2f66e4e184c01f74518d6 -->
_Source: Linters/SAST tools_
<!-- This is an auto-generated comment by CodeRabbit -->
| - name: Spell check with typos | ||
| if: runner.os == 'Linux' | ||
| uses: crate-ci/typos@v1.47.2 | ||
| with: | ||
| files: subtrack/ | ||
| config: typos.toml |
There was a problem hiding this comment.
Pin GitHub Action to a commit SHA.
Line 82 uses crate-ci/typos@v1.47.2, which is not digest-pinned. Tag references are mutable and weaken CI supply-chain guarantees; pin this action to a full commit SHA.
Suggested hardening
- - name: Spell check with typos
- if: runner.os == 'Linux'
- uses: crate-ci/typos@v1.47.2
+ - name: Spell check with typos
+ if: runner.os == 'Linux'
+ uses: crate-ci/typos@<full_commit_sha>
with:
files: subtrack/
config: typos.toml🧰 Tools
🪛 zizmor (1.25.2)
[error] 82-82: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/app-ci.yml around lines 80 - 85, The GitHub Action
reference for crate-ci/typos in the "Spell check with typos" step uses a mutable
version tag reference (v1.47.2) instead of being pinned to a specific commit
SHA. Replace the version tag reference in the uses field with the full commit
SHA of the v1.47.2 release to strengthen supply-chain security and ensure the
exact version of the action is always used, preventing unexpected changes from
tag mutations.
Source: Linters/SAST tools
| "location": "file:///home/nazozokc/ghq/github.com/nazozokc/subtrack/.agents/skills/subtrack-rules/SKILL.md" | ||
| }, | ||
| { | ||
| "name": "subtrack-commit", | ||
| "description": "When committing changes to subtrack, creating PRs, or pushing to remote", | ||
| "location": "file:///home/nazozokc/ghq/github.com/nazozokc/subtrack/.agents/skills/subtrack-commit/SKILL.md" |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In OpenCode opencode.jsonc, what is the recommended portable format for skills[].locationwhen skill files live in the same repository? Are absolutefile:///home/... paths discouraged?
💡 Result:
In OpenCode, when defining custom skill locations via the skills.paths array in opencode.jsonc, the recommended portable format for paths is to use relative paths (e.g., ./custom/skills) or home-relative paths (e.g., ~/my-skills) rather than absolute paths [1][2]. While the native OpenCode Skill.Service is capable of processing absolute paths, they are generally discouraged for project-level configuration because they break portability across different development environments and machines [3][2]. Native resolution behavior in OpenCode is as follows: - Home-relative paths starting with ~/ are expanded using the user's home directory [3][2]. - Relative paths are resolved against the project root (or the directory containing the configuration file, depending on specific version implementation details) [3][2]. - Absolute paths (e.g., /home/... or C:\Users\...) are supported but remain non-portable [3][1]. To ensure your configuration works for all team members, favor paths relative to the repository root [1].
Citations:
- 1: [FEATURE]: Add configurable skill paths anomalyco/opencode#14370
- 2: feat(skill-loader): support skills.paths config for plugin skill discovery code-yeongyu/oh-my-openagent#2840
- 3: https://github.com/sst/opencode/blob/c7b35342/packages/opencode/src/skill/skill.ts
Use repository-relative paths for skill locations instead of absolute machine-specific paths
Lines 7 and 12 hard-code /home/nazozokc/... paths, which will fail for other developers and CI environments. Replace with paths relative to the repository root (e.g., ./.agents/skills/subtrack-rules/SKILL.md) or home-relative paths (e.g., ~/.agents/...).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@opencode.jsonc` around lines 7 - 12, In the opencode.jsonc file, replace the
absolute machine-specific paths in the location fields for the "subtrack-rules"
and "subtrack-commit" skills. Instead of using the full absolute path starting
with /home/nazozokc/ghq/github.com/nazozokc/subtrack/, use repository-relative
paths starting with ./.agents/skills/ (e.g.,
./.agents/skills/subtrack-rules/SKILL.md and
./.agents/skills/subtrack-commit/SKILL.md) to ensure the configuration works
across different machines and CI environments.
| price: Math.round( | ||
| convertPrice(sub.price, sub.currency, options.currency!, rates.rates), | ||
| ), | ||
| currency: options.currency! as Currency, | ||
| })) |
There was a problem hiding this comment.
Normalize smallest-unit prices before FX conversion.
Lines 238-242 convert sub.price directly with whole-currency FX rates. Under the commands/db contract (smallest-unit integers), this mis-scales converted amounts (e.g., USD cents treated as USD units).
🛠️ Proposed direction
+const minorUnitScale: Record<Currency, number> = {
+ JPY: 1,
+ USD: 100,
+ EUR: 100,
+ GBP: 100,
+ AUD: 100,
+ CAD: 100,
+ KRW: 1,
+ CNY: 100,
+ SGD: 100,
+ HKD: 100,
+}
+
list = list.map((sub) => ({
...sub,
- price: Math.round(
- convertPrice(sub.price, sub.currency, options.currency!, rates.rates),
- ),
+ price: Math.round(
+ convertPrice(
+ sub.price / minorUnitScale[sub.currency],
+ sub.currency,
+ options.currency! as Currency,
+ rates.rates,
+ ) * minorUnitScale[options.currency! as Currency],
+ ),
currency: options.currency! as Currency,
}))As per coding guidelines, subtrack/src/{db,commands}.ts should represent prices as integers using the smallest unit (JPY with no decimal, USD in cents).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@subtrack/src/commands.ts` around lines 238 - 242, The price conversion in the
map function that processes subscriptions is not accounting for the
smallest-unit integer representation required by the contract. Before passing
sub.price to the convertPrice function, normalize it from smallest-unit integers
to whole currency units by dividing by the appropriate decimal places for
sub.currency. After convertPrice returns the converted amount in whole units,
normalize it back to smallest-unit integers by multiplying by the decimal places
of the target currency (options.currency). Apply Math.round to the final result
to ensure an integer value is stored in the price field.
Source: Coding guidelines
| export async function fetchFxRates(): Promise<FxRates> { | ||
| const res = await fetch("https://open.er-api.com/v6/latest/USD") | ||
| if (!res.ok) { | ||
| throw new Error(`FX API responded with ${res.status}`) | ||
| } | ||
| return res.json() as Promise<FxRates> | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify current fetch usage and whether timeout signal is present
rg -nP --type=ts 'fetch\s*\(' subtrack/src/display.ts -C3
rg -nP --type=ts 'signal\s*:' subtrack/src/display.ts -C2Repository: nazozokc/subtrack
Length of output: 289
Add a timeout to the FX-rate HTTP call.
Line 18 performs an external network call with no timeout, so export --currency can block indefinitely on network stalls.
⚙️ Proposed fix
export async function fetchFxRates(): Promise<FxRates> {
- const res = await fetch("https://open.er-api.com/v6/latest/USD")
+ const controller = new AbortController()
+ const timeout = setTimeout(() => controller.abort(), 10_000)
+ const res = await fetch("https://open.er-api.com/v6/latest/USD", {
+ signal: controller.signal,
+ }).finally(() => clearTimeout(timeout))
if (!res.ok) {
throw new Error(`FX API responded with ${res.status}`)
}
return res.json() as Promise<FxRates>
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@subtrack/src/display.ts` around lines 17 - 23, The fetchFxRates function
performs an external network call without a timeout, which can cause indefinite
blocking on network stalls. Add a timeout mechanism using AbortController to the
fetch call. Create an AbortController instance, set a timeout (e.g., 5 seconds)
that aborts the controller, pass the abort signal to the fetch request via the
options parameter, and handle the AbortError appropriately in the error handling
logic.
| const tags = s.tags.map((t) => escapeCsv(t)).join(";") | ||
| const name = escapeCsv(s.name) | ||
| return `${name},${s.cycle},${tags},${s.price},${s.currency}` |
There was a problem hiding this comment.
Escape the full tags CSV field after joining.
Line 288 escapes each tag individually, then concatenates them. If a tag contains comma/quote/newline, the resulting field can become invalid CSV. Join first, then escape once for the whole field.
🛠️ Proposed fix
- const tags = s.tags.map((t) => escapeCsv(t)).join(";")
+ const tags = escapeCsv(s.tags.join(";"))
const name = escapeCsv(s.name)
return `${name},${s.cycle},${tags},${s.price},${s.currency}`📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const tags = s.tags.map((t) => escapeCsv(t)).join(";") | |
| const name = escapeCsv(s.name) | |
| return `${name},${s.cycle},${tags},${s.price},${s.currency}` | |
| const tags = escapeCsv(s.tags.join(";")) | |
| const name = escapeCsv(s.name) | |
| return `${name},${s.cycle},${tags},${s.price},${s.currency}` |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@subtrack/src/display.ts` around lines 288 - 290, The tags field is being
escaped at the individual tag level before joining, but the entire joined tags
string needs to be escaped as a complete CSV field to properly handle special
CSV characters. Modify the code around line 288 to first join the raw tags with
semicolons, then apply escapeCsv to the entire joined result as a single field
rather than escaping each tag individually before joining.
| const tags = s.tags.join(", ") || "-" | ||
| const price = formatPrice(s.price, s.currency) | ||
| return `| ${s.name} | ${s.cycle} | ${tags} | ${price} | ${s.currency} |` | ||
| }) |
There was a problem hiding this comment.
Escape Markdown table cell content before interpolation.
Lines 302-305 inject raw name/tags; values containing | or newlines will break table structure.
🛠️ Proposed fix
+function escapeMdCell(value: string): string {
+ return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ")
+}
+
export function exportMd(subs: SharedArgs[]): string {
const header = "| name | cycle | tags | price | currency |"
const separator = "| --- | --- | --- | --- | --- |"
const rows = subs.map((s) => {
- const tags = s.tags.join(", ") || "-"
+ const tags = escapeMdCell(s.tags.join(", ") || "-")
+ const name = escapeMdCell(s.name)
const price = formatPrice(s.price, s.currency)
- return `| ${s.name} | ${s.cycle} | ${tags} | ${price} | ${s.currency} |`
+ return `| ${name} | ${s.cycle} | ${tags} | ${price} | ${s.currency} |`
})
return [header, separator, ...rows].join("\n")
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const tags = s.tags.join(", ") || "-" | |
| const price = formatPrice(s.price, s.currency) | |
| return `| ${s.name} | ${s.cycle} | ${tags} | ${price} | ${s.currency} |` | |
| }) | |
| function escapeMdCell(value: string): string { | |
| return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ") | |
| } | |
| export function exportMd(subs: SharedArgs[]): string { | |
| const header = "| name | cycle | tags | price | currency |" | |
| const separator = "| --- | --- | --- | --- | --- |" | |
| const rows = subs.map((s) => { | |
| const tags = escapeMdCell(s.tags.join(", ") || "-") | |
| const name = escapeMdCell(s.name) | |
| const price = formatPrice(s.price, s.currency) | |
| return `| ${name} | ${s.cycle} | ${tags} | ${price} | ${s.currency} |` | |
| }) | |
| return [header, separator, ...rows].join("\n") | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@subtrack/src/display.ts` around lines 302 - 305, The Markdown table
construction in the anonymous function return statement is injecting raw values
like s.name, s.cycle, tags, price, and s.currency without escaping special
characters. Values containing pipe characters (|) or newlines will break the
table structure. Before interpolating these values into the template string,
escape pipe characters and newlines by replacing them with safe alternatives
(for example, pipe characters can be replaced with a space or
backslash-escaped). Apply the escaping to all values being interpolated in the
return statement to ensure table integrity.
- remove tsc --noEmit from CI (pre-existing type errors in sql.js code) - fix @inquirer/input hint removal in v8 (show existing tags in message instead)
Summary
AI agent configuration, CI improvements, and new export commands for subtrack.
Changes
AI Agent Configs
.github/copilot-instructions.mdfor GitHub Copilot (Codex).claude/CLAUDE.mdand symlink.claude/skills→.agents/skillsfor Claude Codeopencode.jsoncfor OpenCodesubtrack/CLAUDE.md(better-sqlite3→sql.js)subtrack/AGENTS.md(symlink toCLAUDE.md, auto-synced)CI Improvements
tsc --noEmit)pnpm auditstepexport csvandexport md--provenanceflag to npm publishCSV Export (
subtrack export csv)--tagsand--currencyoptionsMarkdown Export (
subtrack export md)--tagsand--currencyoptionsTesting
Summary by CodeRabbit
New Features
Chores