dsh-gitbash-shell 0.8.0 → 0.10.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/dsh.plugin.json +1 -1
- package/package.json +14 -3
- package/src/client.js +280 -0
- package/src/index.js +124 -4
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-gitbash-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "Windows 全模式 Git Bash:用 Git for Windows bash 替换 PowerShell 执行器,并物化 standard/minimal/code/cordis 的 Git Bash 变体 preset。双 era 适配 dsh <= 0.1.1(内置 id 'code')与 >= 0.1.2(改名 'ptc'),启动探测自动选择,preset id 永不变。联动:dsh-ptc-cordis-preset(两者同装时 PTC 创造模式自动物化为 Git Bash 版)+ dsh-better-sidebar(终端 UI 标签与模型 terminal_* 工具自动切到 Git Bash)。",
|
|
6
6
|
"engines": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-gitbash-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "DSH plugin: run every agent shell command through Git for Windows bash on Windows instead of PowerShell. Replaces the pwsh executor with a Git Bash ctx.shell provider and materializes Git Bash variants of the standard/minimal/code/cordis agent presets into your user preset root at startup. On Windows it also adopts dsh-better-sidebar's terminal shell (UI tabs and the model-facing terminal_* tools) through the sidebar's official settings seam, and pairs with dsh-ptc-cordis-preset so the PTC Creation-mode preset materializes as its Git Bash variant. Ships both composition eras for dsh <= 0.1.1 (built-in preset id 'code') and dsh >= 0.1.2 (renamed id 'ptc') — the era is probed per boot and re-materialized automatically after a dsh upgrade, in either upgrade order; preset ids never change so pinned sessions stay valid.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"main": "src/index.js",
|
|
11
11
|
"exports": {
|
|
12
12
|
".": "./src/index.js",
|
|
13
|
-
"./shell": "./src/shell.js"
|
|
13
|
+
"./shell": "./src/shell.js",
|
|
14
|
+
"./client": "./src/client.js"
|
|
14
15
|
},
|
|
15
16
|
"engines": {
|
|
16
17
|
"node": ">=18"
|
|
@@ -18,6 +19,15 @@
|
|
|
18
19
|
"dsh": {
|
|
19
20
|
"bundle": {
|
|
20
21
|
"patch": "./cordis.patch.yml"
|
|
22
|
+
},
|
|
23
|
+
"client": {
|
|
24
|
+
"inject": [
|
|
25
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
26
|
+
"@deepseek-ai/dsh-client-locale",
|
|
27
|
+
"@deepseek-ai/dsh-client-ui-slots",
|
|
28
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
29
|
+
],
|
|
30
|
+
"platform": "web"
|
|
21
31
|
}
|
|
22
32
|
},
|
|
23
33
|
"files": [
|
|
@@ -42,7 +52,8 @@
|
|
|
42
52
|
],
|
|
43
53
|
"license": "MIT",
|
|
44
54
|
"peerDependencies": {
|
|
45
|
-
"@deepseek-ai/cordis": "^4.0.1"
|
|
55
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
56
|
+
"@deepseek-ai/schemastery": "^3.18.1"
|
|
46
57
|
},
|
|
47
58
|
"publishConfig": {
|
|
48
59
|
"access": "public"
|
package/src/client.js
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-gitbash-shell — browser half (hand-written ModuleLoader bundle).
|
|
3
|
+
*
|
|
4
|
+
* ONE job: the Settings → Plugins card that gates the unified POSIX path
|
|
5
|
+
* dialect. The Plugins tab dispatches the intersection of Host-served
|
|
6
|
+
* namespaces and registered cards, so the card appears only when the host
|
|
7
|
+
* half (src/index.js) has registered the 'gitbash-shell' settings namespace.
|
|
8
|
+
*
|
|
9
|
+
* The card flips one boolean — posixPaths — through a bound settingsScope:
|
|
10
|
+
* on → the host injects the order-126 directive (every tool takes MSYS
|
|
11
|
+
* drive roots /c/...) and the tools/execute wrapper translates
|
|
12
|
+
* path-argument fields (/x/ → X:/) for the Node-backed file tools;
|
|
13
|
+
* off → directive text is empty (dropped at assembly, zero prompt noise)
|
|
14
|
+
* and the wrapper passes calls through untouched (dsh-native).
|
|
15
|
+
* Bash itself is always Git Bash while the plugin is installed; the switch
|
|
16
|
+
* only governs the cross-tool path dialect.
|
|
17
|
+
*
|
|
18
|
+
* Hand-written bundle rules (no build step in this repo):
|
|
19
|
+
* - ONE window.__ModuleLoader__.load({...}) call, id = package name;
|
|
20
|
+
* - require restricted to the client-module BASELINE whitelist
|
|
21
|
+
* (react and @deepseek-ai/dsh-client-ui-primitives only, smoke-enforced);
|
|
22
|
+
* - plain React.createElement, no JSX/TS; components at module level;
|
|
23
|
+
* - dsh.client.inject in package.json lists the packages that must load
|
|
24
|
+
* first so locale / settingsScope / slots exist when this applies.
|
|
25
|
+
*/
|
|
26
|
+
window.__ModuleLoader__.load({
|
|
27
|
+
id: "dsh-gitbash-shell",
|
|
28
|
+
factory: (require) => {
|
|
29
|
+
var module = { exports: {} };
|
|
30
|
+
var exports = module.exports;
|
|
31
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
32
|
+
|
|
33
|
+
var React = require("react");
|
|
34
|
+
var ui = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
35
|
+
|
|
36
|
+
var E = React.createElement;
|
|
37
|
+
var useState = React.useState;
|
|
38
|
+
|
|
39
|
+
var TAG = "[gitbash-shell/client]";
|
|
40
|
+
/** Dictionary namespace (the plugin's own t seat). */
|
|
41
|
+
var NS = "gitbashShell";
|
|
42
|
+
/** The settings namespace the HOST half serves. */
|
|
43
|
+
var SETTINGS_NAMESPACE = "gitbash-shell";
|
|
44
|
+
|
|
45
|
+
// ── dictionaries (zh/en MUST stay key-aligned; smoke-enforced) ─────────
|
|
46
|
+
|
|
47
|
+
var zh = {
|
|
48
|
+
"title": "Git Bash 路径方言",
|
|
49
|
+
"cardDesc": "所有工具统一 /c/ POSIX 路径形式(默认关闭)",
|
|
50
|
+
"state.label": "当前状态",
|
|
51
|
+
"state.on": "已启用",
|
|
52
|
+
"state.off": "已关闭",
|
|
53
|
+
"switch.on": "启用",
|
|
54
|
+
"switch.off": "停用",
|
|
55
|
+
"error": "写入失败",
|
|
56
|
+
"hint": "启用后:所有工具(bash 命令与 workdir、read/write/edit/read_image/glob/grep 的路径参数)统一使用 MSYS 盘根 POSIX 路径(/c/Users/...);文件工具的路径参数由宿主自动翻译,模型无感。停用后恢复 dsh 原生行为(文件工具用 Windows 路径)。bash 始终是 Git Bash,不受此开关影响。",
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
var en = {
|
|
60
|
+
"title": "Git Bash path dialect",
|
|
61
|
+
"cardDesc": "One /c/ POSIX path style for every tool (off by default)",
|
|
62
|
+
"state.label": "Current state",
|
|
63
|
+
"state.on": "Enabled",
|
|
64
|
+
"state.off": "Disabled",
|
|
65
|
+
"switch.on": "Enable",
|
|
66
|
+
"switch.off": "Disable",
|
|
67
|
+
"error": "write failed",
|
|
68
|
+
"hint": "Enabled: every tool (bash commands and workdir, read/write/edit/read_image/glob/grep path arguments) uses MSYS drive-root POSIX paths (/c/Users/...); the host translates path fields for the file tools automatically. Disabled restores dsh-native behavior (Windows paths for file tools). Bash is always Git Bash while the plugin is installed; this switch only governs the cross-tool path dialect.",
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// ── styles (gb- prefixed; tokens mirror PluginCard.module.css) ─────────
|
|
72
|
+
|
|
73
|
+
var STYLE_ID = "dsh-gitbash-shell-style";
|
|
74
|
+
|
|
75
|
+
var CSS = [
|
|
76
|
+
".gb-card{list-style:none;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-3);transition:border-color .16s,background .16s}",
|
|
77
|
+
".gb-card:hover{border-color:var(--dsw-alias-label-dimmed)}",
|
|
78
|
+
".gb-card.gb-open{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}",
|
|
79
|
+
".gb-header{width:100%;appearance:none;border:0;background:none;font:inherit;color:inherit;text-align:left;cursor:pointer;display:flex;align-items:center;gap:12px;padding:14px 16px;border-radius:12px}",
|
|
80
|
+
".gb-header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}",
|
|
81
|
+
".gb-headText{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}",
|
|
82
|
+
".gb-name{font-size:15px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary)}",
|
|
83
|
+
".gb-desc{font-size:13px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}",
|
|
84
|
+
".gb-chevron{flex:none;color:var(--dsw-alias-label-tertiary);transition:transform .16s}",
|
|
85
|
+
".gb-chevron.gb-chevronOpen{transform:rotate(180deg)}",
|
|
86
|
+
".gb-body{display:flex;flex-direction:column;gap:12px;padding:4px 16px 16px;max-width:640px}",
|
|
87
|
+
".gb-row{display:flex;align-items:baseline;gap:8px;font-size:13px;line-height:1.5;color:var(--dsw-alias-label-secondary)}",
|
|
88
|
+
".gb-rowLabel{flex:none;color:var(--dsw-alias-label-tertiary)}",
|
|
89
|
+
".gb-rowValue{min-width:0;overflow-wrap:anywhere;color:var(--dsw-alias-label-primary)}",
|
|
90
|
+
".gb-seg{display:flex;gap:8px;flex-wrap:wrap}",
|
|
91
|
+
".gb-segBtn{appearance:none;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);font:inherit;font-size:13px;padding:6px 12px;cursor:pointer;transition:border-color .16s,color .16s}",
|
|
92
|
+
".gb-segBtn:hover{border-color:var(--dsw-alias-label-dimmed)}",
|
|
93
|
+
".gb-segBtn:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}",
|
|
94
|
+
".gb-segBtn.gb-segActive{border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-primary)}",
|
|
95
|
+
".gb-hint{margin:0;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-tertiary)}",
|
|
96
|
+
".gb-error{margin:0;font-size:12px;color:var(--dsw-alias-status-danger, #e5484d)}",
|
|
97
|
+
].join("\n");
|
|
98
|
+
|
|
99
|
+
function ensureStyles() {
|
|
100
|
+
try {
|
|
101
|
+
if (typeof document === "undefined" || typeof document.getElementById !== "function") return function () {};
|
|
102
|
+
if (document.getElementById(STYLE_ID)) return function () {};
|
|
103
|
+
var style = document.createElement("style");
|
|
104
|
+
style.id = STYLE_ID;
|
|
105
|
+
style.textContent = CSS;
|
|
106
|
+
document.head.appendChild(style);
|
|
107
|
+
return function () {
|
|
108
|
+
try {
|
|
109
|
+
if (style.parentNode) style.parentNode.removeChild(style);
|
|
110
|
+
} catch (error) { /* best effort */ }
|
|
111
|
+
};
|
|
112
|
+
} catch (error) {
|
|
113
|
+
return function () {};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Defensive primitives lookup: an unknown icon name degrades to a text chevron. */
|
|
118
|
+
function icon(name) {
|
|
119
|
+
try {
|
|
120
|
+
var component = ui && ui[name];
|
|
121
|
+
return typeof component === "function" ? component : null;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── error boundary (the dsh-better-workspace QuietBoundary pattern) ──────
|
|
128
|
+
|
|
129
|
+
/** A render failure degrades THIS card, never the settings page. */
|
|
130
|
+
function QuietBoundary(props) {}
|
|
131
|
+
QuietBoundary.prototype = Object.create(React.Component.prototype);
|
|
132
|
+
QuietBoundary.prototype.constructor = QuietBoundary;
|
|
133
|
+
QuietBoundary.state = { failed: false };
|
|
134
|
+
QuietBoundary.getDerivedStateFromError = function () { return { failed: true }; };
|
|
135
|
+
QuietBoundary.prototype.componentDidCatch = function (error) {
|
|
136
|
+
console.warn(TAG + " settings card render failed:", error && error.message ? error.message : error);
|
|
137
|
+
};
|
|
138
|
+
QuietBoundary.prototype.render = function () {
|
|
139
|
+
if (this.state && this.state.failed) return null;
|
|
140
|
+
return this.props.children;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// ── settings card (module-level component) ───────────────────────────────
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The Settings → Plugins card. t arrives through the registration's
|
|
147
|
+
* locale field; scope arrives as a PLAIN prop from the inject factory.
|
|
148
|
+
* Snapshots are read per render; each write bumps a local tick so the
|
|
149
|
+
* card re-reads without an external-store hook adapter.
|
|
150
|
+
*/
|
|
151
|
+
function GitBashCard(props) {
|
|
152
|
+
var t = typeof props.t === "function" ? props.t : function (key) { return key; };
|
|
153
|
+
|
|
154
|
+
var openState = useState(false);
|
|
155
|
+
var open = openState[0];
|
|
156
|
+
var setOpen = openState[1];
|
|
157
|
+
|
|
158
|
+
var errorState = useState("");
|
|
159
|
+
var error = errorState[0];
|
|
160
|
+
var setError = errorState[1];
|
|
161
|
+
|
|
162
|
+
var tickState = useState(0);
|
|
163
|
+
var tick = tickState[0];
|
|
164
|
+
var bumpTick = tickState[1];
|
|
165
|
+
void tick;
|
|
166
|
+
|
|
167
|
+
var scope = props.scope;
|
|
168
|
+
|
|
169
|
+
var snap = { status: "unavailable" };
|
|
170
|
+
try {
|
|
171
|
+
if (scope && typeof scope.getSnapshot === "function") snap = scope.getSnapshot();
|
|
172
|
+
} catch (error_) { /* keep unavailable */ }
|
|
173
|
+
|
|
174
|
+
if (snap.status !== "ready") return null;
|
|
175
|
+
|
|
176
|
+
var value = snap.value || {};
|
|
177
|
+
var enabled = value.posixPaths === true;
|
|
178
|
+
|
|
179
|
+
function write(next) {
|
|
180
|
+
setError("");
|
|
181
|
+
scope.set("posixPaths", next)
|
|
182
|
+
.then(function () { bumpTick(function (n) { return n + 1; }); })
|
|
183
|
+
.catch(function (err) {
|
|
184
|
+
bumpTick(function (n) { return n + 1; });
|
|
185
|
+
setError(t("error") + ": " + (err && err.message ? err.message : String(err)));
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
var Chevron = icon("IconChevronDownOutline14");
|
|
190
|
+
|
|
191
|
+
return E("li", { className: "gb-card" + (open ? " gb-open" : "") },
|
|
192
|
+
E("button", {
|
|
193
|
+
type: "button",
|
|
194
|
+
className: "gb-header",
|
|
195
|
+
"aria-expanded": open,
|
|
196
|
+
onClick: function () { setOpen(!open); },
|
|
197
|
+
},
|
|
198
|
+
E("span", { className: "gb-headText" },
|
|
199
|
+
E("span", { className: "gb-name" }, t("title")),
|
|
200
|
+
E("span", { className: "gb-desc" }, t("cardDesc")),
|
|
201
|
+
),
|
|
202
|
+
Chevron
|
|
203
|
+
? E(Chevron, { className: "gb-chevron" + (open ? " gb-chevronOpen" : "") })
|
|
204
|
+
: E("span", { className: "gb-chevron" + (open ? " gb-chevronOpen" : "") }, "▾"),
|
|
205
|
+
),
|
|
206
|
+
open ? E("div", { className: "gb-body" },
|
|
207
|
+
E("div", { className: "gb-row" },
|
|
208
|
+
E("span", { className: "gb-rowLabel" }, t("state.label") + ":"),
|
|
209
|
+
E("span", { className: "gb-rowValue" }, enabled ? t("state.on") : t("state.off")),
|
|
210
|
+
),
|
|
211
|
+
E("div", { className: "gb-seg" },
|
|
212
|
+
E("button", {
|
|
213
|
+
type: "button",
|
|
214
|
+
className: "gb-segBtn" + (enabled ? " gb-segActive" : ""),
|
|
215
|
+
onClick: function () { if (!enabled) write(true); },
|
|
216
|
+
}, t("switch.on")),
|
|
217
|
+
E("button", {
|
|
218
|
+
type: "button",
|
|
219
|
+
className: "gb-segBtn" + (!enabled ? " gb-segActive" : ""),
|
|
220
|
+
onClick: function () { if (enabled) write(false); },
|
|
221
|
+
}, t("switch.off")),
|
|
222
|
+
),
|
|
223
|
+
error ? E("p", { className: "gb-error" }, error) : null,
|
|
224
|
+
E("p", { className: "gb-hint" }, t("hint")),
|
|
225
|
+
) : null,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ── plugin ────────────────────────────────────────────────────────────
|
|
230
|
+
|
|
231
|
+
exports.name = "dsh-gitbash-shell/client";
|
|
232
|
+
|
|
233
|
+
/** Required client services: locale runtime, settings scopes, slots. */
|
|
234
|
+
exports.inject = ["locale", "settingsScope", "slots"];
|
|
235
|
+
|
|
236
|
+
exports.apply = function (ctx) {
|
|
237
|
+
var scope = ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE });
|
|
238
|
+
|
|
239
|
+
ctx.effect(function () {
|
|
240
|
+
var disposers = [ensureStyles()];
|
|
241
|
+
try {
|
|
242
|
+
var disposeDict = ctx.locale.register(NS, { zh: zh, en: en });
|
|
243
|
+
if (typeof disposeDict === "function") disposers.push(disposeDict);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.warn(TAG + " dictionary registration failed:", error && error.message ? error.message : error);
|
|
246
|
+
}
|
|
247
|
+
return function () {
|
|
248
|
+
for (var i = 0; i < disposers.length; i++) {
|
|
249
|
+
try {
|
|
250
|
+
if (typeof disposers[i] === "function") disposers[i]();
|
|
251
|
+
} catch (error) { /* best effort */ }
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}, "dsh-gitbash-shell: styles, dictionaries");
|
|
255
|
+
|
|
256
|
+
// Guarded registration (the dsh-better-workspace pattern): a thrown
|
|
257
|
+
// register degrades this one seat, never the plugin fiber.
|
|
258
|
+
try {
|
|
259
|
+
var slots = ctx.slots;
|
|
260
|
+
if (!slots || typeof slots.inject !== "function") {
|
|
261
|
+
console.warn(TAG + " slots service unavailable; settings card idle");
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
slots.inject("settings.plugin.item",
|
|
265
|
+
{
|
|
266
|
+
name: "settings.plugin.item",
|
|
267
|
+
key: SETTINGS_NAMESPACE,
|
|
268
|
+
locale: NS,
|
|
269
|
+
inject: function () { return { scope: scope }; },
|
|
270
|
+
},
|
|
271
|
+
function (props) {
|
|
272
|
+
return E(QuietBoundary, null, E(GitBashCard, props));
|
|
273
|
+
},
|
|
274
|
+
);
|
|
275
|
+
} catch (error) {
|
|
276
|
+
console.warn(TAG + " settings card registration failed:", error && error.message ? error.message : error);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
},
|
|
280
|
+
});
|
package/src/index.js
CHANGED
|
@@ -290,6 +290,50 @@ export function installRegisterShim(reg) {
|
|
|
290
290
|
}
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
+
// ── unified path dialect: settings namespace + gate (v0.9.0) ───────────────
|
|
294
|
+
//
|
|
295
|
+
// The dialect (directive + translation wrapper) is OFF by default and gated
|
|
296
|
+
// by the posixPaths boolean in the 'gitbash-shell' settings namespace,
|
|
297
|
+
// flipped from the Settings → Plugins card (src/client.js). The directive's
|
|
298
|
+
// text closure returns '' while off — empty context contributions are
|
|
299
|
+
// dropped at assembly, so a disabled dialect adds zero prompt noise; the
|
|
300
|
+
// wrapper reads the same value per dispatch and passes calls through.
|
|
301
|
+
|
|
302
|
+
const SETTINGS_NAMESPACE = 'gitbash-shell'
|
|
303
|
+
|
|
304
|
+
/** The full directive text, injected only while posixPaths is on. */
|
|
305
|
+
const POSIX_DIRECTIVE_TEXT = 'The working shell is Git for Windows bash: paths use MSYS drive roots (/c/Users/...), and every tool accepts that form directly.'
|
|
306
|
+
|
|
307
|
+
/** Read the posixPaths switch from the live settings service; never throws. */
|
|
308
|
+
export function readPosixPaths(ctxLike) {
|
|
309
|
+
try {
|
|
310
|
+
const settings = ctxLike && typeof ctxLike.get === 'function' ? ctxLike.get('settings') : undefined
|
|
311
|
+
const value = settings && typeof settings.get === 'function' ? settings.get(SETTINGS_NAMESPACE) : undefined
|
|
312
|
+
return !!(value && value.posixPaths === true)
|
|
313
|
+
} catch {
|
|
314
|
+
return false
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Windows absolute path -> MSYS drive-root form, for rewriting the OFFICIAL
|
|
319
|
+
// prompt text in place (v0.10.0). Two patterns keep quoted spaced paths
|
|
320
|
+
// ("C:\Program Files\Git") whole while bare paths stop at whitespace or a
|
|
321
|
+
// closing punctuation; the lookbehind set rejects URL schemes (https:),
|
|
322
|
+
// file:// forms, and anything already mid-word, so only real drive-letter
|
|
323
|
+
// paths are translated. Separators normalize to single slashes.
|
|
324
|
+
const BARE_WIN_PATH = /(?<![A-Za-z0-9:\\/"'`])([A-Za-z]):(?:\\|\/)([^\s"'`<>|),;:!?]+)/g
|
|
325
|
+
const QUOTED_WIN_PATH = /(["'`])([A-Za-z]):(?:\\|\/)([^`]*?)\1/g
|
|
326
|
+
|
|
327
|
+
/** Rewrite every Windows absolute path in a text to the MSYS form; pure. */
|
|
328
|
+
export function windowsToMsys(text) {
|
|
329
|
+
if (typeof text !== 'string' || text.length === 0) return text
|
|
330
|
+
return text
|
|
331
|
+
.replace(QUOTED_WIN_PATH, (_whole, quote, drive, rest) =>
|
|
332
|
+
quote + '/' + drive.toLowerCase() + '/' + rest.replace(/[\\/]+/g, '/') + quote)
|
|
333
|
+
.replace(BARE_WIN_PATH, (_whole, drive, rest) =>
|
|
334
|
+
'/' + drive.toLowerCase() + '/' + rest.replace(/[\\/]+/g, '/'))
|
|
335
|
+
}
|
|
336
|
+
|
|
293
337
|
// ── MSYS drive-root path translation (Windows, EVERY tool dispatch) ────────
|
|
294
338
|
//
|
|
295
339
|
// The directive below tells the model to use POSIX-style MSYS paths (/c/...)
|
|
@@ -502,6 +546,74 @@ export async function apply(ctx, config = {}) {
|
|
|
502
546
|
const disposeGitBash = ctx.provide('gitBash', gitBashCapability)
|
|
503
547
|
ctx.effect(() => disposeGitBash, 'dsh-gitbash-shell: gitBash capability')
|
|
504
548
|
|
|
549
|
+
// ── settings namespace: the posixPaths switch (default OFF) ──────────────
|
|
550
|
+
// Served on the host so the Plugins tab pairs it with the browser card
|
|
551
|
+
// (the tab dispatches Host-served namespaces ∩ registered cards). Dynamic
|
|
552
|
+
// imports keep the zero-dependency smoke path importable; the schema MUST
|
|
553
|
+
// be a callable schemastery object (dsh-settings calls schema(merged)).
|
|
554
|
+
try {
|
|
555
|
+
ctx.inject(['settings'], (sctx) => {
|
|
556
|
+
Promise.all([import('@deepseek-ai/dsh-settings'), import('@deepseek-ai/schemastery')])
|
|
557
|
+
.then(([ds, sm]) => {
|
|
558
|
+
const settings = sctx && sctx.settings
|
|
559
|
+
if (!settings || typeof settings.register !== 'function') return
|
|
560
|
+
const Schema = sm.default
|
|
561
|
+
// Era probe: newer dsh register() takes a plain string; the older
|
|
562
|
+
// one accepted the branded helper — one call satisfies both.
|
|
563
|
+
const ns = typeof ds.settingsNamespace === 'function'
|
|
564
|
+
? ds.settingsNamespace(SETTINGS_NAMESPACE)
|
|
565
|
+
: SETTINGS_NAMESPACE
|
|
566
|
+
settings.register(ns, Schema.object({
|
|
567
|
+
posixPaths: Schema.boolean().default(true),
|
|
568
|
+
}))
|
|
569
|
+
console.log(`${TAG} settings namespace registered: ${SETTINGS_NAMESPACE} (posixPaths default on)`)
|
|
570
|
+
})
|
|
571
|
+
.catch((error) => {
|
|
572
|
+
console.log(`${TAG} settings namespace registration FAILED: ${error && error.stack || String(error)}`)
|
|
573
|
+
})
|
|
574
|
+
})
|
|
575
|
+
} catch (error) {
|
|
576
|
+
console.log(`${TAG} settings inject wiring failed: ${error?.message ?? error}`)
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// ── prompt-assembly path dialect (Windows only, gated; v0.10.0) ────────
|
|
580
|
+
// While posixPaths is on, EVERY Windows absolute path the model would
|
|
581
|
+
// see — section text, context text, and prompt variables — is rewritten
|
|
582
|
+
// IN PLACE to the MSYS drive-root form. Nothing is added or removed: the
|
|
583
|
+
// official prompt keeps its exact shape and only the path examples
|
|
584
|
+
// change dialect, so the model meets a /c/ world at the source instead
|
|
585
|
+
// of being asked to translate Windows forms it sees. Our own directive
|
|
586
|
+
// context is skipped (self-reference), and tool schemas stay untouched
|
|
587
|
+
// (they carry no drive-letter examples today, and blind string rewriting
|
|
588
|
+
// could corrupt pattern/default fields).
|
|
589
|
+
if (process.platform === 'win32') {
|
|
590
|
+
try {
|
|
591
|
+
ctx.on('system-prompt/assemble', (assembly, _assembleContext, next) => {
|
|
592
|
+
try {
|
|
593
|
+
if (readPosixPaths(ctx) && assembly && typeof assembly === 'object') {
|
|
594
|
+
for (const section of Array.isArray(assembly.sections) ? assembly.sections : []) {
|
|
595
|
+
if (section && typeof section.text === 'string') section.text = windowsToMsys(section.text)
|
|
596
|
+
}
|
|
597
|
+
for (const assembled of Array.isArray(assembly.contexts) ? assembly.contexts : []) {
|
|
598
|
+
if (!assembled || assembled.name === 'gitbash-shell:posix-paths') continue
|
|
599
|
+
if (typeof assembled.text === 'string') assembled.text = windowsToMsys(assembled.text)
|
|
600
|
+
}
|
|
601
|
+
const variables = assembly.variables
|
|
602
|
+
if (variables && typeof variables === 'object') {
|
|
603
|
+
for (const key of Object.keys(variables)) {
|
|
604
|
+
if (typeof variables[key] === 'string') variables[key] = windowsToMsys(variables[key])
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
} catch { /* never block assembly */ }
|
|
609
|
+
return next()
|
|
610
|
+
})
|
|
611
|
+
console.log(TAG + ' prompt-assembly path dialect active (gated by the posixPaths setting)')
|
|
612
|
+
} catch (error) {
|
|
613
|
+
console.log(TAG + ' system-prompt/assemble wiring failed: ' + (error?.message ?? error))
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
505
617
|
// ── MSYS path translation on every tool dispatch (Windows only) ─────────
|
|
506
618
|
// Covers every preset and mode: the wrapper sits on the global
|
|
507
619
|
// tools/execute waterfall, through which model-direct calls, PTC run_code
|
|
@@ -510,7 +622,7 @@ export async function apply(ctx, config = {}) {
|
|
|
510
622
|
try {
|
|
511
623
|
ctx.on('tools/execute', (exec, next) => {
|
|
512
624
|
try {
|
|
513
|
-
if (exec && exec.arguments && typeof exec.arguments === 'object') {
|
|
625
|
+
if (exec && exec.arguments && typeof exec.arguments === 'object' && readPosixPaths(ctx)) {
|
|
514
626
|
translatePathArguments(exec.arguments)
|
|
515
627
|
}
|
|
516
628
|
} catch { /* never block a call on translation */ }
|
|
@@ -538,9 +650,17 @@ export async function apply(ctx, config = {}) {
|
|
|
538
650
|
pctx.effect(() => pctx.systemPrompt.context({
|
|
539
651
|
name: 'gitbash-shell:posix-paths',
|
|
540
652
|
order: 126,
|
|
541
|
-
text:
|
|
653
|
+
text: () => {
|
|
654
|
+
try {
|
|
655
|
+
const settings = pctx.get('settings')
|
|
656
|
+
const value = settings && typeof settings.get === 'function' ? settings.get(SETTINGS_NAMESPACE) : undefined
|
|
657
|
+
return value && value.posixPaths === true ? POSIX_DIRECTIVE_TEXT : ''
|
|
658
|
+
} catch {
|
|
659
|
+
return ''
|
|
660
|
+
}
|
|
661
|
+
},
|
|
542
662
|
}), 'dsh-gitbash-shell: posix-path context')
|
|
543
|
-
console.log(TAG + ' unified POSIX-path directive context active (win32)')
|
|
663
|
+
console.log(TAG + ' unified POSIX-path directive context active (win32, gated by the posixPaths setting)')
|
|
544
664
|
} catch (error) {
|
|
545
665
|
console.log(TAG + ' context registration failed: ' + (error?.message ?? error))
|
|
546
666
|
}
|
|
@@ -618,4 +738,4 @@ export async function apply(ctx, config = {}) {
|
|
|
618
738
|
}
|
|
619
739
|
|
|
620
740
|
// Test surface: pure helpers, no Cordis context required.
|
|
621
|
-
export const _internal = { PRESET_IDS, translateMsysPath, translatePathArguments, MARKER_FILE, classify, materialize, cleanupOnDispose, firstUserRoot, hashTree, skillsHashes, syncDecision, installRegisterShim, baseForRoster, detectBase, pickComposition }
|
|
741
|
+
export const _internal = { PRESET_IDS, translateMsysPath, translatePathArguments, readPosixPaths, windowsToMsys, MARKER_FILE, classify, materialize, cleanupOnDispose, firstUserRoot, hashTree, skillsHashes, syncDecision, installRegisterShim, baseForRoster, detectBase, pickComposition }
|