@volter/twin-jira
v0.1.0
Published
Local Jira twin — REST; your real `jira.js` talks to it unmodified. Mirror, simulate, and fork. Built on @volter/twin.
Readme
@volter/twin-jira
The Jira twin — a local replica of the Jira Cloud REST API (Atlassian's
nested fields shape) on the shared @volter/twin kernel. The real
jira.js Version3Client works against it unmodified.
Surface
- REST API (
jira-twin.ts; HTTP wrapperjira-server.ts→createJiraTwinServer): search, get issue, list/add comments. - Writes (
applyJiraWrite): create issue (POST /issue), update (PUT /issue/:key), add comment — local transactions, visible via an action overlay (R3/R5/R18); the --read-only flag rejects writes. - Webhooks (
jira-events.ts):jira:issue_created/jira:issue_updated/comment_createdon write. - Conformance (
jira-conformance.ts): field-name subset vs the vendored Jira Cloud REST issue/comment schema (standing gate). - UI mirror (
jira-mirror-ui.ts): a Jira-style board (React) over the twin's REST API.
CLI
world-jira serve [--read-only] [--port N] [--root DIR]
world-jira mirror [--port N] [--root DIR]
world-jira conformance [--root DIR]Point the real jira.js Version3Client at it via host.
Four ways to use it
- Mock SDK — zero edits (preferred):
JIRA_TWIN_URL=http://127.0.0.1:PORT node --require @volter/twin/inject your-appredirects the realjira.jsfrom*.atlassian.netto the twin. Or override directly:new Version3Client({ host: 'http://127.0.0.1:PORT', authentication: {…} }). - API + CLI —
world-jira serve(writable) + drive withvolter-twin status|plan|refs jira, then push. - Read-only —
world-jira serve --read-only: unlimited local reads, no rate limits; writes refuse like Jira (4xx). - UI mirror —
world-jira mirrorrenders a Jira-style view of the twin's state.
(See the repo's GETTING-STARTED → "Four ways to use a twin", and cookbook/zero-edit-inject.)
Stable on the twin rubric: fidelity, read/write/fork, sync, observability, event emission, and conformance are tracked with explicit coverage gaps.
Coverage
Goal: honest, explicitly tracked coverage of Jira's core feature surface. The only accepted carve-outs are the explicit Out-of-scope items below. Tracked in three buckets — anything not done or carved out is a gap to close.
Done — full standard issue model under the real nested fields shape: ADF
description + ADF comments (round-tripped), status + statusCategory (To Do /
In Progress / Done), issue type, priority, labels, components, fixVersions, resolution +
resolutiondate, parent, project, assignee/reporter/creator, due/created/updated dates;
workflow transitions (list + apply, with auto-resolution on Done); JQL (a
recursive-descent evaluator: =, !=, ~, IN (…)/NOT IN (…) for label and
non-label fields, IS EMPTY/IS NOT EMPTY, AND/OR/NOT with parenthesised
grouping, the currentUser() function for user fields, and multi-field
ORDER BY a ASC, b DESC; unsupported syntax → faithful 400) + search
pagination (startAt/maxResults); board configuration
(GET /rest/agile/1.0/board/:id/configuration — column→status mapping for
To Do/In Progress/Done, story-point estimation field, swimlanes); issue links + link types, sub-tasks,
attachments (metadata only), worklogs + aggregate timetracking, watchers,
votes; agile boards (one synthetic scrum board per project) + sprints (create/
update/start/close, move issues); changelog (?expand=changelog + paginated
/changelog, derived from the event/action stream); story points (customfield_10016)
- original time estimate; Jira Service Management (JSM) over the real
/rest/servicedeskapinamespace — service desks (GET /servicedesk[/:id], one synthetic desk per project), request types (GET /servicedesk/:id/requesttype[/:id], fixed catalog), and customer requests (POST /requestcreate,GET /request/:key,GET /requestlist + filter by status,GET /request/:key/statushistory) — backed by real issues, with the JSM paged envelope (start/limit → size/isLastPage/values) and faithful 400/404; the deeper JSM surface — queues (GET /servicedesk/:id/queue[/:qid][/issue], saved-JQL queues with live issue counts), SLAs (GET /request/:key/sla— first-response + resolution goals, ongoing/completed cycles, breached flags), approvals (GET /request/:key/approval,POST .../approval/:idapprove/decline → advances the issue), request comments (POST/GET /request/:key/comment— public vs internal with the?publicfilter), participants (POST/DELETE/GET /request/:key/participant), organizations (POST/DELETE /organization+/:id/usermembers), customers (POST /customer), and knowledge base (GET /servicedesk/:id/article+/knowledgebase/articlesubstring search); custom fields — create/update/delete (POST/PUT/DELETE /field, typed schema: text/textarea/number/datepicker/select/multiselect/url/labels, surfaced inGET /fieldascustom:true) + field options (POST/PUT/DELETE /field/:id/optionfor select/multiselect); issue niche — reactions (emoji on comments + issues), move (POST /issue/:key/movebetween projects — re-keys the issue and tombstones the old key), notify (POST /issue/:key/notify); project niche — roles + actors (GET/POST/DELETE /project/:key/role/:idover a fixed role catalog), project types (GET /project/type), features (GET /project/:key/features+PUT .../features/:ftoggle), entity properties (GET/PUT/DELETE /project/:key/properties/:k); JQL history operators (WAS [NOT],CHANGED [FROM v] [TO v]withAFTER/BEFORE/ONpredicates, derived from the real changelog); projects as first-class resources — projects CRUD (POST /projectcreate with faithful 400 on missing/duplicate/invalid key,GET /project/:keyOrId, paginatedGET /project/search+?query,PUT /project/:keyOrId,DELETE /project/:keyOrId), components (POST /component,GET /project/:key/components,GET/PUT/DELETE /component/:id) and versions / releases (POST /version,GET /project/:key/versions,GET/PUT/DELETE /version/:id) — persisted via the action log with faithful ids/shapes/404 (issue-referenced-but-uncreated project keys still surface as derived stubs, keeping issue project/components/fixVersions consistent); webhooks (jira:issue_created/jira:issue_updated/comment_created); UI mirror (rung-5 ✅ — board columns by status category, cards, issue detail with Details sidebar / Description / Activity / Sub-tasks / Issue links / Attachments / Work log; Projects directory view — a row per project (key/name/type/ issue count) with a detail pane listing the project's Components and Versions/releases; JSM service-desk + queue view — request queues grouped by status, request rows with type/reporter/status, and the per-desk request-type catalog); connector (pull via JQL + push: create/update, comment, real transitions resolved by target status, worklog, issue link, watcher/vote, sprint create/update + issue-move).
Planned (known-missing, will do) — permission schemes; notification schemes; field configuration schemes (custom-field CRUD + select options are now Done above; field config schemes that bind fields to screens/contexts remain); workflow configuration (beyond the small fixed To Do / In Progress / Done workflow); bulk operations (bulk edit/transition/move/delete); user / group management; issue-type / screen / field-config schemes; CSV import; automation rules; pulling / pushing components, fixVersions, story points and time estimates through the connector (the REST twin models them; the connector mapper does not yet carry them).
Out of scope (deliberately not modeled, with reason) —
- Real binary attachment bytes (the twin records attachment metadata —
filename/size/mimeType/author — and exposes the
contentURL, but stores no file body; uploads are declared via JSON, not multipart): a file store is infra, not the issue API — the attachment objects are modeled; only the raw bytes are out of scope. - Board create/delete via REST (
POST/DELETE /rest/agile/1.0/board): boards are derived per-project in the twin (one synthetic scrum board per project key), so a board is a projection of a project (which is first-class —projects.crudis done), not a separately-created resource. Explicit board CRUD is out of scope.
