@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 +10 -0
- package/COMPATIBILITY.md +65 -45
- package/README.md +74 -25
- package/bin/agent-skills.js +6 -0
- package/package.json +5 -5
- package/skills/jira-browser-fetch/SKILL.md +25 -2
- package/skills/jira-browser-fetch/references/usage.md +31 -1
- package/skills/jira-browser-fetch/scripts/jira-browser-fetch.js +92 -5
- package/skills/jira-browser-fetch/scripts/lib.js +43 -0
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
|
-
##
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
### Generic Agent Skills default
|
|
9
|
+
For cross-agent installation, prefer the open Skills CLI:
|
|
20
10
|
|
|
21
11
|
```bash
|
|
22
|
-
npx
|
|
12
|
+
npx skills add aholbreich/agent-skills -g
|
|
23
13
|
```
|
|
24
14
|
|
|
25
|
-
|
|
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
|
|
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
|
-
|
|
27
|
+
## Compatibility matrix
|
|
32
28
|
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
39
|
+
Pi can install this repository as a Pi package directly from npm:
|
|
38
40
|
|
|
39
41
|
```bash
|
|
40
|
-
|
|
42
|
+
pi install npm:@aholbreich/agent-skills
|
|
41
43
|
```
|
|
42
44
|
|
|
43
|
-
|
|
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
|
-
|
|
51
|
+
Temporary Pi run without installing:
|
|
50
52
|
|
|
51
53
|
```bash
|
|
52
|
-
|
|
54
|
+
pi -e npm:@aholbreich/agent-skills
|
|
53
55
|
```
|
|
54
56
|
|
|
55
|
-
|
|
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
|
|
62
|
+
npx @aholbreich/agent-skills
|
|
59
63
|
```
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
This installs to `~/.agents/skills` and is equivalent to:
|
|
62
66
|
|
|
63
67
|
```bash
|
|
64
|
-
npx @aholbreich/agent-skills --target
|
|
68
|
+
npx @aholbreich/agent-skills --target agents
|
|
65
69
|
```
|
|
66
70
|
|
|
67
|
-
|
|
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
|
-
|
|
82
|
+
This fallback copies files. For symlinked, multi-agent installs, prefer `npx skills add aholbreich/agent-skills`.
|
|
74
83
|
|
|
75
|
-
|
|
76
|
-
npx @aholbreich/agent-skills --target project-codex
|
|
77
|
-
```
|
|
84
|
+
## Collision behavior
|
|
78
85
|
|
|
79
|
-
|
|
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
|
-
|
|
82
|
-
npx @aholbreich/agent-skills --target agents
|
|
83
|
-
```
|
|
88
|
+
Common precedence pattern:
|
|
84
89
|
|
|
85
|
-
Project-local
|
|
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
|
-
|
|
88
|
-
|
|
94
|
+
Pi example:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
.pi/skills/jira-browser-fetch/SKILL.md
|
|
89
98
|
```
|
|
90
99
|
|
|
91
|
-
|
|
100
|
+
shadows:
|
|
92
101
|
|
|
93
|
-
```
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
- `
|
|
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
|
-
|
|
18
|
+
Recommended install paths:
|
|
19
19
|
|
|
20
|
-
|
|
|
20
|
+
| Use case | Command |
|
|
21
21
|
|---|---|
|
|
22
|
-
|
|
|
23
|
-
| Pi
|
|
24
|
-
|
|
|
25
|
-
|
|
|
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
|
-
##
|
|
38
|
+
## Recommended install with the Skills CLI
|
|
41
39
|
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
51
|
+
npx skills add aholbreich/agent-skills
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
List available skills without installing:
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
|
|
57
|
+
npx skills add aholbreich/agent-skills --list
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
Non-interactive examples:
|
|
61
61
|
|
|
62
|
-
|
|
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
|
-
|
|
74
|
+
pi install npm:@aholbreich/agent-skills
|
|
66
75
|
```
|
|
67
76
|
|
|
68
|
-
|
|
77
|
+
Project-local Pi package install, useful for teams that already standardize on Pi packages:
|
|
69
78
|
|
|
70
79
|
```bash
|
|
71
|
-
|
|
80
|
+
pi install -l npm:@aholbreich/agent-skills
|
|
72
81
|
```
|
|
73
82
|
|
|
74
|
-
|
|
83
|
+
Try without installing:
|
|
75
84
|
|
|
76
85
|
```bash
|
|
77
|
-
|
|
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
|
|
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
|
|
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:
|
package/bin/agent-skills.js
CHANGED
|
@@ -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.
|
|
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": "
|
|
46
|
-
"pack:dry": "
|
|
47
|
-
"prepack": "
|
|
48
|
-
"prepublishOnly": "
|
|
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 {
|
|
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
|
-
|
|
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
|
};
|