pm-jira 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 - 2026-05-26
4
+
5
+ ### Other
6
+
7
+ - Release readiness hardening for pm-jira ([pm-jira-5d71](https://github.com/unbraind/pm-jira/blob/main/.agents/pm/tasks/pm-jira-5d71.toon))
package/README.md ADDED
@@ -0,0 +1,198 @@
1
+ # pm-jira
2
+
3
+ A [pm-cli](https://github.com/unbraind/pm-cli) extension that syncs Jira issues into pm items using the Jira REST API v3.
4
+
5
+ ## Features
6
+
7
+ - Sync issues from any Jira project into pm items with full deduplication
8
+ - Custom JQL support for fine-grained control over what gets synced
9
+ - Automatic mapping of Jira statuses and priorities to pm equivalents
10
+ - Labels and fix versions mapped as pm tags
11
+ - Dry-run mode to preview changes before writing
12
+ - Works as both a `pm jira sync` command and a `jira-sync` importer
13
+
14
+ ## Installation
15
+
16
+ Install with pm from GitHub:
17
+
18
+ ```bash
19
+ pm install github.com/unbraind/pm-jira
20
+ ```
21
+
22
+ Or build locally from source:
23
+
24
+ ```bash
25
+ npm ci
26
+ npm run build
27
+ ```
28
+
29
+ ## Jira API Setup
30
+
31
+ You need a Jira API token to authenticate. To create one:
32
+
33
+ 1. Go to [https://id.atlassian.com/manage-profile/security/api-tokens](https://id.atlassian.com/manage-profile/security/api-tokens)
34
+ 2. Click **Create API token**
35
+ 3. Give it a label (e.g. `pm-cli-sync`) and copy the token
36
+
37
+ ## Required Environment Variables
38
+
39
+ | Variable | Description | Example |
40
+ |---|---|---|
41
+ | `JIRA_BASE_URL` | Your Jira instance base URL | `https://company.atlassian.net` |
42
+ | `JIRA_EMAIL` | Email address for your Jira account | `you@company.com` |
43
+ | `JIRA_API_TOKEN` | API token generated above | `<jira-api-token>` |
44
+
45
+ Set them in your shell or `.env`:
46
+
47
+ ```bash
48
+ export JIRA_BASE_URL=https://company.atlassian.net
49
+ export JIRA_EMAIL=you@company.com
50
+ export JIRA_API_TOKEN=<jira-api-token>
51
+ ```
52
+
53
+ ## Usage
54
+
55
+ ### Command: `pm jira sync`
56
+
57
+ ```bash
58
+ # Sync all open issues from a project (default JQL: statusCategory != Done)
59
+ pm jira sync --project PROJ
60
+
61
+ # Sync up to 200 issues
62
+ pm jira sync --project PROJ --max-results 200
63
+
64
+ # Use custom JQL
65
+ pm jira sync --jql "project = PROJ AND assignee = currentUser() ORDER BY updated DESC"
66
+
67
+ # Preview without writing (dry run)
68
+ pm jira sync --project PROJ --dry-run
69
+
70
+ # Only sync issues that map to the "wip" pm status
71
+ pm jira sync --project PROJ --status wip
72
+
73
+ # Combine flags
74
+ pm jira sync --project PROJ --max-results 100 --status todo --dry-run
75
+ ```
76
+
77
+ ### Flags
78
+
79
+ | Flag | Alias | Type | Default | Description |
80
+ |---|---|---|---|---|
81
+ | `--project` | `-p` | string | — | Jira project key (e.g. `PROJ`). Used to build default JQL. |
82
+ | `--jql` | `-q` | string | — | Custom JQL query. Overrides `--project` default JQL. |
83
+ | `--max-results` | `-n` | number | `500` | Maximum number of issues to sync. |
84
+ | `--dry-run` | — | boolean | `false` | Preview what would be synced without writing. |
85
+ | `--status` | `-s` | string | — | Filter by mapped pm status (`todo`, `wip`, `done`, `blocked`). |
86
+
87
+ ### Importer: `jira-sync`
88
+
89
+ Use the `jira-sync` importer in your pm-cli config for automated syncing:
90
+
91
+ ```json
92
+ {
93
+ "importers": {
94
+ "jira-sync": {
95
+ "project": "PROJ",
96
+ "maxResults": 300
97
+ }
98
+ }
99
+ }
100
+ ```
101
+
102
+ Credentials are read from environment variables or from the importer config:
103
+
104
+ ```json
105
+ {
106
+ "importers": {
107
+ "jira-sync": {
108
+ "JIRA_BASE_URL": "https://company.atlassian.net",
109
+ "JIRA_EMAIL": "you@company.com",
110
+ "JIRA_API_TOKEN": "<jira-api-token>",
111
+ "project": "PROJ"
112
+ }
113
+ }
114
+ }
115
+ ```
116
+
117
+ ## Status Mapping
118
+
119
+ | Jira Status | pm Status |
120
+ |---|---|
121
+ | To Do, Open, Backlog, (any other) | `todo` |
122
+ | In Progress, In Review, In Development, Code Review | `wip` |
123
+ | Done, Resolved, Closed, Complete, Completed | `done` |
124
+ | Blocked | `blocked` |
125
+
126
+ ## Priority Mapping
127
+
128
+ | Jira Priority | pm Priority |
129
+ |---|---|
130
+ | Highest, Critical | `1` (highest) |
131
+ | High | `2` |
132
+ | Medium, (any other) | `3` |
133
+ | Low, Lowest | `4` (lowest) |
134
+
135
+ ## Item Structure
136
+
137
+ Each synced item uses `${PROJECT}-${NUMBER}` as the idSuffix for deduplication (e.g. `PROJ-123`). Running sync again updates existing items rather than creating duplicates.
138
+
139
+ Items include:
140
+
141
+ - **title**: `[PROJ-123] Issue summary`
142
+ - **body**: Issue description (converted from Atlassian Document Format to plain text)
143
+ - **status**: Mapped from Jira status (see table above)
144
+ - **priority**: Mapped from Jira priority (see table above)
145
+ - **tags**: Jira labels + fix version names
146
+ - **meta.jira_key**: Original Jira issue key (e.g. `PROJ-123`)
147
+ - **meta.jira_project**: Jira project key (e.g. `PROJ`)
148
+ - **meta.jira_assignee**: Assignee display name (if set)
149
+ - **meta.jira_duedate**: Due date in `YYYY-MM-DD` format (if set)
150
+
151
+ ## JQL Examples
152
+
153
+ ```
154
+ # All open issues in a project, by priority
155
+ project = PROJ AND statusCategory != Done ORDER BY priority ASC
156
+
157
+ # Only issues assigned to you
158
+ project = PROJ AND assignee = currentUser()
159
+
160
+ # Issues updated in the last 7 days
161
+ project = PROJ AND updated >= -7d ORDER BY updated DESC
162
+
163
+ # Issues in a specific sprint
164
+ project = PROJ AND sprint in openSprints()
165
+
166
+ # Issues with a specific label
167
+ project = PROJ AND labels = "backend"
168
+
169
+ # Issues by type
170
+ project = PROJ AND issuetype = Bug AND statusCategory != Done
171
+ ```
172
+
173
+ ## Development
174
+
175
+ ```bash
176
+ # Install dev dependencies
177
+ npm install
178
+
179
+ # Build TypeScript
180
+ npm run build
181
+
182
+ # Watch mode
183
+ npm run dev
184
+ ```
185
+
186
+ ## Requirements
187
+
188
+ - Node.js 18+ (uses native `https` module and `Buffer`)
189
+ - pm-cli `>=2026.5.0`
190
+ - TypeScript 5.x (dev dependency)
191
+
192
+ ## License
193
+
194
+ MIT
195
+
196
+ ## Release Automation
197
+
198
+ This package is release-ready for GitHub, npm, and Bun-compatible installs. CI runs type checking, build, production dependency audit, package packing, Bun install verification, and pm-changelog validation. The daily release workflow publishes only when commits exist after the latest release tag and uses pm-changelog to generate CHANGELOG.md and GitHub release notes.
@@ -0,0 +1,7 @@
1
+ declare const _default: {
2
+ name: string;
3
+ version: string;
4
+ activate(api: import("@unbrained/pm-cli/sdk").ExtensionApi): void;
5
+ };
6
+ export default _default;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;AA2LA,wBA8OG"}
package/dist/index.js ADDED
@@ -0,0 +1,288 @@
1
+ import https from "node:https";
2
+ import { URL } from "node:url";
3
+ import { spawnSync } from "node:child_process";
4
+ const defineExtension = ((extension) => extension);
5
+ function mapJiraPriority(jiraPriority) {
6
+ if (!jiraPriority)
7
+ return 3;
8
+ const name = jiraPriority.toLowerCase();
9
+ if (name === "highest" || name === "critical")
10
+ return 1;
11
+ if (name === "high")
12
+ return 2;
13
+ if (name === "medium")
14
+ return 3;
15
+ if (name === "low" || name === "lowest")
16
+ return 4;
17
+ return 3;
18
+ }
19
+ function mapJiraStatus(jiraStatus) {
20
+ const name = jiraStatus.toLowerCase();
21
+ if (name === "blocked")
22
+ return "blocked";
23
+ if (name === "in progress" ||
24
+ name === "in review" ||
25
+ name === "in development" ||
26
+ name === "code review")
27
+ return "in_progress";
28
+ if (name === "done" ||
29
+ name === "resolved" ||
30
+ name === "closed" ||
31
+ name === "complete" ||
32
+ name === "completed")
33
+ return "closed";
34
+ // Default: to do / open / backlog / any other
35
+ return "open";
36
+ }
37
+ // ---------------------------------------------------------------------------
38
+ // Jira description (Atlassian Document Format) → plain text
39
+ // ---------------------------------------------------------------------------
40
+ function adfToPlainText(node) {
41
+ if (!node)
42
+ return "";
43
+ if ("text" in node && typeof node.text === "string") {
44
+ return node.text;
45
+ }
46
+ if ("content" in node && Array.isArray(node.content)) {
47
+ return node.content
48
+ .map((child) => adfToPlainText(child))
49
+ .join("")
50
+ .trim();
51
+ }
52
+ return "";
53
+ }
54
+ // ---------------------------------------------------------------------------
55
+ // HTTP helper using Node.js native https module
56
+ // ---------------------------------------------------------------------------
57
+ function httpsGet(url, authHeader) {
58
+ return new Promise((resolve, reject) => {
59
+ const parsed = new URL(url);
60
+ const options = {
61
+ hostname: parsed.hostname,
62
+ path: parsed.pathname + parsed.search,
63
+ method: "GET",
64
+ headers: {
65
+ Authorization: authHeader,
66
+ "Content-Type": "application/json",
67
+ Accept: "application/json",
68
+ },
69
+ };
70
+ const req = https.request(options, (res) => {
71
+ let body = "";
72
+ res.on("data", (chunk) => {
73
+ body += chunk.toString();
74
+ });
75
+ res.on("end", () => {
76
+ if (res.statusCode && res.statusCode >= 400) {
77
+ reject(new Error(`Jira API error ${res.statusCode}: ${body.slice(0, 200)}`));
78
+ }
79
+ else {
80
+ resolve(body);
81
+ }
82
+ });
83
+ });
84
+ req.on("error", reject);
85
+ req.end();
86
+ });
87
+ }
88
+ // ---------------------------------------------------------------------------
89
+ // Fetch all pages from Jira search API
90
+ // ---------------------------------------------------------------------------
91
+ async function fetchAllJiraIssues(baseUrl, authHeader, jql, maxResults) {
92
+ const fields = "summary,description,status,priority,labels,assignee,duedate,fixVersions";
93
+ const allIssues = [];
94
+ let startAt = 0;
95
+ const pageSize = Math.min(maxResults, 100);
96
+ while (allIssues.length < maxResults) {
97
+ const remaining = maxResults - allIssues.length;
98
+ const fetchSize = Math.min(remaining, pageSize);
99
+ const url = `${baseUrl}/rest/api/3/search` +
100
+ `?jql=${encodeURIComponent(jql)}` +
101
+ `&fields=${encodeURIComponent(fields)}` +
102
+ `&startAt=${startAt}` +
103
+ `&maxResults=${fetchSize}`;
104
+ const raw = await httpsGet(url, authHeader);
105
+ const data = JSON.parse(raw);
106
+ if (!data.issues || data.issues.length === 0)
107
+ break;
108
+ allIssues.push(...data.issues);
109
+ startAt += data.issues.length;
110
+ if (startAt >= data.total)
111
+ break;
112
+ }
113
+ return allIssues;
114
+ }
115
+ // ---------------------------------------------------------------------------
116
+ // Extension definition
117
+ // ---------------------------------------------------------------------------
118
+ export default defineExtension({
119
+ name: "pm-jira",
120
+ version: "0.1.0",
121
+ activate(api) {
122
+ // -----------------------------------------------------------------------
123
+ // Command: pm jira sync
124
+ // -----------------------------------------------------------------------
125
+ api.registerCommand({
126
+ name: "jira sync",
127
+ description: "Sync Jira issues into pm items",
128
+ intent: "Import or update pm items from a Jira project using the Jira REST API",
129
+ examples: [
130
+ "pm jira sync --project PROJ",
131
+ "pm jira sync --project PROJ --max-results 200",
132
+ "pm jira sync --jql 'project = PROJ AND assignee = currentUser()'",
133
+ "pm jira sync --project PROJ --status open --dry-run",
134
+ ],
135
+ flags: [
136
+ {
137
+ long: "--project",
138
+ value_name: "KEY",
139
+ description: "Jira project key (e.g. PROJ)",
140
+ },
141
+ {
142
+ long: "--jql",
143
+ value_name: "query",
144
+ description: "Custom JQL query",
145
+ },
146
+ {
147
+ long: "--max-results",
148
+ value_name: "n",
149
+ description: "Max issues to sync (default: 500)",
150
+ },
151
+ {
152
+ long: "--dry-run",
153
+ description: "Preview without writing",
154
+ },
155
+ {
156
+ long: "--status",
157
+ value_name: "filter",
158
+ description: "Filter by pm status (open|in_progress|closed|blocked)",
159
+ },
160
+ ],
161
+ async run(ctx) {
162
+ const project = ctx.options["project"];
163
+ const customJql = ctx.options["jql"];
164
+ const maxResults = ctx.options["max-results"] ?? 500;
165
+ const dryRun = ctx.options["dry-run"] ?? false;
166
+ const statusFilter = ctx.options["status"];
167
+ // Validate env vars
168
+ const baseUrl = process.env["JIRA_BASE_URL"];
169
+ const token = process.env["JIRA_API_TOKEN"];
170
+ const email = process.env["JIRA_EMAIL"];
171
+ if (!baseUrl || !token || !email) {
172
+ console.error("Missing required environment variables. Please set JIRA_BASE_URL, JIRA_API_TOKEN, and JIRA_EMAIL.");
173
+ return { success: false, error: "Missing Jira credentials" };
174
+ }
175
+ if (!project && !customJql) {
176
+ console.error("Provide either --project <KEY> or --jql <query> to specify which issues to sync.");
177
+ return { success: false, error: "No project or JQL specified" };
178
+ }
179
+ const jql = customJql ??
180
+ `project = ${project} AND statusCategory != Done ORDER BY priority ASC`;
181
+ const authHeader = `Basic ${Buffer.from(`${email}:${token}`).toString("base64")}`;
182
+ console.error(`Fetching issues from Jira... (JQL: ${jql})`);
183
+ let issues;
184
+ try {
185
+ issues = await fetchAllJiraIssues(baseUrl.replace(/\/$/, ""), authHeader, jql, maxResults);
186
+ }
187
+ catch (err) {
188
+ const msg = err instanceof Error ? err.message : String(err);
189
+ console.error(`Failed to fetch issues from Jira: ${msg}`);
190
+ return { success: false, error: msg };
191
+ }
192
+ console.error(`Fetched ${issues.length} issues from Jira`);
193
+ // Apply status filter before upsert
194
+ const filtered = statusFilter
195
+ ? issues.filter((issue) => mapJiraStatus(issue.fields.status.name) === statusFilter)
196
+ : issues;
197
+ if (statusFilter && filtered.length !== issues.length) {
198
+ console.error(`Filtered to ${filtered.length} issues with pm status "${statusFilter}"`);
199
+ }
200
+ if (dryRun) {
201
+ console.error(`[dry-run] Would upsert ${filtered.length} items:`);
202
+ for (const issue of filtered.slice(0, 20)) {
203
+ console.error(` ${issue.key}: ${issue.fields.summary} [${mapJiraStatus(issue.fields.status.name)}]`);
204
+ }
205
+ if (filtered.length > 20) {
206
+ console.error(` ... and ${filtered.length - 20} more`);
207
+ }
208
+ return {
209
+ success: true,
210
+ dryRun: true,
211
+ total: filtered.length,
212
+ project: project ?? "custom-jql",
213
+ };
214
+ }
215
+ // Create items via pm CLI
216
+ let upserted = 0;
217
+ for (const issue of filtered) {
218
+ const tags = [
219
+ ...(issue.fields.labels ?? []),
220
+ ...(issue.fields.fixVersions?.map((v) => v.name) ?? []),
221
+ ];
222
+ const result = spawnSync("pm", [
223
+ "--path", ctx.pm_root,
224
+ "create",
225
+ "--title", `[${issue.key}] ${issue.fields.summary}`,
226
+ "--status", mapJiraStatus(issue.fields.status.name),
227
+ "--type", "Issue",
228
+ ...(tags.length > 0 ? ["--tags", tags.join(",")] : []),
229
+ ], { encoding: "utf-8" });
230
+ if (result.status === 0) {
231
+ upserted++;
232
+ }
233
+ }
234
+ const projectLabel = project ?? "custom-jql";
235
+ console.error(`Synced ${upserted} issues from Jira project ${projectLabel}`);
236
+ return {
237
+ success: true,
238
+ synced: upserted,
239
+ total: filtered.length,
240
+ project: projectLabel,
241
+ summary: `Synced ${upserted} issues from Jira project ${projectLabel}`,
242
+ };
243
+ },
244
+ });
245
+ // -----------------------------------------------------------------------
246
+ // Importer: jira-sync
247
+ // -----------------------------------------------------------------------
248
+ api.registerImporter("jira-sync", async (ctx) => {
249
+ const baseUrl = ctx.options["JIRA_BASE_URL"] ??
250
+ process.env["JIRA_BASE_URL"];
251
+ const token = ctx.options["JIRA_API_TOKEN"] ??
252
+ process.env["JIRA_API_TOKEN"];
253
+ const email = ctx.options["JIRA_EMAIL"] ??
254
+ process.env["JIRA_EMAIL"];
255
+ const project = ctx.options["project"];
256
+ const customJql = ctx.options["jql"];
257
+ const maxResults = ctx.options["maxResults"] ?? 500;
258
+ if (!baseUrl || !token || !email) {
259
+ throw new Error("jira-sync importer requires JIRA_BASE_URL, JIRA_API_TOKEN, and JIRA_EMAIL (via options or env)");
260
+ }
261
+ if (!project && !customJql) {
262
+ throw new Error("jira-sync importer requires either options.project or options.jql");
263
+ }
264
+ const jql = customJql ??
265
+ `project = ${project} AND statusCategory != Done ORDER BY priority ASC`;
266
+ const authHeader = `Basic ${Buffer.from(`${email}:${token}`).toString("base64")}`;
267
+ console.error(`[jira-sync] Fetching issues with JQL: ${jql}`);
268
+ const issues = await fetchAllJiraIssues(baseUrl.replace(/\/$/, ""), authHeader, jql, maxResults);
269
+ console.error(`[jira-sync] Importing ${issues.length} issues`);
270
+ for (const issue of issues) {
271
+ const tags = [
272
+ ...(issue.fields.labels ?? []),
273
+ ...(issue.fields.fixVersions?.map((v) => v.name) ?? []),
274
+ ];
275
+ spawnSync("pm", [
276
+ "--path", ctx.pm_root,
277
+ "create",
278
+ "--title", `[${issue.key}] ${issue.fields.summary}`,
279
+ "--status", mapJiraStatus(issue.fields.status.name),
280
+ "--type", "Issue",
281
+ ...(tags.length > 0 ? ["--tags", tags.join(",")] : []),
282
+ ], { encoding: "utf-8" });
283
+ }
284
+ console.error(`[jira-sync] Done. Imported ${issues.length} issues.`);
285
+ });
286
+ },
287
+ });
288
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
package/manifest.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "pm-jira",
3
+ "version": "0.1.0",
4
+ "description": "Jira issue sync for pm-cli",
5
+ "author": "@unbraind",
6
+ "entry": "./dist/index.js",
7
+ "priority": 50,
8
+ "capabilities": [
9
+ "commands",
10
+ "schema",
11
+ "importers",
12
+ "services"
13
+ ],
14
+ "pm": {
15
+ "compatibility": "v2"
16
+ }
17
+ }
package/package.json ADDED
@@ -0,0 +1,88 @@
1
+ {
2
+ "name": "pm-jira",
3
+ "version": "0.1.0",
4
+ "description": "Jira issue sync for pm-cli",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/unbraind/pm-jira.git"
8
+ },
9
+ "bugs": {
10
+ "url": "https://github.com/unbraind/pm-jira/issues"
11
+ },
12
+ "homepage": "https://github.com/unbraind/pm-jira#readme",
13
+ "type": "module",
14
+ "main": "dist/index.js",
15
+ "types": "dist/index.d.ts",
16
+ "files": [
17
+ "dist/",
18
+ "manifest.json",
19
+ "README.md",
20
+ "CHANGELOG.md"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "dev": "tsc --watch",
25
+ "prepack": "npm run build",
26
+ "typecheck": "tsc --noEmit",
27
+ "check": "npm run typecheck",
28
+ "audit:prod": "npm audit --omit=dev",
29
+ "pack:dry-run": "npm pack --dry-run",
30
+ "changelog": "pm-changelog --pm-root .agents/pm --mode prepend --output CHANGELOG.md --release-version-from-package --since-previous-tag --until-release-tag --item-url-base https://github.com/unbraind/pm-jira/blob/main/.agents/pm",
31
+ "changelog:full": "pm-changelog --pm-root .agents/pm --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --item-url-base https://github.com/unbraind/pm-jira/blob/main/.agents/pm",
32
+ "changelog:check": "pm-changelog --pm-root .agents/pm --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --item-url-base https://github.com/unbraind/pm-jira/blob/main/.agents/pm --check",
33
+ "release:check": "npm run typecheck && npm run build && npm run audit:prod && npm run pack:dry-run && npm run changelog:check"
34
+ },
35
+ "peerDependencies": {
36
+ "@unbrained/pm-cli": ">=2026.5.24"
37
+ },
38
+ "devDependencies": {
39
+ "@unbrained/pm-cli": "^2026.5.24",
40
+ "typescript": "^6.0.3",
41
+ "pm-changelog": "^2026.5.25",
42
+ "@types/node": "^25.9.1"
43
+ },
44
+ "keywords": [
45
+ "extension",
46
+ "jira",
47
+ "pm-cli",
48
+ "pm-extension",
49
+ "pm-package",
50
+ "sync"
51
+ ],
52
+ "license": "MIT",
53
+ "engines": {
54
+ "node": ">=20.0.0"
55
+ },
56
+ "author": "@unbraind",
57
+ "pm": {
58
+ "aliases": [
59
+ "jira"
60
+ ],
61
+ "extensions": [
62
+ "."
63
+ ],
64
+ "catalog": {
65
+ "display_name": "Jira Sync",
66
+ "category": "sync",
67
+ "summary": "Jira issue sync for pm-cli",
68
+ "tags": [
69
+ "jira",
70
+ "sync",
71
+ "import"
72
+ ],
73
+ "links": {
74
+ "docs": "https://github.com/unbraind/pm-jira#readme",
75
+ "npm": "https://www.npmjs.com/package/pm-jira",
76
+ "repository": "https://github.com/unbraind/pm-jira",
77
+ "report": "https://github.com/unbraind/pm-jira/issues"
78
+ }
79
+ },
80
+ "docs": [
81
+ "README.md",
82
+ "CHANGELOG.md"
83
+ ],
84
+ "examples": [
85
+ "README.md"
86
+ ]
87
+ }
88
+ }