dsh-gitbash-shell 0.8.0 → 0.9.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-gitbash-shell",
3
- "version": "0.8.0",
3
+ "version": "0.9.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.8.0",
3
+ "version": "0.9.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,31 @@ 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 host is Windows and the working shell is Git for Windows bash: use POSIX-style paths with MSYS drive roots everywhere — /c/Users/..., /e/project/... Every tool accepts this form: bash commands and the workdir parameter, and the file tools (read, write, edit, read_image, glob, grep) file_path/path arguments — MSYS roots are translated for them automatically, so never switch to a Windows form on their behalf. Never emit Windows drive-letter paths (C:\Users or C:/Users): when instructions, facts, or context show one, rewrite it to the POSIX form before use; when a tool result prints a Windows path, use its POSIX form (/c/...) in later calls.'
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
+
293
318
  // ── MSYS drive-root path translation (Windows, EVERY tool dispatch) ────────
294
319
  //
295
320
  // The directive below tells the model to use POSIX-style MSYS paths (/c/...)
@@ -502,6 +527,36 @@ export async function apply(ctx, config = {}) {
502
527
  const disposeGitBash = ctx.provide('gitBash', gitBashCapability)
503
528
  ctx.effect(() => disposeGitBash, 'dsh-gitbash-shell: gitBash capability')
504
529
 
530
+ // ── settings namespace: the posixPaths switch (default OFF) ──────────────
531
+ // Served on the host so the Plugins tab pairs it with the browser card
532
+ // (the tab dispatches Host-served namespaces ∩ registered cards). Dynamic
533
+ // imports keep the zero-dependency smoke path importable; the schema MUST
534
+ // be a callable schemastery object (dsh-settings calls schema(merged)).
535
+ try {
536
+ ctx.inject(['settings'], (sctx) => {
537
+ Promise.all([import('@deepseek-ai/dsh-settings'), import('@deepseek-ai/schemastery')])
538
+ .then(([ds, sm]) => {
539
+ const settings = sctx && sctx.settings
540
+ if (!settings || typeof settings.register !== 'function') return
541
+ const Schema = sm.default
542
+ // Era probe: newer dsh register() takes a plain string; the older
543
+ // one accepted the branded helper — one call satisfies both.
544
+ const ns = typeof ds.settingsNamespace === 'function'
545
+ ? ds.settingsNamespace(SETTINGS_NAMESPACE)
546
+ : SETTINGS_NAMESPACE
547
+ settings.register(ns, Schema.object({
548
+ posixPaths: Schema.boolean().default(false),
549
+ }))
550
+ console.log(`${TAG} settings namespace registered: ${SETTINGS_NAMESPACE} (posixPaths default off)`)
551
+ })
552
+ .catch((error) => {
553
+ console.log(`${TAG} settings namespace registration FAILED: ${error && error.stack || String(error)}`)
554
+ })
555
+ })
556
+ } catch (error) {
557
+ console.log(`${TAG} settings inject wiring failed: ${error?.message ?? error}`)
558
+ }
559
+
505
560
  // ── MSYS path translation on every tool dispatch (Windows only) ─────────
506
561
  // Covers every preset and mode: the wrapper sits on the global
507
562
  // tools/execute waterfall, through which model-direct calls, PTC run_code
@@ -510,7 +565,7 @@ export async function apply(ctx, config = {}) {
510
565
  try {
511
566
  ctx.on('tools/execute', (exec, next) => {
512
567
  try {
513
- if (exec && exec.arguments && typeof exec.arguments === 'object') {
568
+ if (exec && exec.arguments && typeof exec.arguments === 'object' && readPosixPaths(ctx)) {
514
569
  translatePathArguments(exec.arguments)
515
570
  }
516
571
  } catch { /* never block a call on translation */ }
@@ -538,9 +593,17 @@ export async function apply(ctx, config = {}) {
538
593
  pctx.effect(() => pctx.systemPrompt.context({
539
594
  name: 'gitbash-shell:posix-paths',
540
595
  order: 126,
541
- text: 'The host is Windows and the working shell is Git for Windows bash: use POSIX-style paths with MSYS drive roots everywhere — /c/Users/..., /e/project/... Every tool accepts this form: bash commands and the workdir parameter, and the file tools (read, write, edit, read_image, glob, grep) file_path/path arguments — MSYS roots are translated for them automatically, so never switch to a Windows form on their behalf. Never emit Windows drive-letter paths (C:\Users or C:/Users): when instructions, facts, or context show one, rewrite it to the POSIX form before use; when a tool result prints a Windows path, use its POSIX form (/c/...) in later calls.',
596
+ text: () => {
597
+ try {
598
+ const settings = pctx.get('settings')
599
+ const value = settings && typeof settings.get === 'function' ? settings.get(SETTINGS_NAMESPACE) : undefined
600
+ return value && value.posixPaths === true ? POSIX_DIRECTIVE_TEXT : ''
601
+ } catch {
602
+ return ''
603
+ }
604
+ },
542
605
  }), 'dsh-gitbash-shell: posix-path context')
543
- console.log(TAG + ' unified POSIX-path directive context active (win32)')
606
+ console.log(TAG + ' unified POSIX-path directive context active (win32, gated by the posixPaths setting)')
544
607
  } catch (error) {
545
608
  console.log(TAG + ' context registration failed: ' + (error?.message ?? error))
546
609
  }
@@ -618,4 +681,4 @@ export async function apply(ctx, config = {}) {
618
681
  }
619
682
 
620
683
  // 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 }
684
+ export const _internal = { PRESET_IDS, translateMsysPath, translatePathArguments, readPosixPaths, MARKER_FILE, classify, materialize, cleanupOnDispose, firstUserRoot, hashTree, skillsHashes, syncDecision, installRegisterShim, baseForRoster, detectBase, pickComposition }