@kendoo.agentdesk/agentdesk 0.18.1 → 0.18.2
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 +5 -0
- package/cli/tracker-check.mjs +61 -50
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,11 @@ All user-facing changes to AgentDesk. Each entry is tagged:
|
|
|
8
8
|
|
|
9
9
|
Internal refactors, infrastructure changes, and architectural notes are not listed here.
|
|
10
10
|
|
|
11
|
+
## [0.18.2] — 2026-04-18
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- `[CLI]` Jira tracker check no longer blocks on a 404 from the `mypermissions` endpoint (some tenants don't expose it). Auth verification now lives in the `/myself` call; `mypermissions` is best-effort and only reports missing permissions if the tenant returns them. A 404 on `/myself` itself still fails loudly — that's a real configuration problem.
|
|
15
|
+
|
|
11
16
|
## [0.18.1] — 2026-04-18
|
|
12
17
|
|
|
13
18
|
### Fixed
|
package/cli/tracker-check.mjs
CHANGED
|
@@ -98,68 +98,79 @@ async function checkJira({ baseUrl, project }, creds) {
|
|
|
98
98
|
// produce `...net//rest/...` which some Atlassian paths reject.
|
|
99
99
|
const cleanBase = String(baseUrl || "").replace(/\/+$/, "");
|
|
100
100
|
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
101
|
+
// Primary check: /myself. If this works, the tenant + auth are fine.
|
|
102
|
+
// Try v3 first, fall back to v2 on 404. This is what we report to the
|
|
103
|
+
// user as "auth works"; mypermissions is now a best-effort follow-up.
|
|
104
|
+
let myselfRes = null;
|
|
105
|
+
let lastUrl = "";
|
|
106
|
+
for (const v of ["3", "2"]) {
|
|
107
|
+
lastUrl = `${cleanBase}/rest/api/${v}/myself`;
|
|
108
|
+
try {
|
|
109
|
+
myselfRes = await fetch(lastUrl, {
|
|
110
|
+
headers: { Authorization: auth, Accept: "application/json" },
|
|
111
|
+
signal: AbortSignal.timeout(10000),
|
|
112
|
+
});
|
|
113
|
+
if (myselfRes.status !== 404) break;
|
|
114
|
+
} catch (e) {
|
|
115
|
+
if (e.name === "AbortError" || e.name === "TimeoutError") {
|
|
116
|
+
return { ok: false, errors: [`Cannot reach Jira at ${cleanBase} — request timed out`] };
|
|
117
|
+
}
|
|
118
|
+
return { ok: false, errors: [`Cannot reach Jira at ${cleanBase}: ${e.message}`] };
|
|
110
119
|
}
|
|
120
|
+
}
|
|
121
|
+
if (!myselfRes) return { ok: false, errors: [`Cannot reach Jira at ${cleanBase}`] };
|
|
122
|
+
if (myselfRes.status === 401) {
|
|
123
|
+
return { ok: false, errors: ["Jira authentication failed — check JIRA_EMAIL and JIRA_API_TOKEN"] };
|
|
124
|
+
}
|
|
125
|
+
if (myselfRes.status === 403) {
|
|
126
|
+
return { ok: false, errors: ["Jira access forbidden — your account may lack access to this tenant"] };
|
|
127
|
+
}
|
|
128
|
+
if (myselfRes.status === 404) {
|
|
129
|
+
return { ok: false, errors: [`Jira API not found at ${cleanBase} (tried /rest/api/3/myself and /rest/api/2/myself). Confirm the base URL is the Atlassian tenant root and Jira is enabled on this tenant.`] };
|
|
130
|
+
}
|
|
131
|
+
if (!myselfRes.ok) {
|
|
132
|
+
return { ok: false, errors: [`Jira API error (${myselfRes.status}) calling ${lastUrl}`] };
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
const me = await myselfRes.json();
|
|
136
|
+
identity = { name: me.displayName || email, email: me.emailAddress || email, id: me.accountId };
|
|
111
137
|
} catch {}
|
|
112
138
|
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
//
|
|
116
|
-
const permissionsToCheck = "BROWSE_PROJECTS,CREATE_ISSUES,EDIT_ISSUES,ADD_COMMENTS,TRANSITION_ISSUES";
|
|
117
|
-
const tryVersions = ["3", "2"];
|
|
118
|
-
let res = null;
|
|
119
|
-
let lastUrl = "";
|
|
139
|
+
// Best-effort permission check. If it 404s or otherwise fails, we log the
|
|
140
|
+
// specific perms we COULD verify and return ok — the user's auth works;
|
|
141
|
+
// any missing permission will surface when the agent tries the operation.
|
|
120
142
|
try {
|
|
121
|
-
|
|
143
|
+
const permissionsToCheck = "BROWSE_PROJECTS,CREATE_ISSUES,EDIT_ISSUES,ADD_COMMENTS,TRANSITION_ISSUES";
|
|
144
|
+
let permRes = null;
|
|
145
|
+
for (const v of ["3", "2"]) {
|
|
122
146
|
const url = `${cleanBase}/rest/api/${v}/mypermissions?permissions=${permissionsToCheck}` +
|
|
123
147
|
(project ? `&projectKey=${project}` : "");
|
|
124
|
-
|
|
125
|
-
res = await fetch(url, {
|
|
148
|
+
permRes = await fetch(url, {
|
|
126
149
|
headers: { Authorization: auth, Accept: "application/json" },
|
|
127
150
|
signal: AbortSignal.timeout(10000),
|
|
128
151
|
});
|
|
129
|
-
if (
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (res.status === 401) {
|
|
133
|
-
return { ok: false, errors: ["Jira authentication failed — check JIRA_EMAIL and JIRA_API_TOKEN"] };
|
|
134
|
-
}
|
|
135
|
-
if (res.status === 403) {
|
|
136
|
-
return { ok: false, errors: ["Jira access forbidden — your account may lack access to this project"] };
|
|
137
|
-
}
|
|
138
|
-
if (!res.ok) {
|
|
139
|
-
return { ok: false, errors: [`Jira API error (${res.status}) calling ${lastUrl} — check that the base URL is the Atlassian tenant root (e.g. https://yourco.atlassian.net) without a path.`] };
|
|
152
|
+
if (permRes.status !== 404) break;
|
|
140
153
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
errors.push(`Missing permission: ${label} (${key})`);
|
|
154
|
+
if (permRes && permRes.ok) {
|
|
155
|
+
const data = await permRes.json();
|
|
156
|
+
const perms = data.permissions || {};
|
|
157
|
+
const permMap = {
|
|
158
|
+
BROWSE_PROJECTS: "read tasks",
|
|
159
|
+
CREATE_ISSUES: "create tasks",
|
|
160
|
+
EDIT_ISSUES: "update tasks",
|
|
161
|
+
ADD_COMMENTS: "add comments",
|
|
162
|
+
TRANSITION_ISSUES: "change task status",
|
|
163
|
+
};
|
|
164
|
+
for (const [key, label] of Object.entries(permMap)) {
|
|
165
|
+
if (perms[key] && !perms[key].havePermission) {
|
|
166
|
+
errors.push(`Missing permission: ${label} (${key})`);
|
|
167
|
+
}
|
|
156
168
|
}
|
|
157
169
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return { ok: false, errors: [`Cannot reach Jira at ${cleanBase}: ${e.message}`] };
|
|
170
|
+
// If mypermissions failed, silently skip — agent will hit real errors
|
|
171
|
+
// when it tries an operation, which is more accurate anyway.
|
|
172
|
+
} catch {
|
|
173
|
+
// Ignore — auth already verified via /myself above.
|
|
163
174
|
}
|
|
164
175
|
|
|
165
176
|
return { ok: errors.length === 0, errors, identity };
|