Skip to content

fix(cli): accept canonical Forgejo pull request URLs - #36

Merged
kunchenguid merged 2 commits into
kunchenguid:mainfrom
escidmore:fm/tasks-axi-forgejo-pr-links
Aug 9, 2026
Merged

kunchenguid merged 2 commits into
kunchenguid:mainfrom
escidmore:fm/tasks-axi-forgejo-pr-links

Conversation

@escidmore

@escidmore escidmore commented Aug 8, 2026 •

Copy link
Copy Markdown
Contributor

Intent

Accept canonical Forgejo pull-request URLs as typed PR artifacts everywhere tasks-axi accepts PR links (fixes upstream issue #19: done --pr rejected any non-GitHub pull request URL). One authoritative strict PR URL seam - isPrUrl in src/pr-url.ts - shared by ordinary task link derivation (deriveLinks), done/add --pr validation, markdown task links, and public-followup pr_url deliverables. Preserve canonical GitHub https://github.com///pull/; add canonical Forgejo https://///pulls/. Strictly reject issue URLs, singular/plural route confusion, zero and leading-zero numbers, trailing slash, query/fragment, whitespace/control bytes, userinfo, ports, encoded separators, and malformed host/owner/repo segments; non-canonical PR-ish URLs in prose derive as doc links, never pr. Byte-exact rendering preserved; accurate help/docs (DONE_HELP Forgejo example, shared PR_URL_EXPECTED error text, README); TOP_HELP unchanged so the generated skills/tasks-axi/SKILL.md is intentionally untouched. Public-followup pr-merged pr_url uses the same seam under the same privacy-safe contract; the previous looser regex plus userinfo check was deliberately replaced by the strictly tighter isPrUrl. Scope is strictly typed links: no remote tracker backends, no API calls, no merge operations, no generalized forge client. This branch already passed a full pipeline run (PR #36, CI green); the new head applies two supervisor-decided review findings from that run: (1) typed-link whitespace normalization - the --pr value is now validated untrimmed (crud.ts requireTypedLinkUrl skips trim for pr kind; markdown.ts normalizeTypedLink validates the original url for pr kind), so whitespace-padded input is rejected consistently instead of silently normalized, with rejection tests at both the done --pr command layer and the store addLinks layer; (2) the literal NUL byte in test/pr-url.test.ts is now a unicode source escape so git treats the file as text, plus a genuine embedded-space rejection case. A third finding (strict-terminal-newline, claiming a regex dollar anchor matches before a trailing newline) was approved as factually incorrect for JavaScript: without the m flag the anchor matches only at end of input, and a trailing-newline rejection test passes. Update the existing PR #36; do not publish a package or merge the PR.

What Changed

  • Add one strict PR URL classifier for canonical GitHub and Forgejo URLs, shared by prose link derivation, typed --pr values, markdown task links, and public-followup receipts.
  • Reject whitespace-padded and other noncanonical PR-like inputs while classifying prose near-misses as document links.
  • Document Forgejo usage and add regression coverage across URL, grammar, store, command, and public-followup paths.

Risk Assessment

✅ Low: The change is well-bounded, centralizes strict PR URL classification at the required shared seam, covers every specified caller, and introduces no material source or intent-conformance risks.

Testing

After correcting the missing-pnpm PATH setup with Corepack and one script-forwarding mistake, the focused validator, Markdown, state-command, and public-followup tests passed; real CLI evidence confirmed Forgejo acceptance, strict padded-input rejection, near-miss doc classification, persisted state, and updated help, then the temporary dependency directory was removed and the worktree confirmed unchanged. This is CLI-only, so screenshots were not applicable.

Evidence: Forgejo CLI transcript
\n$ tasks-axi add forgejo-demo --title Forgejo typed PR --file /var/folders/zf/93mvgfyd5_d7l2mz6zw_0fbw0000gn/T/no-mistakes-evidence/01KZG5JYKTSJBKW6BM0B565Q2S/forgejo-cli-backlog.md --json
{
  "ok": true,
  "action": "add",
  "task": {
    "id": "forgejo-demo",
    "title": "Forgejo typed PR",
    "state": "queued",
    "kind": null,
    "repo": null,
    "priority": null,
    "created": "2026-08-08",
    "closed": null,
    "deps": [],
    "hold": null,
    "links": [],
    "body": null,
    "blocked": false,
    "blocked_by": [],
    "held": false
  }
}
\n$ tasks-axi done forgejo-demo --pr https://forgejo.example.com/eve/tasks/pulls/39 --no-prune --file /var/folders/zf/93mvgfyd5_d7l2mz6zw_0fbw0000gn/T/no-mistakes-evidence/01KZG5JYKTSJBKW6BM0B565Q2S/forgejo-cli-backlog.md --json
{
  "ok": true,
  "action": "done",
  "pruned": 0,
  "task": {
    "id": "forgejo-demo",
    "title": "Forgejo typed PR https://forgejo.example.com/eve/tasks/pulls/39",
    "state": "done",
    "kind": null,
    "repo": null,
    "priority": null,
    "created": "2026-08-08",
    "closed": "2026-08-08",
    "deps": [],
    "hold": null,
    "links": [
      {
        "kind": "pr",
        "url": "https://forgejo.example.com/eve/tasks/pulls/39"
      }
    ],
    "body": null,
    "blocked": false,
    "blocked_by": [],
    "held": false
  }
}
\n$ tasks-axi show forgejo-demo --file /var/folders/zf/93mvgfyd5_d7l2mz6zw_0fbw0000gn/T/no-mistakes-evidence/01KZG5JYKTSJBKW6BM0B565Q2S/forgejo-cli-backlog.md
task:
  id: forgejo-demo
  title: "Forgejo typed PR https://forgejo.example.com/eve/tasks/pulls/39"
  state: done
  blocked: no
  blocked_by: none
  held: no
  hold_reason: "-"
  hold_kind: "-"
  hold_until: "-"
  kind: task
  repo: "-"
  priority: "-"
  created: "-"
  closed: 2026-08-08
  deps: none
  links: "pr:https://forgejo.example.com/eve/tasks/pulls/39"
  body: ""
\n$ tasks-axi add padded-demo --title Reject padded PR --file /var/folders/zf/93mvgfyd5_d7l2mz6zw_0fbw0000gn/T/no-mistakes-evidence/01KZG5JYKTSJBKW6BM0B565Q2S/forgejo-cli-backlog.md --json
{
  "ok": true,
  "action": "add",
  "task": {
    "id": "padded-demo",
    "title": "Reject padded PR",
    "state": "queued",
    "kind": null,
    "repo": null,
    "priority": null,
    "created": "2026-08-08",
    "closed": null,
    "deps": [],
    "hold": null,
    "links": [],
    "body": null,
    "blocked": false,
    "blocked_by": [],
    "held": false
  }
}
\n$ tasks-axi done padded-demo --pr " https://forgejo.example.com/eve/tasks/pulls/40 " --no-prune --file /var/folders/zf/93mvgfyd5_d7l2mz6zw_0fbw0000gn/T/no-mistakes-evidence/01KZG5JYKTSJBKW6BM0B565Q2S/forgejo-cli-backlog.md --json
error: "Task pr link must be a canonical pull request URL: https://github.com/<owner>/<repo>/pull/<n> (GitHub) or https://<host>/<owner>/<repo>/pulls/<n> (Forgejo)"
code: VALIDATION_ERROR
exit: 2
\n$ tasks-axi add near-miss-demo --title Review https://forgejo.example.com/eve/tasks/pull/41 --file /var/folders/zf/93mvgfyd5_d7l2mz6zw_0fbw0000gn/T/no-mistakes-evidence/01KZG5JYKTSJBKW6BM0B565Q2S/forgejo-cli-backlog.md --json
{
  "ok": true,
  "action": "add",
  "task": {
    "id": "near-miss-demo",
    "title": "Review https://forgejo.example.com/eve/tasks/pull/41",
    "state": "queued",
    "kind": null,
    "repo": null,
    "priority": null,
    "created": "2026-08-08",
    "closed": null,
    "deps": [],
    "hold": null,
    "links": [
      {
        "kind": "doc",
        "url": "https://forgejo.example.com/eve/tasks/pull/41"
      }
    ],
    "body": null,
    "blocked": false,
    "blocked_by": [],
    "held": false
  }
}
\n$ tasks-axi show near-miss-demo --file /var/folders/zf/93mvgfyd5_d7l2mz6zw_0fbw0000gn/T/no-mistakes-evidence/01KZG5JYKTSJBKW6BM0B565Q2S/forgejo-cli-backlog.md
task:
  id: near-miss-demo
  title: "Review https://forgejo.example.com/eve/tasks/pull/41"
  state: queued
  blocked: no
  blocked_by: none
  held: no
  hold_reason: "-"
  hold_kind: "-"
  hold_until: "-"
  kind: task
  repo: "-"
  priority: "-"
  created: 2026-08-08
  closed: "-"
  deps: none
  links: "doc:https://forgejo.example.com/eve/tasks/pull/41"
  body: ""
\n$ persisted markdown
# Backlog

## In flight
## Queued
- [ ] padded-demo - Reject padded PR (since 2026-08-08)
- [ ] near-miss-demo - Review https://forgejo.example.com/eve/tasks/pull/41 (since 2026-08-08)
## Done
- [x] forgejo-demo - Forgejo typed PR https://forgejo.example.com/eve/tasks/pulls/39 (merged 2026-08-08)
Evidence: Persisted Markdown backlog
# Backlog

## In flight
## Queued
- [ ] padded-demo - Reject padded PR (since 2026-08-08)
- [ ] near-miss-demo - Review https://forgejo.example.com/eve/tasks/pull/41 (since 2026-08-08)
## Done
- [x] forgejo-demo - Forgejo typed PR https://forgejo.example.com/eve/tasks/pulls/39 (merged 2026-08-08)
Evidence: DONE_HELP Forgejo example
tasks-axi done fj-task-q1 --pr https://forgejo.example.com/o/r/pulls/39

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • rtk git rev-parse HEAD
  • rtk pnpm exec vitest run test/pr-url.test.ts test/backends/markdown-grammar.test.ts test/backends/markdown.test.ts test/commands/state.test.ts test/commands/public-followup.test.ts (pnpm was unavailable on PATH)
  • rtk corepack pnpm --version
  • rtk corepack pnpm install --frozen-lockfile
  • rtk corepack pnpm exec vitest run test/pr-url.test.ts test/backends/markdown-grammar.test.ts test/backends/markdown.test.ts test/commands/state.test.ts test/commands/public-followup.test.ts
  • rtk corepack pnpm dev -- done --help (incorrect script forwarding, then corrected)
  • rtk corepack pnpm exec tsx bin/tasks-axi.ts done --help
  • rtk corepack pnpm exec tsx bin/tasks-axi.ts show --help
  • CLI evidence flow: add a task, complete it using --pr https://forgejo.example.com/eve/tasks/pulls/39, and inspect the resulting typed pr link and persisted Markdown
  • CLI rejection flow: pass whitespace-padded Forgejo --pr input and verify VALIDATION_ERROR with exit 2
  • CLI derivation flow: add prose containing https://forgejo.example.com/eve/tasks/pull/41 and verify it appears as a doc link, never pr
  • rtk rm -rf /Users/host/.no-mistakes/worktrees/45059bee3575/01KZG5JYKTSJBKW6BM0B565Q2S/node_modules
  • rtk git status --short
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

One classification seam (isPrUrl in src/pr-url.ts) now decides what
counts as a PR URL for prose link derivation, done/add --pr validation,
and public-followup pr_url deliverables: canonical GitHub
https://github.com/<owner>/<repo>/pull/<n> or Forgejo
https://<host>/<owner>/<repo>/pulls/<n> with a positive, no-leading-zero
number. Near misses (issue routes, singular/plural route confusion,
trailing slash, query/fragment, whitespace, userinfo, ports, encoded
separators, malformed segments) are rejected as --pr / pr_url values and
derive as doc links, never pr.

Fixes kunchenguid#19
Review follow-ups from pipeline run 01KZFA73D662DCSJ4HVWKW21QX: --pr values
and pr-kind addLinks are validated before any trim, so whitespace-padded
input is rejected instead of normalized. The literal NUL byte in
test/pr-url.test.ts is now written as a unicode source escape so git
treats the file as text; an embedded-space rejection case is added
alongside it.
@escidmore escidmore changed the title fix: accept canonical Forgejo pull request URLs fix(cli): accept canonical Forgejo pull request URLs Aug 8, 2026
@kunchenguid
kunchenguid merged commit 9a86c7c into kunchenguid:main Aug 9, 2026
6 checks passed
@kunchenguid

Copy link
Copy Markdown
Owner

Thanks @escidmore - merged! Really appreciate the contribution.

yjuyjuy added a commit to yjuyjuy/tasks-axi that referenced this pull request Aug 13, 2026
* fix(cli): speed up standalone version queries (kunchenguid#34)

* perf(cli): answer --version through the axi-sdk-js fast path

Extract the package-version helper out of the heavy `src/cli.ts` graph into a
leaf `src/version.ts` (node builtins only), and rewrite `bin/tasks-axi.ts` to
answer a bare `-v`/`-V`/`--version` via `axi-sdk-js/fast-path`, dynamically
importing the command graph only for everything else. Bumps axi-sdk-js to
^0.1.10 for the `./fast-path` subpath export.

Version output is byte-identical and all other argv shapes still route through
`runAxiCli` unchanged. Guarded by a deterministic ESM loader module trace with
a negative control plus flag parity; no wall-clock assertion in CI.

* no-mistakes(document): Confirm fast-path docs and lint cleanliness

* no-mistakes: apply CI fixes

* chore(main): release tasks-axi 0.2.5 (kunchenguid#35)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(cli): accept canonical Forgejo pull request URLs (kunchenguid#36)

* fix: accept canonical Forgejo pull request URLs as typed PR links

One classification seam (isPrUrl in src/pr-url.ts) now decides what
counts as a PR URL for prose link derivation, done/add --pr validation,
and public-followup pr_url deliverables: canonical GitHub
https://github.com/<owner>/<repo>/pull/<n> or Forgejo
https://<host>/<owner>/<repo>/pulls/<n> with a positive, no-leading-zero
number. Near misses (issue routes, singular/plural route confusion,
trailing slash, query/fragment, whitespace, userinfo, ports, encoded
separators, malformed segments) are rejected as --pr / pr_url values and
derive as doc links, never pr.

Fixes kunchenguid#19

* fix: validate pr links against the untrimmed input

Review follow-ups from pipeline run 01KZFA73D662DCSJ4HVWKW21QX: --pr values
and pr-kind addLinks are validated before any trim, so whitespace-padded
input is rejected instead of normalized. The literal NUL byte in
test/pr-url.test.ts is now written as a unicode source escape so git
treats the file as text; an embedded-space rejection case is added
alongside it.

* chore: remove committed no-mistakes evidence (now on orphan branch) (kunchenguid#39)

* chore: gitignore no-mistakes evidence dir (contributor safety) (kunchenguid#41)

---------

Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Evelyn Scidmore <13389701+escidmore@users.noreply.github.com>
Co-authored-by: Chris Yuan <cyuan@hyfin.app>
yjuyjuy added a commit to yjuyjuy/tasks-axi that referenced this pull request Aug 17, 2026
* fix(cli): speed up standalone version queries (kunchenguid#34)

* perf(cli): answer --version through the axi-sdk-js fast path

Extract the package-version helper out of the heavy `src/cli.ts` graph into a
leaf `src/version.ts` (node builtins only), and rewrite `bin/tasks-axi.ts` to
answer a bare `-v`/`-V`/`--version` via `axi-sdk-js/fast-path`, dynamically
importing the command graph only for everything else. Bumps axi-sdk-js to
^0.1.10 for the `./fast-path` subpath export.

Version output is byte-identical and all other argv shapes still route through
`runAxiCli` unchanged. Guarded by a deterministic ESM loader module trace with
a negative control plus flag parity; no wall-clock assertion in CI.

* no-mistakes(document): Confirm fast-path docs and lint cleanliness

* no-mistakes: apply CI fixes

* chore(main): release tasks-axi 0.2.5 (kunchenguid#35)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(cli): accept canonical Forgejo pull request URLs (kunchenguid#36)

* fix: accept canonical Forgejo pull request URLs as typed PR links

One classification seam (isPrUrl in src/pr-url.ts) now decides what
counts as a PR URL for prose link derivation, done/add --pr validation,
and public-followup pr_url deliverables: canonical GitHub
https://github.com/<owner>/<repo>/pull/<n> or Forgejo
https://<host>/<owner>/<repo>/pulls/<n> with a positive, no-leading-zero
number. Near misses (issue routes, singular/plural route confusion,
trailing slash, query/fragment, whitespace, userinfo, ports, encoded
separators, malformed segments) are rejected as --pr / pr_url values and
derive as doc links, never pr.

Fixes kunchenguid#19

* fix: validate pr links against the untrimmed input

Review follow-ups from pipeline run 01KZFA73D662DCSJ4HVWKW21QX: --pr values
and pr-kind addLinks are validated before any trim, so whitespace-padded
input is rejected instead of normalized. The literal NUL byte in
test/pr-url.test.ts is now written as a unicode source escape so git
treats the file as text; an embedded-space rejection case is added
alongside it.

* chore: remove committed no-mistakes evidence (now on orphan branch) (kunchenguid#39)

* chore: gitignore no-mistakes evidence dir (contributor safety) (kunchenguid#41)

---------

Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Evelyn Scidmore <13389701+escidmore@users.noreply.github.com>
Co-authored-by: Chris Yuan <cyuan@hyfin.app>
yjuyjuy added a commit to yjuyjuy/tasks-axi that referenced this pull request Aug 24, 2026
…e no-mistakes gate to the shared action (#6)

* fix(cli): speed up standalone version queries (kunchenguid#34)

* perf(cli): answer --version through the axi-sdk-js fast path

Extract the package-version helper out of the heavy `src/cli.ts` graph into a
leaf `src/version.ts` (node builtins only), and rewrite `bin/tasks-axi.ts` to
answer a bare `-v`/`-V`/`--version` via `axi-sdk-js/fast-path`, dynamically
importing the command graph only for everything else. Bumps axi-sdk-js to
^0.1.10 for the `./fast-path` subpath export.

Version output is byte-identical and all other argv shapes still route through
`runAxiCli` unchanged. Guarded by a deterministic ESM loader module trace with
a negative control plus flag parity; no wall-clock assertion in CI.

* no-mistakes(document): Confirm fast-path docs and lint cleanliness

* no-mistakes: apply CI fixes

* chore(main): release tasks-axi 0.2.5 (kunchenguid#35)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(cli): accept canonical Forgejo pull request URLs (kunchenguid#36)

* fix: accept canonical Forgejo pull request URLs as typed PR links

One classification seam (isPrUrl in src/pr-url.ts) now decides what
counts as a PR URL for prose link derivation, done/add --pr validation,
and public-followup pr_url deliverables: canonical GitHub
https://github.com/<owner>/<repo>/pull/<n> or Forgejo
https://<host>/<owner>/<repo>/pulls/<n> with a positive, no-leading-zero
number. Near misses (issue routes, singular/plural route confusion,
trailing slash, query/fragment, whitespace, userinfo, ports, encoded
separators, malformed segments) are rejected as --pr / pr_url values and
derive as doc links, never pr.

Fixes kunchenguid#19

* fix: validate pr links against the untrimmed input

Review follow-ups from pipeline run 01KZFA73D662DCSJ4HVWKW21QX: --pr values
and pr-kind addLinks are validated before any trim, so whitespace-padded
input is rejected instead of normalized. The literal NUL byte in
test/pr-url.test.ts is now written as a unicode source escape so git
treats the file as text; an embedded-space rejection case is added
alongside it.

* chore: remove committed no-mistakes evidence (now on orphan branch) (kunchenguid#39)

* chore: gitignore no-mistakes evidence dir (contributor safety) (kunchenguid#41)

* chore(agents): use @AGENTS.md import instead of CLAUDE.md symlink (kunchenguid#42)

Co-authored-by: Kun Chen <kun-1@kunchenguid.com>

* ci: require no-mistakes pipeline attestation in the gate (kunchenguid#45)

* ci: require no-mistakes pipeline attestation in the gate

* test: run the no-mistakes gate script on POSIX legs only

* ci: bind the no-mistakes attestation to the current PR head (kunchenguid#46)

* ci: migrate the no-mistakes gate to the shared composite action (kunchenguid#47)

Replace the inline gate `run:` block in
.github/workflows/no-mistakes-required.yml with a thin caller of
kunchenguid/no-mistakes/.github/actions/require-no-mistakes, pinned to an
immutable commit SHA. Enforcement logic and its tests now live upstream, so
this repository no longer carries a hand-copied script that can drift from
its siblings.

Drop `synchronize` from the pull_request trigger: the verdict is a pure
function of the PR body, and the pipeline pushes before it writes the
Pipeline section, so a push-triggered run pinned a failure to a head whose
body the same run was about to fix. This repo's ruleset is advisory with no
required status check, so dropping the trigger cannot wedge a merge.

Remove test/workflows/no-mistakes-gate.test.ts, which extracted and executed
the now-absent inline block, and point AGENTS.md at the shared action.

* fix: make the generated skill defer to live CLI guidance (kunchenguid#48)

* fix(skill): shrink SKILL.md to a CLI-deferring stub

Installed skills go stale when the npm package is bumped. Keep only
identity frontmatter plus pointers to live CLI help so regeneration
cannot re-inflate baked command docs.

Co-authored-by: Cursor <cursoragent@cursor.com>

* no-mistakes(review): Align skill documentation with minimal generator contract

* no-mistakes(document): Consolidate generated skill documentation

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

* no-mistakes: apply CI fixes

---------

Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Evelyn Scidmore <13389701+escidmore@users.noreply.github.com>
Co-authored-by: Kun Chen <kun-1@kunchenguid.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Chris Yuan <cyuan@hyfin.app>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants