Commit Graph

34 Commits

Author SHA1 Message Date
6c31eb9e62 test: split the packaging tier and parameterize its installed binary (task 0036)
All checks were successful
CI / test (pull_request) Successful in 53s
CI / test (push) Successful in 52s
The packaging tier held two kinds of assertion joined only by an
expensive shared setup: the shape of the packed tarball and its
manifest, and the behaviour of the resulting installed binary. Split
them, and teach the second to take the binary it drives from
GITEA_AXI_INSTALLED_BIN.

When that variable names an existing binary the tier drives it and skips
pack-and-install entirely; unset, it packs and installs exactly as
before. The installed-binary facet becomes one seam with two callers —
the npm distribution path today, the Nix installation path in task 0038
— so the two cannot drift apart in what they guarantee about an
installed gitea-axi. Nothing in it may assert on how the binary came to
exist, since store paths, wrapper internals, and the arrangement of the
installed tree are implementation detail of the installation method.

The tarball assertions stay npm-only: no other distribution method
produces a tarball or a packed manifest.
2026-07-19 22:28:25 -04:00
5422f49f38 feat(search): guide a 0-result search and fill the single-match number
The next-step suggestion on `search issues`/`search prs` is now conditioned
on the in-repo match count. On a miss it pointed the agent at `view <number>`,
which is nonsensical when nothing matched; it now suggests the non-indexed
`issue list --state all` / `pr list --state all` fallback, which recovers from
both an over-narrow query and issue-indexer lag without naming the cause. On
exactly one match it fills the real number (`issue view 2`), applying AXI
Principle 9's single-id fill. Two or more matches keep the parameterized
placeholder.

Search stays a locator — it never auto-loads the detail even on a single
match; ADR 0017 records that decision (a deliberate narrowing of Principle 4)
and the CONTEXT.md search term is updated to match.
2026-07-19 10:17:14 -04:00
d56b1d0707 refactor(skill): steer find-then-act instead of open-ended discovery
The bundled skill's Discovery section told the agent to run the bare
dashboard and reach for --help proactively, and advertised overlapping
find-paths — inducing exploratory commands that made the gitea-axi arm the
most expensive of the benchmark's four. Replace it with a "find the target,
then act" section, name the non-obvious mutation flags so common edits do
not need --help, and drop the setup line and the over-tea/raw/git bullets
that only duplicated the description. A same-time A/B cut cost-equivalent
tokens ~10% and collapsed bare-dashboard use from 60% to 7% with no loss of
success.
2026-07-19 09:41:13 -04:00
dd58cd9dad fix(context): tolerate a trailing /api/v1 in the base URL
The client (gitea-js) appends /api/v1 to the base URL itself, so a
GITEA_AXI_API_URL that already carries it — a natural guess given the
variable's name — doubled the segment and failed as a spurious
REPO_NOT_FOUND. Normalize the base URL by stripping a trailing /api/v1
(and any trailing slashes) on both the env-URL and tea-login paths, so the
host base and the /api/v1 endpoint both resolve.
2026-07-19 09:41:13 -04:00
662ba82d71 feat: add --comments-file to pr review for inline comments (task 0035)
All checks were successful
CI / test (pull_request) Successful in 55s
CI / test (push) Successful in 53s
`pr review <n>` gains `--comments-file <path>`, a JSON array of inline
comments submitted with the review. Each entry is one of two exclusive
shapes: a new comment `{ path, line, body }` (mapped to `new_position`,
always the new side) or a reply `{ reply_to, body }`. A reply carries no
line or side — gitea-axi finds the target via the reviews-plus-comments
fan-out (there is no get-comment-by-id endpoint), reconstructs its anchor
from the target's own `diff_hunk`, and infers old/new side from it, so a
same-line post threads with the existing conversation. All entries map
onto the review-submission payload's `comments[]`; no new HTTP layer is
added. An unknown `reply_to` is a VALIDATION_ERROR raised before the POST,
and the submitted inline-comment count rides the action block.

The shared path-resolve-and-read behind --body-file and --comments-file is
extracted into src/flag-file.ts.
2026-07-18 16:11:26 -04:00
b6d247dd4e feat: surface inline-comment anchor fields on pr view --reviews (task 0034)
Each inline review comment under `pr view <n> --reviews` now renders its
`id` (the handle a reply targets), `resolved` (`yes`/`no`, from whether
Gitea populated the comment's `resolver`), and `diff_hunk`. The hunk is
structurally trimmed to its `@@` header line plus its last two lines by
default (hunks of three lines or fewer are left whole) and emitted
verbatim under `--full`, so the trim never touches the char-based body
truncation path. The raw `position`/`original_position` diff offsets stay
unsurfaced. The fields ride the existing reviews-plus-per-review-comments
fetch — no extra API calls.
2026-07-18 16:11:26 -04:00
a557745e59 test: update e2e tracer count-line assertions for task 0033
All checks were successful
CI / test (pull_request) Successful in 55s
CI / test (push) Successful in 56s
The state-aware count line from task 0033 (1166a48) renders
`count: N open of M total`, and the unit tests were updated to match, but
the three e2e tracer assertions still expected the old bare
`count: N of M total`. They are skipped without GITEA_AXI_E2E_URL, so the
staleness only surfaced in CI, where the e2e tier runs. Update them to the
state-qualified form the shipped code already produces — default `open`,
`--state closed` → `closed`. The code was correct; the tests were stale.
2026-07-17 22:52:13 -04:00
8653b89612 feat: show issue labels in issue view and add its --fields flag
`issue view` rendered state but never labels, and offered no way to add
them — so reading one issue's labels forced a detour through
`issue list --fields labels` and hunting the matching row. The benchmark
transcripts showed agents paying this round-trip on every labels/state
read.

Show labels by default in the detail view (a detail view should be
complete), and add a `--fields` flag mirroring `issue list` / `search`
to append assignees, closedAt, milestone, updatedAt, url on request.

Also strengthen SKILL.md against the two command-discovery round-trips
the transcripts exposed: name the required `search issues` / `search prs`
subcommand form (a bare `search "<query>"` is invalid), and point agents
straight at `issue view <n>` for a single issue's fields.

Verified live: read-issue-labels-and-state dropped from 10 turns to 4
(cache-read ~3.3x lower), the transcript reduced to three clean commands
with the search-help and issue-list round-trips gone.
2026-07-17 18:59:16 -04:00
1166a48130 feat: name filtered state in issue list count line (task 0033)
Some checks failed
CI / test (pull_request) Failing after 54s
Make the `issue list` count line name the state it filtered on, so the
answer to "how many issues are open?" is present on the summary line
rather than only inferable from each row. The count line now renders
`count: 5 open of 5 total`; the command composes the state into a generic
optional qualifier while `formatCountLine` stays state-agnostic, so
`pr list`, `search`, and `dashboard` are unaffected. `--state all` imposes
no narrowing and stays unqualified.

The wording is chosen so an agent quoting the summary lands on a phrase the
benchmark read-checker already accepts (`5 open`), closing the accuracy gap
this feature targets. Pairs with the report persistence in task 0032.
2026-07-17 10:09:50 -04:00
9bf8c85dc3 feat: add benchmark scaffold and result store (task 0022)
All checks were successful
CI / test (pull_request) Successful in 50s
CI / test (push) Successful in 50s
Lay the foundation the benchmark harness reads and writes: a bench/
directory (excluded from the published npm package), the immutable
result-record shape, and an append-only per-cell sample store.

- bench/result.ts: the ResultRecord shape — four token components,
  turns, duration, imputed cost, tagged pass/fail outcome, and the
  arm/task/tier/trial/timestamp tags. Arm and Tier are typed unions.
- bench/store.ts: append-only sample store, one JSONL file per cell at
  <root>/<arm>/<taskId>.jsonl; deepening a cell only ever adds samples.
- bench/README.md: harness working docs and benchmark vocabulary, kept
  out of the tool's domain glossary per the spec.
- Dedicated bench test tier (vitest.bench.config.ts, npm run test:bench)
  kept out of the fast tier; tsconfig typechecks bench.
- Packaging tier asserts bench/ never ships in the tarball.
2026-07-15 10:20:15 -04:00
b5955cd7b8 feat: truncate --fields body uniformly (task 0021)
All checks were successful
CI / test (pull_request) Successful in 49s
CI / test (push) Successful in 49s
Rule that the `body` extra field truncates at 500 chars like `issue view`,
resolving the spec's Principle 3 / Command Surface contradiction. Route the
`body` extractor through a new `truncatedBody()` FieldDef so `issue list`,
`issue create`, `pr list`, and `search` all present it exactly as the detail
views do, and add a `--full` flag to each to suppress truncation, keeping the
inline hint's "use --full" promise honest.
2026-07-14 12:23:24 -04:00
ed87f023cb feat: add npm publish readiness (task 0020)
All checks were successful
CI / test (pull_request) Successful in 52s
CI / test (push) Successful in 52s
Complete the distribution metadata and publish flow for the unscoped
`gitea-axi` package:

- add `repository`, `homepage`, and `bugs` to package.json
- add `publishConfig` (public access, npmjs registry) so `npm publish`
  needs no extra flags
- replace `prepublishOnly` with `prepack: npm run build`, so both
  `npm pack` and `npm publish` rebuild `dist/` first
- document the single-command flow in PUBLISHING.md
- add a packaging smoke-test tier (`test:pack`) that packs the real
  tarball, installs it globally, and drives the installed binary
  (`--help`, dashboard header, and `setup` finding the bundled skill)
2026-07-14 12:00:37 -04:00
be7226b321 feat: add setup skill/hooks and update shadow (task 0018)
All checks were successful
CI / test (pull_request) Successful in 52s
CI / test (push) Successful in 51s
Distribute gitea-axi's ambient context via explicit user actions (ADRs
0009, 0013), with no postinstall script:

- Bundle the Agent Skill markdown at skills/gitea-axi/SKILL.md (a
  minimal pointer, not a command reference) and ship it via package.json
  files.
- Add `setup`, which installs the skill into ~/.claude/skills/
  idempotently (installed/updated/unchanged).
- Add `setup hooks`, which registers a SessionStart hook running the
  bare dashboard for Claude Code, Codex, and OpenCode via the SDK's
  installSessionStartHooks(), updating managed entries in place.
- Shadow the SDK's built-in `update` so it fails with VALIDATION_ERROR
  and points at the npm update command, keeping the ten-code error list
  intact.

Integration tests drive all three at the CLI seam against a temporary
HOME; these commands make no Gitea API calls, so there is no live-Gitea
e2e case.
2026-07-14 11:26:56 -04:00
5b6a9b4917 feat: add the two-tier dashboard (task 0017)
All checks were successful
CI / test (pull_request) Successful in 47s
CI / test (push) Successful in 50s
Wire the bare `gitea-axi` home command to a two-tier repository
dashboard (ADR 0012): the short tier shows up to 3 open issues and 3
open PRs with the client-side `review` decision, and `--full` shows the
20-row open-PR table plus open issue counts grouped by label, aggregated
across every page of open issues up to the 1000-issue cap with a `+`
suffix when capped. Empty states render the raw `prs: 0 open` /
`issues: 0 open` strings; issue fetches pass `type=issues`; outside a
Gitea repo the dashboard errors with REPO_NOT_FOUND.

