dsh-jira-tasks 1.0.6 → 1.0.7
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/README.en.md +23 -1
- package/README.md +26 -1
- package/lib/client.js +38 -10
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -25,12 +25,18 @@ Published to npm:
|
|
|
25
25
|
dsh plugin --profile web add dsh-jira-tasks
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
Or straight from GitHub (the repository root is the package directory; `lib/` is prebuilt):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
dsh plugin --profile web add github:liu3734/jira-tasks-dsh-plugin
|
|
32
|
+
```
|
|
33
|
+
|
|
28
34
|
**Restart DSH** to activate.
|
|
29
35
|
|
|
30
36
|
<details>
|
|
31
37
|
<summary>Manual install (without npm)</summary>
|
|
32
38
|
|
|
33
|
-
1. Copy the
|
|
39
|
+
1. Copy this repository (its root is the package directory) to `~/.dsh/profiles/web/packages/dsh-jira-tasks/` (skip `.git/`)
|
|
34
40
|
2. Edit `~/.dsh/profiles/web/package.json`:
|
|
35
41
|
- Add to `dependencies`: `"dsh-jira-tasks": "file:./packages/dsh-jira-tasks"`
|
|
36
42
|
- Append to `dsh.profile.bundles`: `"dsh-jira-tasks"`
|
|
@@ -57,6 +63,8 @@ Open **Settings → Plugins → Plugin configuration → JIRA** and fill in:
|
|
|
57
63
|
|
|
58
64
|
Leaving the token blank on save keeps the existing one; clearing the address on save removes the override and falls back to the environment. Auth is auto-detected: tokens containing `:` use Basic, otherwise Bearer (JIRA PAT).
|
|
59
65
|
|
|
66
|
+
> **A token supplied by the environment cannot be overwritten from this card.** If the environment that launched DSH already defines `JIRA_API_TOKEN` (a Windows *user-level* variable counts), DSH treats that reference as read-only: the card disables the token field and explains why. The panel already uses that variable, so **no save is needed**; to manage the token from settings instead, remove the variable first (Windows: System Properties → Environment Variables, or PowerShell `[Environment]::SetEnvironmentVariable('JIRA_API_TOKEN', $null, 'User')`) and restart DSH.
|
|
67
|
+
|
|
60
68
|
#### Connection test
|
|
61
69
|
|
|
62
70
|
The card's footer carries a status light and a **Test connection** button:
|
|
@@ -108,6 +116,20 @@ dsh plugin --profile web remove dsh-jira-tasks
|
|
|
108
116
|
| Cannot parse JIRA response | Network / proxy issue, curl produced no output |
|
|
109
117
|
</details>
|
|
110
118
|
|
|
119
|
+
<details>
|
|
120
|
+
<summary>Saving the token fails with "is supplied read-only by the launching environment"</summary>
|
|
121
|
+
|
|
122
|
+
`JIRA_API_TOKEN` (or `JIRA_TOKEN`) is supplied by the environment that launched DSH, and DSH treats that reference as read-only: a write would be shadowed by the variable, so it is refused. The panel already uses that variable and queries fine, so **there is nothing to save**.
|
|
123
|
+
|
|
124
|
+
To manage the token from the settings card instead, remove the variable and restart DSH:
|
|
125
|
+
|
|
126
|
+
- Windows (PowerShell): `[Environment]::SetEnvironmentVariable('JIRA_API_TOKEN', $null, 'User')`, then reopen the terminal
|
|
127
|
+
- Windows (GUI): System Properties → Advanced → Environment Variables, delete the user variable
|
|
128
|
+
- macOS / Linux: remove the export from `~/.zshrc` / `~/.bashrc` (or equivalent) and reopen the terminal
|
|
129
|
+
|
|
130
|
+
Since v1.0.7 the card detects a read-only token, disables the field, and shows this guidance inline instead of failing on save.
|
|
131
|
+
</details>
|
|
132
|
+
|
|
111
133
|
<details>
|
|
112
134
|
<summary>Panel does not appear</summary>
|
|
113
135
|
|
package/README.md
CHANGED
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
- 👤 默认仅显示当前用户(`assignee = currentUser()`)的「开启 / 重新开启」任务
|
|
17
17
|
- ⚙️ **设置 → 插件 → JIRA** 配置 JIRA 地址与访问令牌(令牌写入凭据存储,不回传前端)
|
|
18
18
|
- 🟢 设置卡片自动探测连接并显示状态灯:绿=可用、红=不可用、灰=未配置;点「测试连接」可用**未保存的草稿值**即时验证
|
|
19
|
+
|
|
20
|
+
<img width="1590" height="1574" alt="image" src="https://github.com/user-attachments/assets/af5f11c6-aa9a-4c3b-84ca-cff6c0017b22" />
|
|
21
|
+
|
|
19
22
|
- ⚙️ 项目 Key 与 JQL 按工作区保存;未配置的工作区显示"未配置"
|
|
20
23
|
- 🔄 打开新会话自动查询,面板内支持一键刷新(⟳)
|
|
21
24
|
- 🧭 点击标题可**收起 / 展开**面板;标题徽标显示查询命中的任务总数(列表最多展示 50 条,按更新时间倒序)
|
|
@@ -31,6 +34,12 @@
|
|
|
31
34
|
dsh plugin --profile web add dsh-jira-tasks
|
|
32
35
|
```
|
|
33
36
|
|
|
37
|
+
或直接从 GitHub 安装(仓库根即包目录,`lib/` 为预构建产物):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
dsh plugin --profile web add github:liu3734/jira-tasks-dsh-plugin
|
|
41
|
+
```
|
|
42
|
+
|
|
34
43
|
**重启 DSH** 后生效。
|
|
35
44
|
|
|
36
45
|
> 若改用 GitHub Packages 源:先在 profile 的 `.npmrc` 配置 `@liu3734:registry=https://npm.pkg.github.com/` 及读取令牌,再执行 `dsh plugin --profile web add @liu3734/dsh-jira-tasks`。
|
|
@@ -38,7 +47,7 @@ dsh plugin --profile web add dsh-jira-tasks
|
|
|
38
47
|
<details>
|
|
39
48
|
<summary>手动安装(不使用 npm)</summary>
|
|
40
49
|
|
|
41
|
-
1.
|
|
50
|
+
1. 将本仓库(仓库根目录即包目录)复制为 `~/.dsh/profiles/web/packages/dsh-jira-tasks/`(可忽略 `.git/`)
|
|
42
51
|
2. 编辑 `~/.dsh/profiles/web/package.json`:
|
|
43
52
|
- `dependencies` 增加:`"dsh-jira-tasks": "file:./packages/dsh-jira-tasks"`
|
|
44
53
|
- `dsh.profile.bundles` 追加:`"dsh-jira-tasks"`
|
|
@@ -65,6 +74,8 @@ dsh plugin --profile web add dsh-jira-tasks
|
|
|
65
74
|
|
|
66
75
|
留空并保存会保持已有令牌不变;地址留空并保存则清除设置项,回退到环境变量。认证自动识别:令牌含 `:` 用 Basic,否则用 Bearer(JIRA PAT)。
|
|
67
76
|
|
|
77
|
+
> **令牌已由环境变量提供时,设置页无法改写它**:若启动 DSH 的环境里已设置 `JIRA_API_TOKEN`(Windows 用户级环境变量也算),DSH 会将该引用视为只读,卡片会禁用令牌输入并说明原因。此时面板已直接使用该环境变量,**无需保存**;要改由设置页管理,请先移除环境变量(Windows:系统属性 → 环境变量,或 PowerShell `[Environment]::SetEnvironmentVariable('JIRA_API_TOKEN', $null, 'User')`)后重启 DSH。
|
|
78
|
+
|
|
68
79
|
#### 连接测试
|
|
69
80
|
|
|
70
81
|
卡片底部有连接状态灯与 **测试连接** 按钮:
|
|
@@ -119,6 +130,20 @@ dsh plugin --profile web remove dsh-jira-tasks
|
|
|
119
130
|
| 无法解析 JIRA 响应:… | 网络 / 代理问题,curl 无输出 |
|
|
120
131
|
</details>
|
|
121
132
|
|
|
133
|
+
<details>
|
|
134
|
+
<summary>保存令牌报 “is supplied read-only by the launching environment”</summary>
|
|
135
|
+
|
|
136
|
+
`JIRA_API_TOKEN`(或 `JIRA_TOKEN`)已由启动 DSH 的环境提供,DSH 判定该引用只读:写入会被环境变量遮蔽,因此拒绝保存。此时面板已经直接使用该环境变量,能正常查询,**无需在设置页保存**。
|
|
137
|
+
|
|
138
|
+
如需改由设置页管理令牌,先移除环境变量再重启 DSH:
|
|
139
|
+
|
|
140
|
+
- Windows(PowerShell):`[Environment]::SetEnvironmentVariable('JIRA_API_TOKEN', $null, 'User')`,然后重开终端
|
|
141
|
+
- Windows(图形界面):系统属性 → 高级 → 环境变量,删除对应用户变量
|
|
142
|
+
- macOS / Linux:从 `~/.zshrc` / `~/.bashrc` 等启动脚本中移除后重开终端
|
|
143
|
+
|
|
144
|
+
v1.0.7 起卡片会检测只读令牌并直接禁用输入框、在卡片内给出上述提示,不再等到保存才报英文错误。
|
|
145
|
+
</details>
|
|
146
|
+
|
|
122
147
|
<details>
|
|
123
148
|
<summary>面板不显示</summary>
|
|
124
149
|
|
package/lib/client.js
CHANGED
|
@@ -288,6 +288,18 @@ window.__ModuleLoader__.load({
|
|
|
288
288
|
var TOKEN_REF = "JIRA_API_TOKEN";
|
|
289
289
|
var TOKEN_REFS = ["JIRA_API_TOKEN", "JIRA_TOKEN"];
|
|
290
290
|
|
|
291
|
+
// credentials-local 拒绝写入“由启动环境提供”的引用时,原始信息是英文的;这里取出引用名并给出可操作的中文说明。
|
|
292
|
+
function shadowedTokenRef(message) {
|
|
293
|
+
var m = /"([^"]+)" is supplied read-only by the launching environment/.exec(String(message || ""));
|
|
294
|
+
return m ? m[1] : "";
|
|
295
|
+
}
|
|
296
|
+
function tokenReadOnlyHint(ref) {
|
|
297
|
+
var name = ref || TOKEN_REF;
|
|
298
|
+
return "令牌由启动 DSH 的环境变量 " + name + " 提供(只读),面板已直接使用,无需在此保存。"
|
|
299
|
+
+ "如需改由设置页管理,请先移除该环境变量并重启 DSH;Windows 可在 PowerShell 执行 "
|
|
300
|
+
+ "[Environment]::SetEnvironmentVariable('" + name + "', $null, 'User') 后重开终端。";
|
|
301
|
+
}
|
|
302
|
+
|
|
291
303
|
function useScopeSnapshot(scope) {
|
|
292
304
|
var state = React.useState(function () { return scope.getSnapshot(); });
|
|
293
305
|
var snapshot = state[0], setSnapshot = state[1];
|
|
@@ -303,15 +315,20 @@ window.__ModuleLoader__.load({
|
|
|
303
315
|
function createJiraSettingsCard(scope, credentials) {
|
|
304
316
|
function readTokenInfo() {
|
|
305
317
|
return credentials.describe(TOKEN_REFS).then(function (res) {
|
|
306
|
-
if (!res || !res.ok || !res.value) return { configured: false, writable:
|
|
318
|
+
if (!res || !res.ok || !res.value) return { configured: false, writable: true };
|
|
307
319
|
for (var i = 0; i < TOKEN_REFS.length; i++) {
|
|
308
|
-
var
|
|
309
|
-
|
|
320
|
+
var ref = TOKEN_REFS[i];
|
|
321
|
+
var info = res.value[ref];
|
|
322
|
+
// 命中的第一个引用即生效来源;writable 为 false 表示只读(由启动环境提供),写不进去。
|
|
323
|
+
if (info && info.configured) {
|
|
324
|
+
return { configured: true, writable: info.writable !== false, ref: ref };
|
|
325
|
+
}
|
|
310
326
|
}
|
|
311
327
|
var primary = res.value[TOKEN_REF];
|
|
312
|
-
return { configured: false, writable: primary ? primary.writable !== false : true };
|
|
328
|
+
return { configured: false, writable: primary ? primary.writable !== false : true, ref: TOKEN_REF };
|
|
313
329
|
}).catch(function () {
|
|
314
|
-
|
|
330
|
+
// 状态读取失败不阻断保存,交由写入路径给出真实错误。
|
|
331
|
+
return { configured: false, writable: true };
|
|
315
332
|
});
|
|
316
333
|
}
|
|
317
334
|
|
|
@@ -347,6 +364,9 @@ window.__ModuleLoader__.load({
|
|
|
347
364
|
var baseValue = baseEdit === undefined ? storedBase : baseEdit;
|
|
348
365
|
var dirty = (baseEdit !== undefined && baseEdit !== storedBase) || (tokenDraft || "").length > 0;
|
|
349
366
|
var writable = snapshot.writable !== false;
|
|
367
|
+
// 令牌可能来自启动环境(只读):此时禁用输入并说明原因,而不是等到保存才报 DSH 的英文错误。
|
|
368
|
+
var tokenWritable = !tokenInfo || tokenInfo.writable !== false;
|
|
369
|
+
var tokenReadOnly = !!(tokenInfo && tokenInfo.configured && tokenInfo.writable === false);
|
|
350
370
|
|
|
351
371
|
// 命名空间未挂载时不显示,避免留下一张无法操作的卡片。
|
|
352
372
|
if (snapshot.status === "unavailable") return null;
|
|
@@ -360,6 +380,11 @@ window.__ModuleLoader__.load({
|
|
|
360
380
|
tasks.push(baseEdit === "" ? scope.unset("baseUrl") : scope.set("baseUrl", baseEdit));
|
|
361
381
|
}
|
|
362
382
|
var token = (tokenDraft || "").trim();
|
|
383
|
+
if (token && !tokenWritable) {
|
|
384
|
+
setBusy(false);
|
|
385
|
+
setFailed(tokenReadOnlyHint(tokenInfo && tokenInfo.ref));
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
363
388
|
if (token) {
|
|
364
389
|
tasks.push(credentials.set(TOKEN_REF, token).then(function (res) {
|
|
365
390
|
if (res && res.ok === false) {
|
|
@@ -377,7 +402,8 @@ window.__ModuleLoader__.load({
|
|
|
377
402
|
setBusy(false);
|
|
378
403
|
}).catch(function (err) {
|
|
379
404
|
setBusy(false);
|
|
380
|
-
|
|
405
|
+
var shadowed = shadowedTokenRef(err && err.message);
|
|
406
|
+
setFailed(shadowed ? tokenReadOnlyHint(shadowed) : String((err && err.message) || err));
|
|
381
407
|
});
|
|
382
408
|
}
|
|
383
409
|
|
|
@@ -404,7 +430,9 @@ window.__ModuleLoader__.load({
|
|
|
404
430
|
|
|
405
431
|
var tokenHint = tokenInfo === null
|
|
406
432
|
? "正在读取令牌状态…"
|
|
407
|
-
: (
|
|
433
|
+
: (tokenReadOnly
|
|
434
|
+
? tokenReadOnlyHint(tokenInfo.ref)
|
|
435
|
+
: (tokenInfo.configured ? "令牌已配置;留空并保存可保持不变。" : "令牌未配置。含 “:” 时用 Basic,否则用 Bearer。"));
|
|
408
436
|
var dotClass = probe.phase === "ok" ? "jt-dot jt-dot-ok"
|
|
409
437
|
: probe.phase === "fail" ? "jt-dot jt-dot-fail"
|
|
410
438
|
: probe.phase === "testing" ? "jt-dot jt-dot-testing" : "jt-dot";
|
|
@@ -433,9 +461,9 @@ window.__ModuleLoader__.load({
|
|
|
433
461
|
className: "jt-input",
|
|
434
462
|
type: "password",
|
|
435
463
|
value: tokenDraft,
|
|
436
|
-
placeholder: tokenInfo && tokenInfo.configured ? "已配置,留空保持不变" : "粘贴令牌",
|
|
464
|
+
placeholder: tokenReadOnly ? "由环境变量提供(只读)" : (tokenInfo && tokenInfo.configured ? "已配置,留空保持不变" : "粘贴令牌"),
|
|
437
465
|
autoComplete: "off",
|
|
438
|
-
disabled: !writable || busy,
|
|
466
|
+
disabled: !writable || busy || !tokenWritable,
|
|
439
467
|
onChange: function (e) { setTokenDraft(e.target.value); },
|
|
440
468
|
onKeyDown: function (e) { if (e.key === "Enter") save(); }
|
|
441
469
|
})
|
|
@@ -455,7 +483,7 @@ window.__ModuleLoader__.load({
|
|
|
455
483
|
onClick: function () { runProbe({ baseUrl: baseValue, token: (tokenDraft || "").trim() }); }
|
|
456
484
|
}, probe.phase === "testing" ? "测试中…" : "测试连接"),
|
|
457
485
|
h("button", { className: "jt-btn", disabled: !dirty || busy, onClick: discard }, "放弃"),
|
|
458
|
-
h("button", { className: "jt-btn jt-btn-primary", disabled: !dirty || busy || !writable, onClick: save }, busy ? "保存中…" : "保存")
|
|
486
|
+
h("button", { className: "jt-btn jt-btn-primary", disabled: !dirty || busy || !writable || ((tokenDraft || "").trim().length > 0 && !tokenWritable), onClick: save }, busy ? "保存中…" : "保存")
|
|
459
487
|
)
|
|
460
488
|
);
|
|
461
489
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-jira-tasks",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "JIRA open tasks panel for DeepSeek Harness (DSH): shows the current user's open/reopened issues below the composer, per-workspace project key, persistent profile bundle.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|