@drscrewdriver/dsh-better-display 0.3.3-fork.1 → 0.3.3-fork.3
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 +1 -0
- package/cordis.patch.yml +1 -1
- package/lib/dsh-better-display.js +160 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- Windows build fix (fork.3): the vendored `tools/client-build.js` server bundling predicate accepted only POSIX-style paths, so on Windows the server entry shipped with dangling `./skill-roots.ts` / `./skill-status.ts` imports and never activated. Relative modules are now inlined on every platform.
|
|
5
6
|
- Message bubbles: each final answer renders in a rounded bubble separating it from the page background, so text no longer sits directly on skinned hosts' wallpapers. Glass mode mixes the same tokens translucently, mirroring the user bubble's frosted treatment. A new 消息气泡 / Message bubbles switch in settings restores the flat layout when off (persisted as `bubbles` on `dsh.reader.v1`, default on).
|
|
6
7
|
|
|
7
8
|
## 0.3.3 — 2026-09-24
|
package/cordis.patch.yml
CHANGED
|
@@ -1,6 +1,161 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { access, readdir } from "node:fs/promises";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
//#region src/skill-status.ts
|
|
8
|
+
/** Shared generative-mcpapps identity. Plugin-tree presence is not installation. */
|
|
9
|
+
const GENERATIVE_MCPAPPS_SKILL = "generative-mcpapps";
|
|
10
|
+
/** Conventional relative roots only. Never expand $HOME or dump host `root.path`. */
|
|
11
|
+
const CONVENTIONAL_SKILL_ROOTS = [".dsh/skills", ".agents/skills"];
|
|
12
|
+
function skillNameMatches(name) {
|
|
13
|
+
return typeof name === "string" && name === "generative-mcpapps";
|
|
14
|
+
}
|
|
15
|
+
function skillListIncludes(entries) {
|
|
16
|
+
return Array.isArray(entries) && entries.some((entry) => skillNameMatches(entry?.name));
|
|
17
|
+
}
|
|
18
|
+
/** Directory bundle `name/SKILL.md` or flat `name.md` at a scanned root. */
|
|
19
|
+
function skillRootEntryMatches(entryName) {
|
|
20
|
+
return entryName === "generative-mcpapps" || entryName === `generative-mcpapps.md`;
|
|
21
|
+
}
|
|
22
|
+
function skillsFromListResult(result) {
|
|
23
|
+
if (Array.isArray(result)) return result;
|
|
24
|
+
if (result === null || typeof result !== "object") return [];
|
|
25
|
+
const record = result;
|
|
26
|
+
if (record.ok === false) return [];
|
|
27
|
+
if (Array.isArray(record.skills)) return record.skills;
|
|
28
|
+
if (record.value && typeof record.value === "object") {
|
|
29
|
+
const value = record.value;
|
|
30
|
+
if (Array.isArray(value.skills)) return value.skills;
|
|
31
|
+
if (Array.isArray(record.value)) return record.value;
|
|
32
|
+
}
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
function publicSkillRoots() {
|
|
36
|
+
return CONVENTIONAL_SKILL_ROOTS.map((path) => ({
|
|
37
|
+
source: "conventional",
|
|
38
|
+
path
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Strip host home / pack absolutes before anything user-facing (HTTP or Settings).
|
|
43
|
+
* Detection still uses the raw scan; this is the public face.
|
|
44
|
+
*/
|
|
45
|
+
function toPublicSkillStatus(status) {
|
|
46
|
+
return {
|
|
47
|
+
name: status.name,
|
|
48
|
+
installed: status.installed,
|
|
49
|
+
via: status.via,
|
|
50
|
+
roots: publicSkillRoots()
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/skill-roots.ts
|
|
55
|
+
function expandHomePath(path, home = homedir()) {
|
|
56
|
+
if (path === "~") return home;
|
|
57
|
+
if (path.startsWith("~/") || path.startsWith("~\\")) return join(home, path.slice(2));
|
|
58
|
+
return path;
|
|
59
|
+
}
|
|
60
|
+
/** `$DSH_HOME` or `~/.dsh`, matching official `resolveDshHome`. */
|
|
61
|
+
function resolveDshHome(env = process.env, home = homedir()) {
|
|
62
|
+
const fromEnv = env.DSH_HOME;
|
|
63
|
+
const selected = fromEnv !== void 0 && fromEnv.trim().length > 0 ? fromEnv : join(home, ".dsh");
|
|
64
|
+
return resolve(expandHomePath(selected, home));
|
|
65
|
+
}
|
|
66
|
+
/** `$DSH_AGENTS_HOME` or `~/.agents`. */
|
|
67
|
+
function resolveAgentsHome(env = process.env, home = homedir()) {
|
|
68
|
+
const fromEnv = env.DSH_AGENTS_HOME;
|
|
69
|
+
const selected = fromEnv !== void 0 && fromEnv.trim().length > 0 ? fromEnv : join(home, ".agents");
|
|
70
|
+
return resolve(expandHomePath(selected, home));
|
|
71
|
+
}
|
|
72
|
+
function userSkillRoots(env = process.env, home = homedir()) {
|
|
73
|
+
return [{
|
|
74
|
+
source: "user-dsh",
|
|
75
|
+
path: join(resolveDshHome(env, home), "skills")
|
|
76
|
+
}, {
|
|
77
|
+
source: "user-agents",
|
|
78
|
+
path: join(resolveAgentsHome(env, home), "skills")
|
|
79
|
+
}];
|
|
80
|
+
}
|
|
81
|
+
function projectSkillRoots(projectRoot) {
|
|
82
|
+
return [{
|
|
83
|
+
source: "project-dsh",
|
|
84
|
+
path: join(projectRoot, ".dsh", "skills")
|
|
85
|
+
}, {
|
|
86
|
+
source: "project-agents",
|
|
87
|
+
path: join(projectRoot, ".agents", "skills")
|
|
88
|
+
}];
|
|
89
|
+
}
|
|
90
|
+
async function findProjectRoot(cwd) {
|
|
91
|
+
let current = resolve(cwd);
|
|
92
|
+
while (true) {
|
|
93
|
+
if (existsSync(join(current, ".git"))) return current;
|
|
94
|
+
const parent = dirname(current);
|
|
95
|
+
if (parent === current) return resolve(cwd);
|
|
96
|
+
current = parent;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function rootHasGenerativeMcpapps(rootPath) {
|
|
100
|
+
let entries;
|
|
101
|
+
try {
|
|
102
|
+
entries = await readdir(rootPath, { withFileTypes: true });
|
|
103
|
+
} catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
for (const entry of entries) {
|
|
107
|
+
if (entry.name === ".system") continue;
|
|
108
|
+
if (!skillRootEntryMatches(entry.name)) continue;
|
|
109
|
+
if (entry.isDirectory()) try {
|
|
110
|
+
await access(join(rootPath, entry.name, "SKILL.md"));
|
|
111
|
+
return true;
|
|
112
|
+
} catch {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (entry.isFile()) return true;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
/** Resolve the plugin-shipped pack. This path is never treated as a skill root. */
|
|
120
|
+
function pluginSkillPackPath(moduleUrl = import.meta.url) {
|
|
121
|
+
const here = dirname(fileURLToPath(moduleUrl));
|
|
122
|
+
return [
|
|
123
|
+
join(here, "../skills", GENERATIVE_MCPAPPS_SKILL),
|
|
124
|
+
join(here, "../../skills", GENERATIVE_MCPAPPS_SKILL),
|
|
125
|
+
join(here, "skills", GENERATIVE_MCPAPPS_SKILL)
|
|
126
|
+
].find((path) => existsSync(join(path, "SKILL.md")));
|
|
127
|
+
}
|
|
128
|
+
async function scanGenerativeMcpappsStatus(options = {}) {
|
|
129
|
+
const roots = [...userSkillRoots(options.env ?? process.env, options.home ?? homedir())];
|
|
130
|
+
const cwd = typeof options.cwd === "string" && options.cwd.trim().length > 0 ? isAbsolute(options.cwd) ? options.cwd : resolve(options.cwd) : void 0;
|
|
131
|
+
if (cwd !== void 0) roots.unshift(...projectSkillRoots(await findProjectRoot(cwd)));
|
|
132
|
+
const inspected = [];
|
|
133
|
+
let rootHit = false;
|
|
134
|
+
for (const root of roots) {
|
|
135
|
+
const present = await rootHasGenerativeMcpapps(root.path);
|
|
136
|
+
inspected.push({
|
|
137
|
+
...root,
|
|
138
|
+
present
|
|
139
|
+
});
|
|
140
|
+
if (present) rootHit = true;
|
|
141
|
+
}
|
|
142
|
+
let via = null;
|
|
143
|
+
let listHit = false;
|
|
144
|
+
if (options.listSkills) try {
|
|
145
|
+
listHit = skillListIncludes(await options.listSkills());
|
|
146
|
+
if (listHit) via = "skills.list";
|
|
147
|
+
} catch {}
|
|
148
|
+
if (!listHit && rootHit) via = "skill-root";
|
|
149
|
+
const packPath = options.packPath ?? pluginSkillPackPath();
|
|
150
|
+
return {
|
|
151
|
+
name: GENERATIVE_MCPAPPS_SKILL,
|
|
152
|
+
installed: listHit || rootHit,
|
|
153
|
+
via,
|
|
154
|
+
roots: inspected,
|
|
155
|
+
...packPath !== void 0 ? { packPath } : {}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
//#endregion
|
|
4
159
|
//#region src/dsh-better-display.ts
|
|
5
160
|
const name = "@drscrewdriver/dsh-better-display";
|
|
6
161
|
const inject = ["webServer"];
|
|
@@ -77,12 +232,10 @@ function apply(ctx) {
|
|
|
77
232
|
return;
|
|
78
233
|
}
|
|
79
234
|
try {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
cwd,
|
|
235
|
+
writeJson(res, 200, toPublicSkillStatus(await scanGenerativeMcpappsStatus({
|
|
236
|
+
cwd: new URL(req.url ?? "", "http://127.0.0.1").searchParams.get("cwd") ?? void 0,
|
|
83
237
|
listSkills: skillLister(ctx)
|
|
84
|
-
});
|
|
85
|
-
writeJson(res, 200, toPublicSkillStatus(status));
|
|
238
|
+
})));
|
|
86
239
|
} catch (err) {
|
|
87
240
|
writeJson(res, 500, {
|
|
88
241
|
ok: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drscrewdriver/dsh-better-display",
|
|
3
|
-
"version": "0.3.3-fork.
|
|
3
|
+
"version": "0.3.3-fork.3",
|
|
4
4
|
"description": "A calmer reading view for DeepSeek Harness: native process details, live reasoning, and clean final answers. Fork adds answer message bubbles with a settings switch.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|