`paginate.ts` now reports whether pagination stopped at the cap, which
drives the label-count `+` suffix.
2026-07-14 11:01:07 -04:00
c2c5f1728c test: poll for indexer consistency in search e2e (task 0016)
All checks were successful
CI / test (pull_request) Successful in 45s
CI / test (push) Successful in 46s
Gitea's issue/PR search endpoint is backed by an asynchronous, eventually-
consistent indexer (bleve by default), so a PR opened moments earlier in the
e2e `beforeAll` was not yet searchable when `search prs` ran, and the live
assertion saw zero matches. Both live-search tests now poll the search via
`expect.poll` until the freshly-created content is indexed before asserting on
the exact locator-schema output. Record the eventual-consistency behaviour as
a project gotcha.
2026-07-14 10:09:51 -04:00
4c3dde26b4 feat: add search commands (task 0016)
Some checks failed
CI / test (pull_request) Failing after 45s
Add `search issues <query>` and `search prs <query>`, the full-text escape
hatch the forbidden `--search` flag on the list commands redirects to.

Both hit Gitea's cross-repo issue-search endpoint with the query, a `type`
of issues or pulls, and the owner param, then filter results to the current
repository client-side via each result's `repository` field — the endpoint
has no repo-name filter. The count line reports `count: N of T total` with
`T` from the filtered set (ADR 0005), never the endpoint's cross-repo
`X-Total-Count`.

The positional query is required (VALIDATION_ERROR if missing). Flags:
`--state` (default open), `--label` (comma-separated names passed straight
through as the API `labels` param), `--limit` (default 30), and `--fields`.
Default output is the locator schema (`number`, `title`, `state`, `author`,
`created`) under `issues:` / `pull_requests:` blocks matching the list
commands — search finds the number, `issue view` / `pr view` load the detail.

Covered by fixture-server tests for both types, cross-repo filtering, the
count rule, each flag, the empty state, and missing-query validation, plus
end-to-end tests against a live Gitea instance.
2026-07-14 09:55:20 -04:00
03937a8f6e test: add label e2e coverage and fixture-tier backfill (task 0015)
Some checks failed
CI / test (pull_request) Successful in 50s
CI / test (push) Has been cancelled
2026-07-14 07:35:45 -04:00
0bf914cbdd feat: add label commands (task 0015)
Some checks failed
CI / test (pull_request) Failing after 38s
2026-07-14 07:24:16 -04:00
3db6d421d4 feat: add pr diff and checkout (task 0014)
All checks were successful
CI / test (pull_request) Successful in 42s
Add the two PR commands that touch content and the local worktree:

- `pr diff <n>` fetches the raw diff from the `.diff` endpoint (forcing a
  text response, which the JSON-defaulting client would otherwise discard),
  truncates at 4000 chars with separate `truncated`/`original_length` fields
  and a prepended `--full` suggestion; `--full` returns the raw diff.
- `pr checkout <n>` reads the PR head branch from the PR fetch and fetches
  `refs/pull/{n}/head` from origin (uniform for same-repo and fork PRs, ADR
  0011), three-cased on local branch state so re-checkout is idempotent and
  divergent local commits fail with `GIT_ERROR` rather than being discarded.

Introduces the `GIT_ERROR` mapping (`runGit`) carrying git's first stderr
line plus a remediation help line, and widens the PR 404 classifier so a
`.diff` path still resolves to `PR_NOT_FOUND`.
2026-07-13 22:15:03 -04:00
7d72f94746 feat: add pr review (task 0013)
All checks were successful
CI / test (pull_request) Successful in 38s
Add `pr review <n>` with the three action switches --approve,
--request-changes, and --comment, plus --body/--body-file. Exactly one
action flag is required; zero or multiple raise VALIDATION_ERROR before
any API call, mirroring the merge shorthand-conflict rule. Body
requirements are left to Gitea: a body-less event it rejects surfaces its
422 as VALIDATION_ERROR carrying the server's message. Output is
`review: { number, action }`.
2026-07-13 20:44:59 -04:00
40859b9e6b feat: add pr merge and update-branch (task 0012)
All checks were successful
CI / test (pull_request) Successful in 41s
CI / test (push) Successful in 40s
Add `pr merge` with all six Gitea methods, the three common-method
shorthands, `--auto`, `--delete-branch`, `--subject`, `--body`/`--body-file`,
and `--merge-commit-id` (required with and only valid for
`--method manually-merged`). Conflicting method flags and the
manually-merged/commit-id pairing are rejected as VALIDATION_ERROR before
any API call. An already-merged PR short-circuits to a `pull_request` entity
block with `merged_by`/`merged_at`; merge-blocked 405/409 responses surface
as VALIDATION_ERROR with update-branch/checkout remediation.

