@windypro-rourou/dsh-logcat 0.4.2 → 0.5.0-preview.1
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.md +13 -0
- package/lib/client.js +22 -6
- package/lib/index.js +61 -10
- package/package.json +48 -48
package/README.md
CHANGED
|
@@ -48,6 +48,19 @@ dsh plugin --profile web update # 升到当前 major 内最新
|
|
|
48
48
|
# 或强制最新:dsh plugin --profile web add @windypro-rourou/dsh-logcat@latest
|
|
49
49
|
# 更新后重启 GUI(dsh web)生效
|
|
50
50
|
|
|
51
|
+
# 尝鲜 preview 版(日常迭代高频更新,可能不稳定):
|
|
52
|
+
dsh plugin --profile web add @windypro-rourou/dsh-logcat@preview
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 发布策略(main / preview 双通道)
|
|
56
|
+
|
|
57
|
+
- **`main` 分支 + npm `latest` 标签**:稳定正式版,**低频发布**,每次至少凑够 3-4 个功能再发,
|
|
58
|
+
避免频繁更新提醒打扰用户。
|
|
59
|
+
- **`preview` 分支 + npm `preview` 标签**:日常迭代,有啥更啥(高频),供尝鲜用户测试;
|
|
60
|
+
凑够足够功能后合并回 `main` 批量发布正式版。
|
|
61
|
+
- 版本自检会按安装通道提示(正式版用户只看 `latest`,preview 用户只看 `preview`,互不打扰)。
|
|
62
|
+
|
|
63
|
+
```bash
|
|
51
64
|
# 方式二(源码本地链接,实时生效无需重启):把插件链进 web profile,
|
|
52
65
|
# 并在 ~/.dsh/profiles/web/cordis.patch.yml 增加一行:
|
|
53
66
|
pnpm --dir "%USERPROFILE%\.dsh\profiles\web" add link:F:\dsh-logcat
|
package/lib/client.js
CHANGED
|
@@ -35,8 +35,10 @@ window.__ModuleLoader__.load({
|
|
|
35
35
|
[data-dsh-logcat-entry] .lc-entry-label { font-size: 13px; line-height: 1.2; opacity: .92; }
|
|
36
36
|
.dsh-logcat-view { position: fixed; top: 0; right: 0; bottom: 0; width: min(620px, 94vw); display: flex; flex-direction: column; background: var(--lc-bg, #ffffff); border-left: 1px solid rgba(128,128,128,.3); box-shadow: -10px 0 28px rgba(0,0,0,.18); z-index: 9999; }
|
|
37
37
|
.dsh-logcat-view[hidden] { display: none !important; }
|
|
38
|
-
.dsh-logcat-resize { position: absolute; left: -
|
|
39
|
-
.dsh-logcat-resize:
|
|
38
|
+
.dsh-logcat-resize { position: absolute; left: -6px; top: 0; bottom: 0; width: 12px; cursor: col-resize; z-index: 2; display: flex; align-items: center; justify-content: center; }
|
|
39
|
+
.dsh-logcat-resize::before { content: ""; width: 3px; height: 48px; border-radius: 2px; background: rgba(128,128,128,.35); transition: background .15s, height .15s; }
|
|
40
|
+
.dsh-logcat-resize:hover::before, .dsh-logcat-resize[data-drag]::before { background: rgba(128,128,128,.75); height: 72px; }
|
|
41
|
+
.dsh-logcat-resize:hover, .dsh-logcat-resize[data-drag] { background: rgba(128,128,128,.16); }
|
|
40
42
|
.lc-panel { display: flex; flex-direction: column; height: 100%; min-height: 0; font-family: -apple-system, "Segoe UI", "Microsoft YaHei", sans-serif; }
|
|
41
43
|
.lc-header { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid rgba(128,128,128,.25); flex: none; }
|
|
42
44
|
.lc-back { border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 4px 8px; border-radius: 6px; font-size: 13px; }
|
|
@@ -117,6 +119,8 @@ window.__ModuleLoader__.load({
|
|
|
117
119
|
const [currentVersion, setCurrentVersion] = useState("");
|
|
118
120
|
const [latestVersion, setLatestVersion] = useState("");
|
|
119
121
|
const [updateAvailable, setUpdateAvailable] = useState(false);
|
|
122
|
+
const [updateKind, setUpdateKind] = useState("");
|
|
123
|
+
const [updateHint, setUpdateHint] = useState("");
|
|
120
124
|
const [level, setLevel] = useState("");
|
|
121
125
|
const [keyword, setKeyword] = useState("");
|
|
122
126
|
const [autoScroll, setAutoScroll] = useState(true);
|
|
@@ -255,6 +259,8 @@ window.__ModuleLoader__.load({
|
|
|
255
259
|
setCurrentVersion(body.currentVersion ?? "");
|
|
256
260
|
setLatestVersion(body.latestVersion ?? "");
|
|
257
261
|
setUpdateAvailable(body.updateAvailable === true);
|
|
262
|
+
setUpdateKind(body.updateKind ?? "");
|
|
263
|
+
setUpdateHint(body.updateHint ?? "");
|
|
258
264
|
devicesRef.current = body.devices ?? [];
|
|
259
265
|
if (serialRef.current === "" || !(body.devices ?? []).some((d) => d.serial === serialRef.current)) {
|
|
260
266
|
const first = (body.devices ?? []).find((d) => d.state === "device");
|
|
@@ -457,9 +463,9 @@ window.__ModuleLoader__.load({
|
|
|
457
463
|
h("span", null, "显示 " + filtered.length + " / 缓冲 " + entries.length + " 行"),
|
|
458
464
|
h("span", { title: "插件版本" }, "v" + (currentVersion || "?")),
|
|
459
465
|
updateAvailable === true
|
|
460
|
-
? h("span", { style: { color: "#fbc02d" } },
|
|
461
|
-
h("b", null,
|
|
462
|
-
"(dsh plugin --profile web update 后重启 GUI)")
|
|
466
|
+
? h("span", { style: { color: updateKind === "preview" ? "#4fc3f7" : "#fbc02d" } },
|
|
467
|
+
h("b", null, updateHint || "有新版本"),
|
|
468
|
+
updateKind === "preview" ? "(preview 尝鲜版)" : "(dsh plugin --profile web update 后重启 GUI)")
|
|
463
469
|
: null,
|
|
464
470
|
currentPackage !== ""
|
|
465
471
|
? h("span", { title: "当前测试应用包名(agent 通过 logcat_set_package 设置)" }, "测试: " + currentPackage)
|
|
@@ -661,6 +667,16 @@ window.__ModuleLoader__.load({
|
|
|
661
667
|
};
|
|
662
668
|
const onDown = (e) => {
|
|
663
669
|
e.preventDefault();
|
|
670
|
+
if (drag !== null) return;
|
|
671
|
+
// double-click on the handle resets to the default width
|
|
672
|
+
const now = Date.now();
|
|
673
|
+
if (now - (handle?._lastClick ?? 0) < 350) {
|
|
674
|
+
handle._lastClick = 0;
|
|
675
|
+
container.style.width = Math.min(DEFAULT_WIDTH, Math.max(MIN_WIDTH, window.innerWidth - 80)) + "px";
|
|
676
|
+
try { localStorage.setItem("dsh-logcat-width", String(Math.min(DEFAULT_WIDTH, Math.max(MIN_WIDTH, window.innerWidth - 80)))); } catch { /* private */ }
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
handle._lastClick = now;
|
|
664
680
|
drag = { startX: e.clientX, startWidth: container.getBoundingClientRect().width };
|
|
665
681
|
handle?.setAttribute("data-drag", "");
|
|
666
682
|
window.addEventListener("mousemove", onMove);
|
|
@@ -680,7 +696,7 @@ window.__ModuleLoader__.load({
|
|
|
680
696
|
container.hidden = true; // side-drawer: hidden until the sidebar entry is clicked
|
|
681
697
|
handle = document.createElement("div");
|
|
682
698
|
handle.className = "dsh-logcat-resize";
|
|
683
|
-
handle.title = "
|
|
699
|
+
handle.title = "拖拽调整宽度(双击重置)";
|
|
684
700
|
handle.addEventListener("mousedown", onDown);
|
|
685
701
|
container.appendChild(handle);
|
|
686
702
|
document.body.appendChild(container);
|
package/lib/index.js
CHANGED
|
@@ -25,22 +25,65 @@ import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
|
25
25
|
/** This package's manifest (name + version), read from the installed location. */
|
|
26
26
|
const OWN_MANIFEST = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
|
|
27
27
|
|
|
28
|
-
/** Latest published
|
|
29
|
-
let latestVersion = null
|
|
28
|
+
/** Latest published versions per dist-tag (cached 1h; null until first check). */
|
|
29
|
+
let latestVersion = null // dist-tags.latest (stable)
|
|
30
|
+
let previewVersion = null // dist-tags.preview (experimental)
|
|
30
31
|
let lastVersionCheck = 0
|
|
31
32
|
|
|
32
|
-
/**
|
|
33
|
+
/** Simple semver compare: 1 when a > b, -1 when a < b, 0 equal. Prerelease < release. */
|
|
34
|
+
function semverCompare(a, b) {
|
|
35
|
+
const parse = (v) => {
|
|
36
|
+
const m = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/.exec(v ?? '')
|
|
37
|
+
return m ? { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]), pre: m[4] ?? null } : null
|
|
38
|
+
}
|
|
39
|
+
const pa = parse(a)
|
|
40
|
+
const pb = parse(b)
|
|
41
|
+
if (pa === null || pb === null) return 0
|
|
42
|
+
for (const key of ['major', 'minor', 'patch']) {
|
|
43
|
+
if (pa[key] !== pb[key]) return pa[key] > pb[key] ? 1 : -1
|
|
44
|
+
}
|
|
45
|
+
if (pa.pre === pb.pre) return 0
|
|
46
|
+
if (pa.pre === null) return 1 // release > prerelease
|
|
47
|
+
if (pb.pre === null) return -1
|
|
48
|
+
return pa.pre > pb.pre ? 1 : -1
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Refresh the cached npm dist-tags of this package (offline-safe). */
|
|
33
52
|
async function ensureVersionCheck() {
|
|
34
|
-
if (latestVersion !== null && Date.now() - lastVersionCheck < 3600_000) return
|
|
53
|
+
if ((latestVersion !== null || previewVersion !== null) && Date.now() - lastVersionCheck < 3600_000) return
|
|
35
54
|
lastVersionCheck = Date.now()
|
|
36
55
|
try {
|
|
37
|
-
const res = await fetch(`https://registry.npmjs.org/${encodeURIComponent(OWN_MANIFEST.name)}/
|
|
56
|
+
const res = await fetch(`https://registry.npmjs.org/-/package/${encodeURIComponent(OWN_MANIFEST.name)}/dist-tags`, {
|
|
38
57
|
signal: AbortSignal.timeout(8000),
|
|
39
58
|
})
|
|
40
|
-
if (res.ok)
|
|
59
|
+
if (res.ok) {
|
|
60
|
+
const tags = await res.json()
|
|
61
|
+
latestVersion = tags.latest ?? null
|
|
62
|
+
previewVersion = tags.preview ?? null
|
|
63
|
+
}
|
|
41
64
|
} catch { /* offline / registry unreachable — keep whatever we had */ }
|
|
42
65
|
}
|
|
43
66
|
|
|
67
|
+
/** Whether this install is a prerelease (preview line). */
|
|
68
|
+
const IS_PREVIEW = OWN_MANIFEST.version.includes('-')
|
|
69
|
+
|
|
70
|
+
/** The update hint for the current install, or null when up to date. */
|
|
71
|
+
function updateHint() {
|
|
72
|
+
if (IS_PREVIEW) {
|
|
73
|
+
if (previewVersion !== null && semverCompare(previewVersion, OWN_MANIFEST.version) > 0) {
|
|
74
|
+
return { kind: 'preview', version: previewVersion, text: `新 preview 版本 ${previewVersion} 可更新(npm 标签 preview;正式版 ${latestVersion ?? '?'} 未受影响)` }
|
|
75
|
+
}
|
|
76
|
+
if (previewVersion === null && latestVersion !== null && semverCompare(latestVersion, OWN_MANIFEST.version) > 0) {
|
|
77
|
+
return { kind: 'stable', version: latestVersion, text: `正式版 ${latestVersion} 已发布,可切回稳定版` }
|
|
78
|
+
}
|
|
79
|
+
return null
|
|
80
|
+
}
|
|
81
|
+
if (latestVersion !== null && semverCompare(latestVersion, OWN_MANIFEST.version) > 0) {
|
|
82
|
+
return { kind: 'stable', version: latestVersion, text: `新版本 ${latestVersion} 可更新` }
|
|
83
|
+
}
|
|
84
|
+
return null
|
|
85
|
+
}
|
|
86
|
+
|
|
44
87
|
/** Stable cordis plugin name. */
|
|
45
88
|
export const name = 'logcat'
|
|
46
89
|
|
|
@@ -78,9 +121,12 @@ function logcatGuidance(engine) {
|
|
|
78
121
|
const pkgLine = engine.currentPackage !== ''
|
|
79
122
|
? `当前测试应用包名:${engine.currentPackage}(logcat_recent 默认按它过滤日志)。`
|
|
80
123
|
: ''
|
|
81
|
-
const versionLine =
|
|
82
|
-
|
|
83
|
-
|
|
124
|
+
const versionLine = (() => {
|
|
125
|
+
const hint = updateHint()
|
|
126
|
+
if (hint === null) return ''
|
|
127
|
+
const tag = IS_PREVIEW ? 'preview' : 'stable'
|
|
128
|
+
return `dsh-logcat 更新提醒(${tag} 通道):${hint.text}(升级:dsh plugin --profile web update 或 add @windypro-rourou/dsh-logcat@${hint.kind === 'preview' ? 'preview' : 'latest'},然后重启 GUI)。`
|
|
129
|
+
})()
|
|
84
130
|
return `${LOGCAT_GUIDANCE}\n${deviceLine}${pkgLine !== '' ? `\n${pkgLine}` : ''}${versionLine !== '' ? `\n${versionLine}` : ''}`
|
|
85
131
|
}
|
|
86
132
|
}
|
|
@@ -507,6 +553,7 @@ function makeRoutes(engine) {
|
|
|
507
553
|
if (!isLoopbackRequest(req)) { writeJson(res, 403, { error: 'forbidden: loopback-only' }); return }
|
|
508
554
|
if ((req.method ?? 'GET') !== 'GET') { writeJson(res, 405, { error: 'method not allowed' }); return }
|
|
509
555
|
await ensureVersionCheck()
|
|
556
|
+
const hint = updateHint()
|
|
510
557
|
writeJson(res, 200, {
|
|
511
558
|
adbPath: engine.adb,
|
|
512
559
|
adbVersion: engine.adbVersion,
|
|
@@ -516,7 +563,11 @@ function makeRoutes(engine) {
|
|
|
516
563
|
currentPackage: engine.currentPackage,
|
|
517
564
|
currentVersion: OWN_MANIFEST.version,
|
|
518
565
|
latestVersion,
|
|
519
|
-
|
|
566
|
+
previewVersion,
|
|
567
|
+
updateAvailable: hint !== null,
|
|
568
|
+
updateKind: hint?.kind ?? null,
|
|
569
|
+
updateTarget: hint?.version ?? null,
|
|
570
|
+
updateHint: hint?.text ?? null,
|
|
520
571
|
})
|
|
521
572
|
},
|
|
522
573
|
},
|
package/package.json
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@windypro-rourou/dsh-logcat",
|
|
3
|
-
"description": "Android Logcat viewer for the dsh web GUI: auto-connects to any adb device in debug mode, live logcat stream with level/keyword filters, pause/clear/export, plus agent tools (logcat_recent). Hot-pluggable — mounted via ~/.dsh/cordis.patch.yml + a profile node_modules copy, no dsh source changes.",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"type": "module",
|
|
6
|
-
"packageManager": "pnpm@11.22.0",
|
|
7
|
-
"engines": {
|
|
8
|
-
"node": "^22.19.0 || >=24.0.0"
|
|
9
|
-
},
|
|
10
|
-
"main": "lib/index.js",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"default": "./lib/index.js"
|
|
14
|
-
},
|
|
15
|
-
"./client": {
|
|
16
|
-
"default": "./lib/client.js"
|
|
17
|
-
},
|
|
18
|
-
"./package.json": "./package.json"
|
|
19
|
-
},
|
|
20
|
-
"dsh": {
|
|
21
|
-
"bundle": {
|
|
22
|
-
"patch": "./cordis.patch.yml"
|
|
23
|
-
},
|
|
24
|
-
"client": {
|
|
25
|
-
"inject": [
|
|
26
|
-
"@deepseek-ai/dsh-client-runtime"
|
|
27
|
-
],
|
|
28
|
-
"platform": "web"
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"ws": "^8.18.0"
|
|
33
|
-
},
|
|
34
|
-
"peerDependencies": {
|
|
35
|
-
"react": "^18.2.0",
|
|
36
|
-
"react-dom": "^18.2.0"
|
|
37
|
-
},
|
|
38
|
-
"files": [
|
|
39
|
-
"lib/**/*.js",
|
|
40
|
-
"cordis.patch.yml",
|
|
41
|
-
"README.md"
|
|
42
|
-
],
|
|
43
|
-
"license": "Apache-2.0",
|
|
44
|
-
"repository": {
|
|
45
|
-
"type": "git",
|
|
46
|
-
"url": "https://github.com/
|
|
47
|
-
}
|
|
48
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@windypro-rourou/dsh-logcat",
|
|
3
|
+
"description": "Android Logcat viewer for the dsh web GUI: auto-connects to any adb device in debug mode, live logcat stream with level/keyword filters, pause/clear/export, plus agent tools (logcat_recent). Hot-pluggable — mounted via ~/.dsh/cordis.patch.yml + a profile node_modules copy, no dsh source changes.",
|
|
4
|
+
"version": "0.5.0-preview.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"packageManager": "pnpm@11.22.0",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
9
|
+
},
|
|
10
|
+
"main": "lib/index.js",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"default": "./lib/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./client": {
|
|
16
|
+
"default": "./lib/client.js"
|
|
17
|
+
},
|
|
18
|
+
"./package.json": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
"dsh": {
|
|
21
|
+
"bundle": {
|
|
22
|
+
"patch": "./cordis.patch.yml"
|
|
23
|
+
},
|
|
24
|
+
"client": {
|
|
25
|
+
"inject": [
|
|
26
|
+
"@deepseek-ai/dsh-client-runtime"
|
|
27
|
+
],
|
|
28
|
+
"platform": "web"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"ws": "^8.18.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": "^18.2.0",
|
|
36
|
+
"react-dom": "^18.2.0"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"lib/**/*.js",
|
|
40
|
+
"cordis.patch.yml",
|
|
41
|
+
"README.md"
|
|
42
|
+
],
|
|
43
|
+
"license": "Apache-2.0",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/WindyPro-rourou/dsh-logcat.git"
|
|
47
|
+
}
|
|
48
|
+
}
|