@aholbreich/agent-skills 0.2.3 → 0.4.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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ Added:
6
+
7
+ - `jira-browser-fetch --backlog URL|BOARD_ID` to fetch all issues from a Jira Software board backlog through the authenticated browser session.
8
+ - Backlog manifests at `raw/jira-board-<board-id>-backlog.json` and a `backlogs` section in `raw/jira-browser-fetch-run.json`.
9
+ - Documentation examples for natural-language user requests that should invoke the skills.
10
+ - Recommended `npx skills add aholbreich/agent-skills -g` cross-agent install path, plus collision/update guidance for Pi and project-local overrides.
11
+ - CI/package dry-run scripts that use `npm pack --dry-run` for compatibility with older local pnpm launchers.
12
+
3
13
  ## 0.1.0 - 2026-05-06
4
14
 
5
15
  Initial public package structure.
package/COMPATIBILITY.md CHANGED
@@ -4,96 +4,111 @@ This package is designed as a pure [Agent Skills](https://agentskills.io/) packa
4
4
 
5
5
  Each bundled skill is a directory containing `SKILL.md` plus scripts and references. The frontmatter follows the Agent Skills conventions: required `name` and `description`, directory name matching the skill name, lowercase hyphenated names, and optional `license`/`compatibility` metadata.
6
6
 
7
- ## Compatibility matrix
8
-
9
- | Tool / Harness | Status | Install method |
10
- |---|---:|---|
11
- | Pi | Supported and tested | `pi install npm:@aholbreich/agent-skills` or `npx @aholbreich/agent-skills --target pi` |
12
- | Claude Code | Compatible Agent Skills layout | `npx @aholbreich/agent-skills --target claude` or copy `skills/*` into Claude's skills directory |
13
- | OpenAI Codex | Compatible Agent Skills layout | `npx @aholbreich/agent-skills --target codex` or copy `skills/*` into Codex's skills directory |
14
- | OpenClaw / generic Agent Skills harnesses | Compatible Agent Skills layout | `npx @aholbreich/agent-skills --target agents` or copy `skills/*` into `.agents/skills` / configured skills directory |
15
- | Any Agent Skills-compatible tool | Compatible layout | Copy each folder under `skills/` into the tool's configured skills directory |
7
+ ## Recommended installer
16
8
 
17
- ## Install commands
18
-
19
- ### Generic Agent Skills default
9
+ For cross-agent installation, prefer the open Skills CLI:
20
10
 
21
11
  ```bash
22
- npx @aholbreich/agent-skills
12
+ npx skills add aholbreich/agent-skills -g
23
13
  ```
24
14
 
25
- This installs to `~/.agents/skills` and is equivalent to:
15
+ The Skills CLI discovers `skills/*/SKILL.md`, supports many agent clients, and symlinks agent-specific installs to a managed source by default. Use `--copy` only when symlinks are not supported.
16
+
17
+ Useful variants:
26
18
 
27
19
  ```bash
28
- npx @aholbreich/agent-skills --target agents
20
+ npx skills add aholbreich/agent-skills --list
21
+ npx skills add aholbreich/agent-skills # project-local/team install
22
+ npx skills add aholbreich/agent-skills -g -y # non-interactive global install
23
+ npx skills update -g # update global skills installed by the Skills CLI
24
+ npx skills list -g # list global skills
29
25
  ```
30
26
 
31
- ### Pi global
27
+ ## Compatibility matrix
32
28
 
33
- ```bash
34
- pi install npm:@aholbreich/agent-skills
35
- ```
29
+ | Tool / Harness | Status | Recommended install method |
30
+ |---|---:|---|
31
+ | Pi | Supported and tested | `pi install npm:@aholbreich/agent-skills` for Pi-managed package updates, or `npx skills add aholbreich/agent-skills -g` for cross-agent installs |
32
+ | Claude Code | Compatible Agent Skills layout | `npx skills add aholbreich/agent-skills -g --agent claude-code` |
33
+ | OpenAI Codex | Compatible Agent Skills layout | `npx skills add aholbreich/agent-skills -g --agent codex` |
34
+ | OpenClaw / generic Agent Skills harnesses | Compatible Agent Skills layout | `npx skills add aholbreich/agent-skills -g` or install to `.agents/skills` |
35
+ | Any Agent Skills-compatible tool | Compatible layout | Copy or symlink each folder under `skills/` into the tool's configured skills directory |
36
+
37
+ ## Pi-native install commands
36
38
 
37
- or:
39
+ Pi can install this repository as a Pi package directly from npm:
38
40
 
39
41
  ```bash
40
- npx @aholbreich/agent-skills --target pi
42
+ pi install npm:@aholbreich/agent-skills
41
43
  ```
42
44
 
43
- ### Pi project-local
45
+ Project-local Pi package install:
44
46
 
45
47
  ```bash
46
48
  pi install -l npm:@aholbreich/agent-skills
47
49
  ```
48
50
 
49
- or:
51
+ Temporary Pi run without installing:
50
52
 
51
53
  ```bash
52
- npx @aholbreich/agent-skills --target project
54
+ pi -e npm:@aholbreich/agent-skills
53
55
  ```
54
56
 
55
- ### Claude Code
57
+ ## Package fallback installer
58
+
59
+ The npm package also ships a small dependency-free installer for environments where the Skills CLI is not available:
56
60
 
57
61
  ```bash
58
- npx @aholbreich/agent-skills --target claude
62
+ npx @aholbreich/agent-skills
59
63
  ```
60
64
 
61
- Project-local Claude-style install:
65
+ This installs to `~/.agents/skills` and is equivalent to:
62
66
 
63
67
  ```bash
64
- npx @aholbreich/agent-skills --target project-claude
68
+ npx @aholbreich/agent-skills --target agents
65
69
  ```
66
70
 
67
- ### Codex
71
+ Other targets:
68
72
 
69
73
  ```bash
74
+ npx @aholbreich/agent-skills --target pi
75
+ npx @aholbreich/agent-skills --target claude
70
76
  npx @aholbreich/agent-skills --target codex
77
+ npx @aholbreich/agent-skills --target project
78
+ npx @aholbreich/agent-skills --target project-agents
79
+ npx @aholbreich/agent-skills install --dir /path/to/skills
71
80
  ```
72
81
 
73
- Project-local Codex-style install:
82
+ This fallback copies files. For symlinked, multi-agent installs, prefer `npx skills add aholbreich/agent-skills`.
74
83
 
75
- ```bash
76
- npx @aholbreich/agent-skills --target project-codex
77
- ```
84
+ ## Collision behavior
78
85
 
79
- ### Generic `.agents/skills`
86
+ Agent Skills are identified by their `name` frontmatter. If the same skill name exists in more than one discovered location, agents apply their own precedence rules.
80
87
 
81
- ```bash
82
- npx @aholbreich/agent-skills --target agents
83
- ```
88
+ Common precedence pattern:
84
89
 
85
- Project-local generic install:
90
+ 1. Project-local skills override user/global skills.
91
+ 2. User/global skills override bundled/system skills.
92
+ 3. Duplicate names are not merged.
86
93
 
87
- ```bash
88
- npx @aholbreich/agent-skills --target project-agents
94
+ Pi example:
95
+
96
+ ```text
97
+ .pi/skills/jira-browser-fetch/SKILL.md
89
98
  ```
90
99
 
91
- ### Custom skills directory
100
+ shadows:
92
101
 
93
- ```bash
94
- npx @aholbreich/agent-skills install --dir /path/to/skills
102
+ ```text
103
+ ~/.nvm/.../@aholbreich/agent-skills/skills/jira-browser-fetch/SKILL.md
95
104
  ```
96
105
 
106
+ That is useful for intentional repo-specific overrides, but it also means package updates may not affect the active skill in that repository. If you see a collision warning, choose one source of truth:
107
+
108
+ - Keep the project-local skill if the repository intentionally customizes it.
109
+ - Remove the project-local copy if you want the package/global install to be active.
110
+ - Re-run the installer/update command for the install method that owns the active copy.
111
+
97
112
  ## Discoverability
98
113
 
99
114
  The package is tagged for discovery with npm keywords including:
@@ -106,7 +121,11 @@ The package is tagged for discovery with npm keywords including:
106
121
  - `claude-code`
107
122
  - `codex`
108
123
 
109
- After publishing to npm, tools and indexes that crawl npm packages for Agent Skills-compatible packages, such as skills registries, should be able to discover the package from its package metadata and conventional `skills/` directory.
124
+ The repository is also compatible with the Skills CLI GitHub shorthand:
125
+
126
+ ```bash
127
+ npx skills add aholbreich/agent-skills --list
128
+ ```
110
129
 
111
130
  If a registry requires manual submission, use:
112
131
 
@@ -114,6 +133,7 @@ If a registry requires manual submission, use:
114
133
  Package: @aholbreich/agent-skills
115
134
  Repository: https://github.com/aholbreich/agent-skills
116
135
  Skills directory: skills/
136
+ Install command: npx skills add aholbreich/agent-skills -g
117
137
  ```
118
138
 
119
139
  ## Compliance checks in this repo
@@ -129,6 +149,6 @@ That includes:
129
149
  - JavaScript syntax checks.
130
150
  - Unit tests.
131
151
  - Skill frontmatter compliance checks.
132
- - `pnpm pack --dry-run` package content check.
152
+ - `npm pack --dry-run` package content check.
133
153
 
134
154
  The compliance tests are intentionally local and dependency-free; they validate the parts of the Agent Skills structure that matter for broad tool compatibility.
package/README.md CHANGED
@@ -8,25 +8,23 @@ This repository is a pure skills package. It currently contains browser-authenti
8
8
 
9
9
  | Skill | Purpose |
10
10
  |---|---|
11
- | [`jira-browser-fetch`](skills/jira-browser-fetch/) | Fetch Jira issue JSON, rendered HTML/XML, linked/referenced issues, JQL result sets, and attachments through an authenticated Chrome session. |
11
+ | [`jira-browser-fetch`](skills/jira-browser-fetch/) | Fetch Jira issue JSON, rendered HTML/XML, linked/referenced issues, Jira Software board backlogs, JQL result sets, and attachments through an authenticated Chrome session. |
12
12
  | [`confluence-browser-fetch`](skills/confluence-browser-fetch/) | Fetch Confluence page JSON, storage/view HTML, browser HTML, descendants, CQL result sets, and attachments through an authenticated Chrome session. |
13
13
 
14
14
  ## Compatibility
15
15
 
16
16
  This repository follows the Agent Skills directory convention: each skill lives under `skills/<skill-name>/SKILL.md` with matching frontmatter.
17
17
 
18
- Supported install targets:
18
+ Recommended install paths:
19
19
 
20
- | Target | Command |
20
+ | Use case | Command |
21
21
  |---|---|
22
- | Pi | `pi install npm:@aholbreich/agent-skills` |
23
- | Pi via npx | `npx @aholbreich/agent-skills --target pi` |
24
- | Claude Code-style global skills | `npx @aholbreich/agent-skills --target claude` |
25
- | Codex-style global skills | `npx @aholbreich/agent-skills --target codex` |
26
- | OpenClaw / generic `.agents/skills` | `npx @aholbreich/agent-skills --target agents` |
27
- | Project-local generic skills | `npx @aholbreich/agent-skills --target project-agents` |
22
+ | Cross-agent wizard (recommended) | `npx skills add aholbreich/agent-skills -g` |
23
+ | Pi package-managed install | `pi install npm:@aholbreich/agent-skills` |
24
+ | Project-local/team skills | `npx skills add aholbreich/agent-skills` |
25
+ | Package fallback without the aggregator | `npx @aholbreich/agent-skills` |
28
26
 
29
- See [`COMPATIBILITY.md`](COMPATIBILITY.md) for details.
27
+ See [`COMPATIBILITY.md`](COMPATIBILITY.md) for details, including collision behavior.
30
28
 
31
29
  ## Requirements
32
30
 
@@ -37,52 +35,74 @@ See [`COMPATIBILITY.md`](COMPATIBILITY.md) for details.
37
35
 
38
36
  No npm runtime dependencies are required.
39
37
 
40
- ## Install with Pi
38
+ ## Recommended install with the Skills CLI
41
39
 
42
- From GitHub:
40
+ For most users, use the open `skills` installer. It discovers the skills in this repository, prompts for compatible agents, and symlinks agent-specific installs to a single managed source by default.
41
+
42
+ Global/user install:
43
43
 
44
44
  ```bash
45
- pi install git:github.com/aholbreich/agent-skills
45
+ npx skills add aholbreich/agent-skills -g
46
46
  ```
47
47
 
48
48
  Project-local install, useful for teams:
49
49
 
50
50
  ```bash
51
- pi install -l git:github.com/aholbreich/agent-skills
51
+ npx skills add aholbreich/agent-skills
52
52
  ```
53
53
 
54
- Try without installing:
54
+ List available skills without installing:
55
55
 
56
56
  ```bash
57
- pi -e git:github.com/aholbreich/agent-skills
57
+ npx skills add aholbreich/agent-skills --list
58
58
  ```
59
59
 
60
- ## One-shot install with npx
60
+ Non-interactive examples:
61
61
 
62
- Install bundled skills into the generic Agent Skills directory `~/.agents/skills`:
62
+ ```bash
63
+ npx skills add aholbreich/agent-skills -g --skill '*' -y
64
+ npx skills add aholbreich/agent-skills -g --agent claude-code --agent codex --skill jira-browser-fetch -y
65
+ ```
66
+
67
+ Use `--copy` only when symlinks are not supported in your environment.
68
+
69
+ ## Pi-native install
70
+
71
+ If you only use Pi and want Pi to manage package updates, install the npm package directly:
63
72
 
64
73
  ```bash
65
- npx @aholbreich/agent-skills
74
+ pi install npm:@aholbreich/agent-skills
66
75
  ```
67
76
 
68
- This is equivalent to:
77
+ Project-local Pi package install, useful for teams that already standardize on Pi packages:
69
78
 
70
79
  ```bash
71
- npx @aholbreich/agent-skills --target agents
80
+ pi install -l npm:@aholbreich/agent-skills
72
81
  ```
73
82
 
74
- Install into a project-local `.pi/skills` directory:
83
+ Try without installing:
75
84
 
76
85
  ```bash
77
- npx @aholbreich/agent-skills install --target project
86
+ pi -e npm:@aholbreich/agent-skills
87
+ ```
88
+
89
+ ## Package fallback with npx
90
+
91
+ If you cannot use the `skills` aggregator, this package also ships a small installer. It copies bundled skills into a selected skills directory.
92
+
93
+ Install bundled skills into the generic Agent Skills directory `~/.agents/skills`:
94
+
95
+ ```bash
96
+ npx @aholbreich/agent-skills
78
97
  ```
79
98
 
80
- Install for Claude Code, Codex, or generic Agent Skills harnesses:
99
+ Install for a specific target:
81
100
 
82
101
  ```bash
102
+ npx @aholbreich/agent-skills install --target agents
83
103
  npx @aholbreich/agent-skills install --target claude
84
104
  npx @aholbreich/agent-skills install --target codex
85
- npx @aholbreich/agent-skills install --target agents
105
+ npx @aholbreich/agent-skills install --target project
86
106
  ```
87
107
 
88
108
  Overwrite existing installed skill directories:
@@ -97,6 +117,18 @@ List bundled skills:
97
117
  npx @aholbreich/agent-skills list
98
118
  ```
99
119
 
120
+ ## Collision and update notes
121
+
122
+ Avoid installing the same skill into multiple locations for the same agent unless you intentionally want one copy to shadow another. Most agents give project-local skills priority over user/global skills.
123
+
124
+ For example, in Pi a project skill at `.pi/skills/jira-browser-fetch/SKILL.md` shadows the same skill installed from `npm:@aholbreich/agent-skills`. In that case `pi update` updates the package, but the active project-local copy remains unchanged.
125
+
126
+ Recommended rule of thumb:
127
+
128
+ - Cross-agent users: prefer `npx skills add aholbreich/agent-skills -g`.
129
+ - Pi-only users: prefer `pi install npm:@aholbreich/agent-skills`.
130
+ - Team/repo-specific overrides: commit project-local skills intentionally and update them intentionally.
131
+
100
132
  ## Manual install
101
133
 
102
134
  ```bash
@@ -170,6 +202,23 @@ jira-browser-fetch \
170
202
  --jql 'assignee = currentUser() ORDER BY updated DESC'
171
203
  ```
172
204
 
205
+ Fetch a Jira Software board backlog:
206
+
207
+ ```bash
208
+ jira-browser-fetch \
209
+ --server https://example.atlassian.net \
210
+ --raw-dir ./raw \
211
+ --backlog 'https://example.atlassian.net/jira/software/c/projects/ABC/boards/42/backlog?epics=visible'
212
+ ```
213
+
214
+ Example user requests that should invoke this skill:
215
+
216
+ - "Fetch all Jira issues from this backlog URL into `raw/`."
217
+ - "Archive board 42's Jira backlog for my LLM wiki."
218
+ - "Fetch `PROJ-123` through my browser session and include linked issues."
219
+ - "Pull my assigned Jira issues without asking me for an API token."
220
+ - "Use this JQL and store the raw Jira evidence under the wiki raw folder."
221
+
173
222
  ## Confluence examples
174
223
 
175
224
  Fetch one page by URL:
@@ -27,6 +27,11 @@ function usage() {
27
27
 
28
28
  Install this package's Agent Skills into a local skills directory.
29
29
 
30
+ Recommended cross-agent installer:
31
+ npx skills add aholbreich/agent-skills -g
32
+
33
+ This fallback installer copies files for environments where the Skills CLI is unavailable.
34
+
30
35
  Commands:
31
36
  install Install skills (default command)
32
37
  list List bundled skills
@@ -40,6 +45,7 @@ Options for install:
40
45
  --dry-run Show what would be copied without writing
41
46
 
42
47
  Examples:
48
+ npx skills add aholbreich/agent-skills -g
43
49
  npx @aholbreich/agent-skills
44
50
  npx @aholbreich/agent-skills install --target agents --force
45
51
  npx @aholbreich/agent-skills install --target pi --force
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aholbreich/agent-skills",
3
- "version": "0.2.3",
3
+ "version": "0.4.0",
4
4
  "description": "Handcrafted Agent Skills for browser-authenticated Jira and Confluence ingestion, LLM wiki workflows, and developer automation.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -42,10 +42,10 @@
42
42
  "scripts": {
43
43
  "check": "node --check bin/agent-skills.js && node --check skills/jira-browser-fetch/scripts/jira-browser-fetch.js && node --check skills/jira-browser-fetch/scripts/lib.js && node --check skills/confluence-browser-fetch/scripts/confluence-browser-fetch.js && node --check skills/confluence-browser-fetch/scripts/lib.js",
44
44
  "test": "node --test",
45
- "ci": "pnpm run check && pnpm test && pnpm pack --dry-run",
46
- "pack:dry": "pnpm pack --dry-run",
47
- "prepack": "pnpm run check",
48
- "prepublishOnly": "pnpm run check && pnpm test"
45
+ "ci": "npm run check && npm test && npm pack --dry-run",
46
+ "pack:dry": "npm pack --dry-run",
47
+ "prepack": "npm run check",
48
+ "prepublishOnly": "npm run check && npm test"
49
49
  },
50
50
  "pi": {
51
51
  "skills": [
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: jira-browser-fetch
3
- description: Fetch Jira issue raw data through an authenticated Chrome browser session when jira-cli/API tokens do not work, especially with Microsoft/SSO. Use to archive Jira issues, linked tickets, rendered HTML/XML, remote links, and attachments into a raw wiki folder.
3
+ description: Fetch Jira issue raw data through an authenticated Chrome browser session when jira-cli/API tokens do not work, especially with Microsoft/SSO. Use to archive Jira issues, Jira Software board backlogs, JQL result sets, linked tickets, rendered HTML/XML, remote links, and attachments into a raw wiki folder.
4
4
  license: MIT
5
5
  compatibility: Agent Skills standard. Tested with Pi; installable into Claude Code, Codex, OpenClaw/generic .agents skills directories. Requires Node.js 22+ with built-in fetch/WebSocket and Google Chrome/Chromium with remote debugging. No npm dependencies.
6
6
  ---
7
7
 
8
8
  # Jira Browser Fetch
9
9
 
10
- Use this skill when Jira API-token authentication fails or the organization uses Microsoft/SSO and the user wants Jira issues archived into a local raw/wiki folder.
10
+ Use this skill when Jira API-token authentication fails or the organization uses Microsoft/SSO and the user wants Jira issues, Jira Software board backlogs, or JQL result sets archived into a local raw/wiki folder.
11
11
 
12
12
  The bundled script opens/reuses Chrome with a dedicated profile, lets the user complete SSO once, extracts Jira cookies via Chrome DevTools, and fetches Jira REST/HTML/XML/attachments into a raw directory.
13
13
 
@@ -33,12 +33,23 @@ Important options:
33
33
  --depth N recursion depth for connected tickets
34
34
  --scan-text find issue keys in JSON/XML/HTML text, not only formal Jira links
35
35
  --jql JQL search Jira with JQL and fetch all matching issues
36
+ --backlog URL|ID fetch all issues from a Jira Software board backlog URL or board id
36
37
  --assignee-me fetch all issues assigned to current Jira user
37
38
  --max-attachment-size S skip attachment files larger than S (default 5mb; use unlimited to disable)
38
39
  --prefix A,B,C only follow keys with these project prefixes
39
40
  --wait SEC SSO/session wait timeout per issue
40
41
  ```
41
42
 
43
+ ## Example User Requests
44
+
45
+ Use this skill for user requests like:
46
+
47
+ - "Fetch Jira issue `PROJ-123` into `raw/` through my browser session."
48
+ - "Archive this Jira backlog for my LLM wiki: `https://example.atlassian.net/jira/software/c/projects/ABC/boards/42/backlog?epics=visible`."
49
+ - "Fetch all Jira issues matching this JQL into the wiki raw folder."
50
+ - "Pull my assigned Jira issues without asking me for an API token."
51
+ - "Fetch this ticket and all linked tickets, including attachments under the default size limit."
52
+
42
53
  ## Typical Workflow
43
54
 
44
55
  1. Identify raw directory.
@@ -64,6 +75,12 @@ scripts/jira-browser-fetch.js \
64
75
  --server https://example.atlassian.net \
65
76
  --raw-dir ./raw \
66
77
  --assignee-me
78
+
79
+ # Fetch every issue currently visible in a Jira Software board backlog:
80
+ scripts/jira-browser-fetch.js \
81
+ --server https://example.atlassian.net \
82
+ --raw-dir ./raw \
83
+ --backlog 'https://example.atlassian.net/jira/software/c/projects/ABC/boards/42/backlog?epics=visible'
67
84
  ```
68
85
 
69
86
  ## Output Layout
@@ -88,6 +105,12 @@ A run manifest is written to:
88
105
  raw/jira-browser-fetch-run.json
89
106
  ```
90
107
 
108
+ Backlog fetches also write:
109
+
110
+ ```text
111
+ raw/jira-board-<board-id>-backlog.json
112
+ ```
113
+
91
114
  ## Installation / PATH
92
115
 
93
116
  The skill can be used directly by path. Optionally install a convenience symlink:
@@ -80,6 +80,26 @@ scripts/jira-browser-fetch.js \
80
80
  --jql "assignee = currentUser() AND statusCategory != Done ORDER BY updated DESC"
81
81
  ```
82
82
 
83
+ Fetch every issue currently visible in a Jira Software board backlog:
84
+
85
+ ```bash
86
+ scripts/jira-browser-fetch.js \
87
+ --server https://example.atlassian.net \
88
+ --raw-dir /path/to/wiki/raw \
89
+ --backlog 'https://example.atlassian.net/jira/software/c/projects/ABC/boards/42/backlog?epics=visible'
90
+ ```
91
+
92
+ If you already know the board id, this is equivalent:
93
+
94
+ ```bash
95
+ scripts/jira-browser-fetch.js \
96
+ --server https://example.atlassian.net \
97
+ --raw-dir /path/to/wiki/raw \
98
+ --backlog 42
99
+ ```
100
+
101
+ A backlog fetch writes `raw/jira-board-<board-id>-backlog.json` with the ordered backlog issue keys and adds a `backlogs` section to `raw/jira-browser-fetch-run.json`.
102
+
83
103
  Use a shorter wait when the browser session is already logged in:
84
104
 
85
105
  ```bash
@@ -102,11 +122,21 @@ Default max attachment download size is `5mb`. Use `--max-attachment-size unlimi
102
122
  | `JIRA_RAW_DIR` | Default output raw directory |
103
123
  | `JIRA_CHROME_DEBUG_PORT` | Chrome DevTools port, default `9223` |
104
124
  | `JIRA_FETCH_WAIT_SEC` | Wait timeout per issue, default `900` |
105
- | `JIRA_MAX_SEARCH_RESULTS` | Max issues added per JQL search, default `1000` |
125
+ | `JIRA_MAX_SEARCH_RESULTS` | Max issues added per JQL or backlog search, default `1000` |
106
126
  | `JIRA_MAX_ATTACHMENT_SIZE` / `JIRA_MAX_ATTACHMENT_BYTES` | Max attachment download size, default `5mb`; skipped files are listed in `attachments.json` |
107
127
  | `JIRA_CHROME_PROFILE` | Dedicated Chrome profile dir |
108
128
  | `CHROME` | Chrome executable path |
109
129
 
130
+ ## Example user requests
131
+
132
+ Agents should invoke this skill for requests such as:
133
+
134
+ - "Fetch all Jira issues from this backlog URL into `/raw`."
135
+ - "Archive board 42's Jira backlog for my LLM wiki."
136
+ - "Fetch my assigned Jira issues through the browser because API tokens do not work."
137
+ - "Fetch `PROJ-123` and all connected tickets with attachments."
138
+ - "Use this JQL and store the raw Jira evidence under the wiki raw folder."
139
+
110
140
  ## Troubleshooting
111
141
 
112
142
  ### `no Jira cookies yet`
@@ -6,7 +6,15 @@ const fsp = require('fs/promises');
6
6
  const os = require('os');
7
7
  const path = require('path');
8
8
  const { spawn } = require('child_process');
9
- const { parseSize, formatBytes, safeName, issueKeysFromText } = require('./lib');
9
+ const {
10
+ parseSize,
11
+ formatBytes,
12
+ safeName,
13
+ issueKeysFromText,
14
+ parseBacklogInput,
15
+ backlogApiUrl,
16
+ issueKeysFromAgilePage,
17
+ } = require('./lib');
10
18
 
11
19
  function usage() {
12
20
  console.log(`Usage: jira-browser-fetch [ISSUE-KEY ...] [options]
@@ -21,8 +29,9 @@ Options:
21
29
  --depth N Connected fetch depth (default: 1 with --connected, otherwise 0)
22
30
  --scan-text Include issue keys found anywhere in issue JSON/XML/HTML text
23
31
  --jql JQL Search Jira with JQL and fetch all matching issues
32
+ --backlog URL|BOARD_ID Fetch all issues from a Jira Software board backlog URL or board id
24
33
  --assignee-me Fetch all issues assigned to current Jira user
25
- --max-search-results N Max issues to add per JQL search (default: 1000)
34
+ --max-search-results N Max issues to add per JQL/backlog search (default: 1000)
26
35
  --max-attachment-size S Skip attachment downloads larger than S (default: 5mb; use unlimited to disable)
27
36
  --prefix A,B,C Only fetch referenced keys with these project prefixes
28
37
  --wait SEC Wait time for SSO/session per issue (default: 900)
@@ -37,7 +46,8 @@ Examples:
37
46
  jira-browser-fetch SWING-4770 --raw-dir /path/wiki/raw
38
47
  jira-browser-fetch SWING-4770 --connected --prefix SWING,SSD,EC --raw-dir ./raw
39
48
  jira-browser-fetch --assignee-me --raw-dir ./raw
40
- JIRA_SERVER=https://example.atlassian.net jira-browser-fetch PROJ-123 --connected
49
+ jira-browser-fetch --backlog 'https://example.atlassian.net/jira/software/c/projects/ABC/boards/42/backlog?epics=visible' --raw-dir ./raw
50
+ JIRA_SERVER=https://example.atlassian.net jira-browser-fetch --backlog 42 --connected
41
51
  `);
42
52
  }
43
53
 
@@ -51,6 +61,7 @@ const opts = {
51
61
  depth: undefined,
52
62
  scanText: false,
53
63
  jqls: [],
64
+ backlogs: [],
54
65
  assigneeMe: false,
55
66
  maxSearchResults: Number(process.env.JIRA_MAX_SEARCH_RESULTS || 1000),
56
67
  maxAttachmentBytes: parseSize(process.env.JIRA_MAX_ATTACHMENT_SIZE || process.env.JIRA_MAX_ATTACHMENT_BYTES || '5mb'),
@@ -70,6 +81,7 @@ for (let i = 2; i < process.argv.length; i++) {
70
81
  else if (a === '--depth') opts.depth = Number(process.argv[++i]);
71
82
  else if (a === '--scan-text') opts.scanText = true;
72
83
  else if (a === '--jql') opts.jqls.push(process.argv[++i]);
84
+ else if (a === '--backlog') opts.backlogs.push(process.argv[++i]);
73
85
  else if (a === '--assignee-me') opts.assigneeMe = true;
74
86
  else if (a === '--max-search-results') opts.maxSearchResults = Number(process.argv[++i]);
75
87
  else if (a === '--max-attachment-size') opts.maxAttachmentBytes = parseSize(process.argv[++i]);
@@ -84,7 +96,7 @@ for (let i = 2; i < process.argv.length; i++) {
84
96
  else { console.error(`Unknown argument: ${a}`); process.exit(2); }
85
97
  }
86
98
 
87
- if (!issues.length && !opts.jqls.length && !opts.assigneeMe) { usage(); process.exit(2); }
99
+ if (!issues.length && !opts.jqls.length && !opts.backlogs.length && !opts.assigneeMe) { usage(); process.exit(2); }
88
100
  if (opts.assigneeMe) opts.jqls.push('assignee = currentUser() ORDER BY updated DESC');
89
101
  if (opts.depth === undefined) opts.depth = opts.connected ? 1 : 0;
90
102
  if (opts.depth > 0) opts.connected = true;
@@ -259,6 +271,65 @@ async function searchJql(jql) {
259
271
  return [...new Set(found)];
260
272
  }
261
273
 
274
+ async function fetchBacklogPageWithWait(url) {
275
+ const deadline = Date.now() + opts.waitSec * 1000;
276
+ let last = '';
277
+ while (Date.now() < deadline) {
278
+ try {
279
+ const cookie = await getCookieHeader();
280
+ if (!cookie) {
281
+ last = 'no Jira cookies yet';
282
+ } else {
283
+ const result = await fetchJson(url, cookie, 'application/json');
284
+ if (result.status === 200 && result.json && Array.isArray(result.json.issues)) return result.json;
285
+ last = `HTTP ${result.status} ${(result.text || '').slice(0, 180).replace(/\s+/g, ' ')}`;
286
+ }
287
+ } catch (e) { last = e.message; }
288
+ process.stdout.write(`\r${new Date().toLocaleTimeString()} waiting for authenticated Jira backlog session: ${last.padEnd(120).slice(0, 120)}`);
289
+ await sleep(3000);
290
+ }
291
+ process.stdout.write('\n');
292
+ throw new Error(`Could not fetch Jira backlog. Last result: ${last}`);
293
+ }
294
+
295
+ async function searchBacklog(input) {
296
+ const backlog = parseBacklogInput(input, opts.server);
297
+ await ensureBrowser(backlog.browseUrl);
298
+ console.log(`If prompted in Chrome, complete SSO for: ${backlog.browseUrl}`);
299
+ console.log(`Waiting up to ${opts.waitSec}s for Jira backlog access...`);
300
+
301
+ const found = [];
302
+ let startAt = 0;
303
+ const pageSize = Math.min(100, Math.max(1, opts.maxSearchResults || 1000));
304
+
305
+ while (found.length < opts.maxSearchResults) {
306
+ const limit = Math.min(pageSize, opts.maxSearchResults - found.length);
307
+ const url = backlogApiUrl(opts.server, backlog.boardId, startAt, limit);
308
+ const page = await fetchBacklogPageWithWait(url);
309
+ const keys = issueKeysFromAgilePage(page);
310
+ for (const key of keys) found.push(key);
311
+ console.log(`Fetched backlog page board=${backlog.boardId} startAt=${startAt}, issues=${keys.length}${typeof page.total === 'number' ? `, total=${page.total}` : ''}`);
312
+ if (page.isLast === true) break;
313
+ if (typeof page.total === 'number' && startAt + keys.length >= page.total) break;
314
+ if (!keys.length) break;
315
+ startAt += keys.length;
316
+ }
317
+
318
+ const keys = [...new Set(found)];
319
+ const manifest = {
320
+ fetchedAt: new Date().toISOString(),
321
+ server: opts.server,
322
+ boardId: backlog.boardId,
323
+ source: backlog.source,
324
+ browseUrl: backlog.browseUrl,
325
+ endpoint: `/rest/agile/1.0/board/${backlog.boardId}/backlog`,
326
+ issueCount: keys.length,
327
+ issues: keys,
328
+ };
329
+ await fsp.writeFile(path.join(opts.rawDir, `jira-board-${backlog.boardId}-backlog.json`), JSON.stringify(manifest, null, 2));
330
+ return manifest;
331
+ }
332
+
262
333
  function addKey(set, key) {
263
334
  if (!key) return;
264
335
  key = String(key).toUpperCase();
@@ -455,6 +526,22 @@ async function main() {
455
526
  const seen = new Set();
456
527
  const failed = [];
457
528
  const searches = [];
529
+ const backlogs = [];
530
+
531
+ for (const backlogInput of opts.backlogs) {
532
+ console.log(`\n===== Fetching Jira backlog: ${backlogInput} =====`);
533
+ try {
534
+ const backlog = await searchBacklog(backlogInput);
535
+ backlogs.push(backlog);
536
+ console.log(`Backlog board ${backlog.boardId} matched ${backlog.issueCount} issue(s): ${backlog.issues.join(' ') || '(none)'}`);
537
+ for (const key of backlog.issues) {
538
+ if (!queue.some(q => q.key === key)) queue.push({ key, depth: 0, from: `Backlog board ${backlog.boardId}` });
539
+ }
540
+ } catch (e) {
541
+ failed.push({ key: `BACKLOG: ${backlogInput}`, error: e.message });
542
+ console.error(`BACKLOG FAILED: ${e.message}`);
543
+ }
544
+ }
458
545
 
459
546
  for (const jql of opts.jqls) {
460
547
  console.log(`\n===== Searching JQL: ${jql} =====`);
@@ -489,7 +576,7 @@ async function main() {
489
576
  }
490
577
  }
491
578
 
492
- const runMeta = { fetchedAt: new Date().toISOString(), server: opts.server, rawDir: opts.rawDir, requested: issues, searches, fetched: [...seen].filter(k => !failed.some(f => f.key === k)), failed };
579
+ const runMeta = { fetchedAt: new Date().toISOString(), server: opts.server, rawDir: opts.rawDir, requested: issues, searches, backlogs, fetched: [...seen].filter(k => !failed.some(f => f.key === k)), failed };
493
580
  await fsp.writeFile(path.join(opts.rawDir, 'jira-browser-fetch-run.json'), JSON.stringify(runMeta, null, 2));
494
581
 
495
582
  if (failed.length) {
@@ -40,6 +40,46 @@ function shouldSkipAttachment(size, maxAttachmentBytes) {
40
40
  return Number.isFinite(n) && n > maxAttachmentBytes;
41
41
  }
42
42
 
43
+ function parseBacklogInput(input, server = '') {
44
+ if (!input) throw new Error('Missing Jira backlog URL or board id');
45
+ const value = String(input).trim();
46
+ const numeric = value.match(/^\d+$/);
47
+ if (numeric) {
48
+ return {
49
+ boardId: Number(value),
50
+ source: value,
51
+ browseUrl: server ? `${String(server).replace(/\/$/, '')}/jira/software/c/boards/${value}/backlog` : value,
52
+ };
53
+ }
54
+
55
+ let url;
56
+ try {
57
+ url = new URL(value);
58
+ } catch {
59
+ throw new Error(`Invalid Jira backlog URL or board id: ${input}`);
60
+ }
61
+
62
+ const m = url.pathname.match(/\/boards\/(\d+)(?:\/backlog)?\b/);
63
+ if (!m) throw new Error(`Could not parse Jira board id from backlog URL: ${input}`);
64
+
65
+ return {
66
+ boardId: Number(m[1]),
67
+ source: value,
68
+ browseUrl: value,
69
+ };
70
+ }
71
+
72
+ function backlogApiUrl(server, boardId, startAt, maxResults) {
73
+ const base = String(server || '').replace(/\/$/, '');
74
+ const params = new URLSearchParams({ startAt: String(startAt), maxResults: String(maxResults) });
75
+ return `${base}/rest/agile/1.0/board/${boardId}/backlog?${params}`;
76
+ }
77
+
78
+ function issueKeysFromAgilePage(page) {
79
+ const issues = page && Array.isArray(page.issues) ? page.issues : [];
80
+ return issues.map(issue => issue && issue.key).filter(Boolean);
81
+ }
82
+
43
83
  module.exports = {
44
84
  DEFAULT_MAX_ATTACHMENT_BYTES,
45
85
  parseSize,
@@ -47,4 +87,7 @@ module.exports = {
47
87
  safeName,
48
88
  issueKeysFromText,
49
89
  shouldSkipAttachment,
90
+ parseBacklogInput,
91
+ backlogApiUrl,
92
+ issueKeysFromAgilePage,
50
93
  };