feat(jtk): add remotelinks subcommand for issue web links#415
Conversation
Automated PR ReviewReviewed commit: Summary
go:implementation-tests (2 findings)Minor -
|
| Field | Value |
|---|---|
| Model | claude-sonnet-4-6 |
| Reviewers | documentation:docs, go:implementation-tests, policies:conventions, structure:repo-health |
| Engine | claude_cli · claude-sonnet-4-6 |
| Reviewed by | cr · piekstra-dev |
| Duration | 4m 08s wall · 4m 06s compute |
| Cost | ~$0.61 (est.) |
| Tokens | 25 in / 11.4k out |
Per-workstream usage
| Workstream | Model | In | Out | Cache read | Cache create | Cost | Duration |
|---|---|---|---|---|---|---|---|
| orchestrator-selection | claude-sonnet-4-6 | 4 | 1.8k | 7.7k | 12.6k | ~$0.08 (est.) | 29s |
| documentation:docs | claude-sonnet-4-6 | 4 | 1.5k | 7.2k | 12.6k | ~$0.07 (est.) | 30s |
| go:implementation-tests | claude-sonnet-4-6 | 5 | 5.8k | 34.7k | 34.0k | ~$0.22 (est.) | 1m 54s |
| policies:conventions | claude-sonnet-4-6 | 4 | 1.5k | 7.7k | 15.4k | ~$0.08 (est.) | 31s |
| structure:repo-health | claude-sonnet-4-6 | 4 | 555 | 7.2k | 18.9k | ~$0.08 (est.) | 15s |
| orchestrator-rollup | claude-sonnet-4-6 | 4 | 432 | 20.7k | 15.6k | ~$0.07 (est.) | 25s |
piekstra-dev
left a comment
There was a problem hiding this comment.
Automated PR review completed with outcome: approved.
Automated PR ReviewReviewed commit: Summary
go:implementation-tests (1 finding)Minor -
|
| Field | Value |
|---|---|
| Model | claude-sonnet-4-6 |
| Reviewers | go:implementation-tests, documentation:docs, policies:conventions |
| Engine | claude_cli · claude-sonnet-4-6 |
| Reviewed by | cr · piekstra-dev |
| Duration | 3m 10s wall · 3m 03s compute |
| Cost | ~$0.33 (est.) |
| Tokens | 18 in / 5.5k out |
Per-workstream usage
| Workstream | Model | In | Out | Cache read | Cache create | Cost | Duration |
|---|---|---|---|---|---|---|---|
| orchestrator-selection | claude-sonnet-4-6 | 3 | 124 | 3.3k | 4.8k | ~$0.02 (est.) | 53s |
| go:implementation-tests | claude-sonnet-4-6 | 4 | 3.5k | 7.2k | 29.2k | ~$0.16 (est.) | 1m 08s |
| documentation:docs | claude-sonnet-4-6 | 4 | 1.3k | 7.2k | 12.6k | ~$0.07 (est.) | 27s |
| policies:conventions | claude-sonnet-4-6 | 3 | 124 | 3.3k | 4.8k | ~$0.02 (est.) | 24s |
| orchestrator-rollup | claude-sonnet-4-6 | 4 | 372 | 7.2k | 11.7k | ~$0.05 (est.) | 10s |
piekstra-dev
left a comment
There was a problem hiding this comment.
Automated PR review completed with outcome: approved.
Add a top-level `jtk remotelinks` command (aliases: `remotelink`, `rl`) to
manage an issue's Jira Remote Links / Web Links — external URLs shown in the
issue's links sidebar — via the Jira REST API
(GET/POST/DELETE /rest/api/3/issue/{key}/remotelink).
Subcommands follow the existing issue-scoped CRUD conventions
(comments/links/attachments) and the jtk command-surface guardrails:
- `remotelinks list <issue-key>` — list remote links (supports
--id / --extended / --fields projection)
- `remotelinks add <issue-key> --url --title [--summary --relationship]` —
attach a web link (`add` = attach child to parent per the verb table);
--title defaults to the URL; --id emits the new link ID
- `remotelinks remove <issue-key> <link-id>` — detach a web link
Layered per the rendering architecture: api.Client methods + DTOs in
api/remotelinks.go, a pure RemoteLinkPresenter in
internal/present/remotelink.go, and command orchestration in
internal/cmd/remotelinks. Adds API, presenter, and command tests, plus
OUTPUT_SPEC and README documentation.
The repo exposes resource commands at the top level (e.g. `jtk links`,
`jtk comments`) rather than under a `jtk issue` parent, so the issue's
requested `jtk issue remotelink` surface is delivered as `jtk remotelinks`,
preserving the requested add/list/remove verbs.
Closes #413
- present: drive PresentList headers and column selection from RemoteLinkListSpec via projection.ProjectTable + ForMode instead of hard-coding two parallel extended/default header+row paths, so the registry stays the single source of truth for columns. - api: DeleteRemoteLink now takes linkID int (matching RemoteLink.ID), guards linkID <= 0 with ErrRemoteLinkIDRequired, and formats the URL with %d; runRemove parses args[1] with strconv.Atoi and returns a user-facing error for non-numeric input before the API call. - api: AddRemoteLink validates req.Object.Title with a new ErrRemoteLinkTitleRequired sentinel (Jira requires object.title). - tests: update TestDeleteRemoteLink to int IDs (+ linkID <= 0 cases), add TestAddRemoteLink_EmptyTitle and TestRunRemove_NonNumericID.
PresentRemoved now accepts linkID int and formats with %d, dropping the int->string round-trip in runRemove now that DeleteRemoteLink takes int. Add a brief README note that remotelinks uses add/remove to mirror the Jira Remote Links API attach/detach semantics.
962aed1 to
4d7f991
Compare
|
|
monit-reviewer
left a comment
There was a problem hiding this comment.
Automated PR Review
Reviewed commit: 5023be4
Approved with 2 non-blocking suggestions below. Address at your discretion.
Summary
| Reviewer | Findings |
|---|---|
| documentation:docs-reviewer | 1 |
| harness-engineering:harness-knowledge-reviewer | 1 |
documentation:docs-reviewer (1 findings)
💡 Suggestion - tools/jtk/internal/cmd/OUTPUT_SPEC.md:490
The
--summaryand--relationshipflags forremotelinks addare implemented and referenced in the PR description but absent from OUTPUT_SPEC.md and README. Users have no way to discover these flags from the docs. The spec entry should be extended to document all optional flags with their behavior.
harness-engineering:harness-knowledge-reviewer (1 findings)
💡 Suggestion - tools/jtk/internal/cmd/OUTPUT_SPEC.md:463
The rationale for placing resource commands at the top level (e.g.,
jtk remotelinksrather thanjtk issue remotelinks) is explained only in the PR description. If ARCHITECTURE.md doesn't already document the 'all resource commands are top-level' convention and the reasoning behind it, this decision will be invisible to future contributors facing the same structural choice.
1 info-level observations excluded. Run with --verbose to include.
9 PR discussion threads considered.
Completed in 3m 16s | $2.72 | sonnet | daemon 0.2.133 | Glorfindel
| Field | Value |
|---|---|
| Model | sonnet |
| Reviewers | hybrid-synthesis, documentation:docs-reviewer, harness-engineering:harness-architecture-reviewer, harness-engineering:harness-enforcement-reviewer, harness-engineering:harness-knowledge-reviewer, harness-engineering:harness-self-documenting-code-reviewer, security:security-code-auditor |
| Engine | claude · sonnet |
| Reviewed by | pr-review-daemon · monit-pr-reviewer |
| Duration | 3m 16s wall · 2m 47s compute (Reviewers: 2m 03s · Synthesis: 44s) |
| Cost | $2.72 (estimated) |
| Tokens | 476.7k in / 23.8k out |
| Turns | 14 |
Per-workstream usage
| Workstream | Model | In | Out | Cache read | Cache create | Cost |
|---|---|---|---|---|---|---|
| hybrid-synthesis | sonnet | 40.9k | 2.0k | 13.1k | 27.8k (1h) | $0.20 |
| documentation:docs-reviewer | sonnet | 39.0k | 3.3k | 13.1k | 25.9k (1h) | $0.21 |
| harness-engineering:harness-architecture-reviewer | sonnet | 67.6k | 1.1k | 13.1k | 54.5k (1h) | $0.35 |
| harness-engineering:harness-enforcement-reviewer | sonnet | 72.2k | 5.3k | 13.1k | 59.1k (1h) | $0.44 |
| harness-engineering:harness-knowledge-reviewer | sonnet | 69.5k | 2.7k | 13.1k | 56.3k (1h) | $0.38 |
| harness-engineering:harness-self-documenting-code-reviewer | sonnet | 72.2k | 6.6k | 13.1k | 59.0k (1h) | $0.46 |
| security:security-code-auditor | sonnet | 66.3k | 1.7k | 13.1k | 53.1k (1h) | $0.35 |
| discussion-summarizer | — | 49.0k | 1.1k | 18.5k | 30.5k (1h) | $0.34 |
Re-reviews only run when @monit-reviewer is re-requested as a reviewer — push as many commits as you need, then re-request when ready. PRs targeting branches other than main, master are skipped, even when @monit-reviewer is re-requested.
| Issue: MON-4818 | ||
| Title: GitHub #456: Some issue | ||
| URL: https://github.com/owner/repo/issues/456 | ||
| ``` |
There was a problem hiding this comment.
🔵 Low (documentation:docs-reviewer): The --summary and --relationship flags for remotelinks add are implemented and referenced in the PR description but absent from OUTPUT_SPEC.md and README. Users have no way to discover these flags from the docs. The spec entry should be extended to document all optional flags with their behavior.
Reply to this thread when addressed.
|
|
||
| Cached during init/refresh. `links create` accepts the type name ("Blocker"), the outward verb ("blocks"), or the inward verb ("is blocked by"). | ||
|
|
||
| ### `remotelinks` |
There was a problem hiding this comment.
🔵 Low (harness-engineering:harness-knowledge-reviewer): The rationale for placing resource commands at the top level (e.g., jtk remotelinks rather than jtk issue remotelinks) is explained only in the PR description. If ARCHITECTURE.md doesn't already document the 'all resource commands are top-level' convention and the reasoning behind it, this decision will be invisible to future contributors facing the same structural choice.
Reply to this thread when addressed.
Closes #413
Summary
Adds a top-level
jtk remotelinkscommand (aliases:remotelink,rl) to manage an issue's Jira Remote Links / Web Links — external URLs shown in the issue's links sidebar — via the Jira REST API (GET/POST/DELETE /rest/api/3/issue/{key}/remotelink).Subcommands deliver the CRUD surface from the issue, following the existing issue-scoped command conventions (
comments/links/attachments) and the jtk command-surface guardrails:remotelinks list <issue-key>— list remote links. Supports--id,--extended(adds RELATIONSHIP + SUMMARY columns), and--fieldsprojection.remotelinks add <issue-key> --url <url> --title <title> [--summary --relationship]— attach a web link. Per the guardrails verb table,add= attach a child to a parent.--titledefaults to the URL when omitted;--idemits only the new link ID; emits aget-style post-state detail block otherwise.remotelinks delete <issue-key> <link-id>— delete a remote link record from the issue. Emits a confirmation line.Note on command placement
The issue requested
jtk issue remotelink ..., but this CLI exposes resource commands at the top level (jtk links,jtk comments,jtk attachments) rather than under ajtk issueparent — there is nojtk issuecommand. The feature is therefore delivered asjtk remotelinks, matching repo convention while preserving the requested issue-scoped remote-link management and flags (--url,--title).Architecture
Layered per
ARCHITECTURE.md(domain → presenter → renderer; commands orchestrate):tools/jtk/api/remotelinks.go—Client.GetRemoteLinks/AddRemoteLink/DeleteRemoteLink+ DTOs; newErrRemoteLinkIDRequired/ErrRemoteLinkURLRequired/ErrRemoteLinkTitleRequiredsentinels inapi/errors.go.tools/jtk/internal/present/remotelink.go— pureRemoteLinkPresenter(list table, added-detail, deleted/empty messages) + a projectionRegistry.tools/jtk/internal/cmd/remotelinks/remotelinks.go— command wiring; registered incmd/jtk/main.go.remotelinkssection intools/jtk/internal/cmd/OUTPUT_SPEC.mdand an example block inREADME.md.Tests added at every layer: API client (httptest), presenter (exact presentation-model assertions), and command (list/add/delete incl.
--id/--extended/--fields, title-defaults-to-URL, empty-state, non-numeric delete IDs).Testing
All commands run from the repo root (
GOFLAGS=-tags=keyring_no1password,keyring_nopassage, per the Makefile).go build -v -o bin/jtk ./tools/jtk/cmd/jtk— passgo test -race ./tools/jtk/...— passcd tools/jtk && golangci-lint run— passcd tools/jtk && go mod tidy+git diff --exit-code go.mod go.sum— cleanRemaining work / follow-ups
--relationshipand--summaryare supported onaddbut optional; anupdate/edit-in-place path (re-POST with a matchingglobalId) was not added.list).