Add `pr update-branch` merging the base into the head via the update
endpoint with `--style <merge|rebase>` (default merge).
2026-07-13 20:22:23 -04:00
965ece306f feat: add pr edit, close, and reopen (task 0011)
All checks were successful
CI / test (pull_request) Successful in 38s
CI / test (push) Successful in 39s
Add the PR-side state mutations mirroring the issue-side slice:

- `pr edit` applies title/body/base/milestone and the recomputed assignee
  list in one PATCH, with additive label endpoints and (per the ADR 0007
  amendment) the dedicated requested-reviewers POST/DELETE endpoints for
  `--add-reviewer`/`--remove-reviewer`.
- `pr close --comment` posts the comment after the PATCH and surfaces a
  comment-post failure; an already-closed or merged PR is an `already: true`
  no-op reporting the actual state.
- `pr reopen` is an `already: true` no-op when already open.

Extract the fetch-then-patch assignee merge into a shared `src/assignees.ts`
(`mergeAssignees` + `assigneeLogins`), now used by both `issue edit` and
`pr edit`.
2026-07-13 19:55:00 -04:00
6c15e6082f feat: add issue blocks and blocked-by (task 0007)
All checks were successful
CI / test (pull_request) Successful in 35s
CI / test (push) Successful in 35s
2026-07-13 19:41:04 -04:00
16d2f29f19 feat: add pr view and checks (task 0009)
All checks were successful
CI / test (pull_request) Successful in 36s
CI / test (push) Successful in 37s
Add `pr view <n>` and `pr checks <n>`, built on the truncation machinery
and review fetches from earlier slices.

`pr view` uses the three-call fetch pattern (PR + reviews in parallel, then
the head commit's combined status) so `checks`, `comment_count`, and
`review_count` are in the default output; `--comments`, `--reviews`, and
`--full` behave as on `issue view`, with `--reviews` exposing Gitea's
`official`/`stale` fields plus per-review inline comments.

`pr checks <n>` renders the checks summary line and the `{ name, conclusion }`
rows, or the scalar no-CI message when no statuses exist.

The state→conclusion mapping and summary live in a new `src/checks.ts`;
`commentRows` is extracted into `src/comment.ts` and shared with `issue view`.
2026-07-12 20:22:17 -04:00
6333058b72 feat: add pr list (task 0008)
All checks were successful
CI / test (pull_request) Successful in 30s
CI / test (push) Successful in 31s
Implements `pr list` with the two policies later PR slices reuse:
client-side filtering with the filtered-set count line (ADR 0005) and
the official-first reviewDecision via parallel per-PR review fetches
(ADR 0006), extracted into src/review.ts.

API-supported flags map to their params (--state, --author→poster,
--label name→ID, --label-id, --sort, --limit, --fields); --assignee,
--base, --head, and --draft filter in-process after full pagination,
with the count line's total taken from the filtered set. --search is
refused with a redirect to `search prs`.

Adds a boolText field extractor and a shared parsePositiveInt helper,
the latter also adopted by issue list's --limit parsing.
2026-07-12 19:23:29 -04:00
7a41807a8a feat: add issue delete, pin, and unpin (task 0006)
All checks were successful
CI / test (pull_request) Successful in 29s
CI / test (push) Successful in 32s
Add the remaining simple issue mutations. `issue delete` hard-deletes via
the DELETE endpoint and is deliberately not idempotent — a nonexistent
issue yields ISSUE_NOT_FOUND rather than reporting success. `issue pin`
and `issue unpin` read the current pin state (Gitea's pin_order field) and
short-circuit to an idempotent no-op with an Already pinned/unpinned
message when there is nothing to do.
2026-07-12 19:02:02 -04:00
6296f47fab feat: add issue edit, close, and reopen (task 0005)
All checks were successful
CI / test (pull_request) Successful in 27s
CI / test (push) Successful in 37s
Implement the issue state-transition mutations:

- issue edit: --title, --body/--body-file, --add-label/--remove-label,
  --add-assignee/--remove-assignee, --milestone. Label mutations use
  Gitea's dedicated additive/removal endpoints (names added directly,
  removals resolved to IDs, unapplied-label 404 as silent success);
  assignees use fetch-then-patch (ADR 0007); title/body/milestone and the
  recomputed assignee list travel in one PATCH. Outputs edited: {number,
  status: ok}.
- issue close: PATCHes state closed, optional --comment posted after with
  its failure surfaced; already-closed short-circuits with Already closed.
- issue reopen: PATCHes state open; already-open short-circuits with
  Already open.

Extract a shared getIssue helper used by view/edit/close/reopen.
2026-07-12 09:47:51 -04:00
348f28a54d feat: complete issue list filters, sort, and fields (task 0002)
Finish the `issue list` flag surface left minimal by the tracer slice:

- Server-side filters `--label`, `--assignee`, `--author`, `--milestone`,
  mapped to Gitea's `labels`, `assigned_by`, `created_by`, `milestones`.
- Client-side `--sort <created|updated|comments>`, always descending, over
  the fully paginated set (ADR 0005); `--limit` caps the sorted result.
- `--fields` exposing body, closedAt, labels, milestone, updatedAt, url.
- `--search` refused with a VALIDATION_ERROR redirecting to `search issues`.

Exhaustive pagination lands as a shared `paginate.ts`, since ADR 0005 makes
it a policy later slices reuse; `lookup.ts` drops its hand-rolled copy of the
same loop. The helper carries the 20-page cap that copy encoded, matching the
1000-item ceiling Principle 8 sets.
2026-07-12 09:29:35 -04:00
590691fc96 feat: add pr create and comment (task 0010)
All checks were successful
CI / test (pull_request) Successful in 30s
CI / test (push) Successful in 29s
`pr create` takes --title (required), --body/--body-file, --base, --head,
--assignee, --reviewer, repeatable name-resolved --label, and --milestone.
An omitted --head defaults to the current local branch; an omitted --base to
the repository's default branch. Before creating, an existing open PR for the
same base/head pair short-circuits to `pull_request: { number, url, already:
true }` rather than opening a duplicate; only an open PR does, since a closed
one's branches are free to be proposed again.

`pr comment <n>` posts through the shared issue-comment endpoint and returns
the created comment as `comment: { number, author, created, body }` (ADR 0008),
reporting a 404 as PR_NOT_FOUND since the caller asked about a pull request.

That comment block is now built in one place (src/comment.ts) for both issue
and pr comment, as ADR 0008 requires them to stay identical.
2026-07-11 21:03:40 -04:00
f82414a933 feat: add issue create and comment (task 0004)
All checks were successful
CI / test (pull_request) Successful in 24s
CI / test (push) Successful in 28s
Introduce the first mutations, along with the shared machinery the later
issue and PR mutation slices reuse.

- `issue create` with --title/--body/--body-file/--assignee/--label/
  --milestone/--fields, emitting `issue: { number, title, state, url }`
- `issue comment <n>`, echoing the created comment from the POST response
  with the body cleaned and truncated at 800 chars
- body-source resolution (--body vs --body-file), label and milestone
  name->ID lookup, repeatable flags, and the `joined`/`selectExtraFields`
  field extractors

Label lookup pages until exhausted, since a repo with more labels than one
page would otherwise fail to resolve a valid name. The end-to-end tier seeds
a mixed-case label and milestone and passes both in a different case, so the
case-insensitive lookup is verified against live Gitea rather than only
against fixtures.
2026-07-11 20:39:01 -04:00
5e66b4d746 feat: add issue view with body cleaning and truncation (task 0003)
All checks were successful
CI / test (pull_request) Successful in 26s
CI / test (push) Successful in 23s
Add `issue view <n>` as the first detail command, introducing the
content-cleaning and truncation machinery (src/body.ts) that later issue
and PR slices reuse.

- Default output: number, title, state, author, created, body (truncated
  at 500), plus comment_count; --comments expands every comment (bodies
  truncated at 800); --full suppresses all truncation.
- cleanBody runs only when a body exceeds its limit: normalizes Gitea
  issue/PR URLs on the detected host to Issue#N/PR#N, strips image embeds
  and long URLs, and collapses quoted blocks.
- Type guard: a PR number fails with VALIDATION_ERROR and a `pr view <n>`
  hint, detected via the fetched object's pull_request field.
- renderDetail joins the detail entity, optional sub-blocks, and help.
2026-07-11 19:36:24 -04:00
ae0f4c2675 test: close tea and error-classifier coverage gaps, raise thresholds
All checks were successful
CI / test (pull_request) Successful in 53s
CI / test (push) Successful in 21s
Cover the previously untested credential and error-classification paths:
- tea.ts: failing/invalid/non-array `tea login list`, a failing token
  helper, and an empty token, all driven through the CLI seam via the fake
  tea harness (now parametrizable for exit codes and output).
- errors.ts: a unit-tier test of classifyHttpError for the pure-classifier
  branches no shipped command reaches yet (issue/pull 404s, the
  already-classified passthrough, transport failures, no-body defaults).

errors.ts is now fully covered and tea.ts is at 96% (the remainder is
defensive code unreachable through the seam). Overall coverage rose from
~87% to ~93% statements / ~89% branches; the ratchet is raised to
92/87/95/92 accordingly.
2026-07-11 09:15:15 -04:00
1d18472297 ci: add end-to-end tier and Gitea Actions workflow (task 0019)
Add the end-to-end test tier: a Gitea Actions workflow (GitHub-compatible)
that runs the unit+integration tiers plus e2e tests against a pinned
disposable Gitea service container. The e2e suite provisions its own repo,
token, and seed data over HTTP and drives the real CLI seam, gated on
GITEA_AXI_E2E_URL so the default suite stays dependency-free.

A fixture-vs-live shape guard anchors the issue-list FieldDef paths against
both the recorded fixture and the live response, failing on divergence.
2026-07-11 09:01:12 -04:00
38026f963d feat: scaffold CLI and minimal issue list (task 0001)
Tracer bullet for gitea-axi: runnable npm package on axi-sdk-js with
gitea-js as the sole HTTP layer, ESM on Node 20+.

- issue list with --state/--limit, default fields, count line from
  X-Total-Count, type=issues guard, explicit empty state, and next-step
  suggestions
- repo context detection from the git origin remote (SSH/scp/HTTPS),
  tea credential discovery with the three-way login-matching split, and
  -R/--repo and --login overrides (flag > env > auto)
- token retrieval via tea login helper get: tea's login list JSON
  carries no token (ADR 0001 amended)
- full AxiError classification table with path-based 404 split, TOON
  errors on stdout, exit codes 0/1/2
- test mode (GITEA_AXI_API_URL/TOKEN/REPO) suppressing subprocesses,
  fixture server, and vitest suites driving the CLI seam (50 tests)
2026-07-11 07:11:07 -04:00