dsh-gitbash-shell 0.33.1 → 0.34.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/CHANGELOG.md +20 -0
- package/README.md +5 -0
- package/dsh.plugin.json +1 -1
- package/package.json +1 -2
- package/src/compositions.js +17 -3
- package/src/index.js +57 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
> 倒序排列,新版本条目在最上面。条目格式:`## vX.Y.Z — YYYY-MM-DD` + 类型(feat / fix / docs / chore)+ 要点 + 相关链接。
|
|
4
4
|
> 纪律见 AGENTS.md「变更记录纪律」:发版前先更新本文件并随版本提交;事故复盘、复现与真机验证记录也记在这里。
|
|
5
5
|
|
|
6
|
+
## v0.34.1 — 2026-10-05
|
|
7
|
+
|
|
8
|
+
**类型**:chore(清理 `dsh.client.inject` 里的死引用 `@deepseek-ai/dsh-client-runtime`)
|
|
9
|
+
|
|
10
|
+
- **背景**:该包只在 dsh 0.1.0-rc.7 ~ 0.1.1-rc.2 期间存在(当时挂在 `packages/bundle/web-app` 的依赖里),自 **0.1.2-alpha.1 起被官方移除**(Web Client runtime unbundling;npm 上停在 `0.0.1-rc.1`);本插件源码对它已无任何引用,只剩 `dsh.client.inject` 这一条元数据残留。
|
|
11
|
+
- **原先的保留理由已失效**:此前复核曾有意保留该条,理由是「避免改变旧宿主排序」——0.1.0-rc.7~0.1.1-rc.2 上它确实是客户端启动图里的真实 row。自宿主下限抬升起本插件宿主下限为 `>=0.1.7-rc`,**该理由保护的那批宿主已不在服务范围内**,死引用因此可安全清除。
|
|
12
|
+
- **安全性**:加载器对 `inject` 里无对应 row 的名字本就静默跳过(官方 `packages/client/modules/src/client/system.ts`),而在服务范围(`>=0.1.7-rc`)内该包从未存在 ⇒ 删除前后行为一致,纯元数据清理。
|
|
13
|
+
- **验证**:`npm test` 全绿(101 项)。
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## v0.34.0 — 2026-10-04
|
|
17
|
+
|
|
18
|
+
**类型**:feat(跟随 dsh 0.2.1:宿主可用时三个全工具变体自动纳入官方时间上下文与提醒工具)
|
|
19
|
+
|
|
20
|
+
- **背景**:dsh 0.2.1 给每个全工具官方 preset(standard/ptc/cordis)新增两行——`time-context`(@deepseek-ai/dsh-time-context,请求时钟上下文)与 `tool-schedule`(@deepseek-ai/dsh-tool-schedule,提醒工具 schedule_create/delete/list/update),并给 subagent / subagent_fork 的 config 加 `toolFilter.deny` 四个 schedule_* 工具(官方「提醒工具按模式提供:极简模式和子代理不可用」);官方 minimal 无变化(0.1.7-rc.2 与 0.2.1 的 minimal.patch.yml sha256 逐字节一致)。
|
|
21
|
+
- **同步方式(探测式,不抬宿主下限)**:preset 行的包缺失会拒绝**整棵挂载**(AGENTS 不变量 2),所以新行不能无条件加——`src/index.js` 新增 `probeHostExtras(ctx)`:从 **`ctx.baseUrl`**(行挂载的同一解析基准,`prepareProfileEntries`)逐包 `require.resolve` 探测,可用才加行 + 加 toolFilter;探测一次每 boot,peer 翻转触发的 reconcile 重注册复用同一结果;**任何解析异常都降级为不可用,绝不 reject boot**。`minimalPluginsFor` 不动(minimal 无新行)。dsh ≤ 0.2.0 宿主行为逐字节不变(0.1.7 镜像),0.2.1+ 宿主全对齐(0.2.1 镜像)——`engines.dsh` 保持 `>=0.1.7-rc`。
|
|
22
|
+
- **组合与测试**:`pluginsFor` 增加 `hostExtras` 参数(`{ timeContext, toolSchedule }`,缺省全 false;toolFilter 跟随 toolSchedule 单独走)。冒烟 99 → 101 项(+hostExtras 专项 + probeHostExtras 单测,含抛异常降级与半探测边界);**`tests/align-official.mjs` 的 pins 升级到 dsh-v0.2.1-alpha.1**(standard/cordis/ptc 换新 sha;minimal 不变),对齐目标切为「全探测行集 × 0.2.1 文本」——本机实测 **alignment OK: all four variants mirror the official row sequence**(34/35/35/7 行);旧宿主形态由 smoke 的 0.1.7 镜像断言继续锁死。两处既有源码形状断言随签名同步(`pluginsFor` 形参、`registerVariant` 调用)。
|
|
23
|
+
- **上游预警(AGENTS 第 8 条追记)**:dsh 仓库有 **proposed** 状态的「让 shell 环境声明只负责键所有权」提案(2026-09-19)——落地后将删 `list()`、`BashEnvVariable`、描述对象与仅描述性校验,贡献方声明改为**显式只读键集合**。本插件 `shellEnv.register` 的 `variables: { DSH_PATH_DIALECT: { description } }` 正是描述对象形状,**提案实施的下一版 dsh 升级必须同步改贡献形状**(register/collect/所有权冲突/未声明拒绝语义不变)。
|
|
24
|
+
- 相关:[dsh v0.2.1-alpha.1 release notes](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.1-alpha.1)、[shell-env 提案(中文)](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/proposed/simplification/2026-09-19-shell-env-key-declarations.zh.md)。
|
|
25
|
+
|
|
6
26
|
## v0.33.1 — 2026-10-02
|
|
7
27
|
|
|
8
28
|
**类型**:docs(issue #14:README「保留官方沙箱语义」与 Windows 受限模式的实际行为不一致)
|
package/README.md
CHANGED
|
@@ -40,6 +40,11 @@ Git Bash 增量;跟随 dsh 升级的对齐由冒烟测试
|
|
|
40
40
|
**preset id 保持 `code-gitbash` 不变**——会话钉在 id 上,dsh 0.1.2 把内置 `code`
|
|
41
41
|
改名 `ptc` 时本插件的变体 id 就没有跟随(改名会让已固定的会话报 preset not found)。
|
|
42
42
|
|
|
43
|
+
**dsh 0.2.1 增量自动随行(v0.34.0)**:官方 0.2.1 给全工具 preset 加了时间上下文
|
|
44
|
+
(`time-context`)与提醒工具(`schedule_*`,子代理不可用)——本插件在 0.2.1+ 宿主上
|
|
45
|
+
探测到对应包即自动把这两行与 subagent 的 schedule_* deny 纳入三个全工具变体
|
|
46
|
+
(极简变体不加,与官方一致);旧宿主行为逐字节不变,**无需为此升级 dsh**。
|
|
47
|
+
|
|
43
48
|
## 安装(公开 npm 插件,推荐)
|
|
44
49
|
|
|
45
50
|
npm: [dsh-gitbash-shell](https://www.npmjs.com/package/dsh-gitbash-shell),
|
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.34.1",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "Windows 全模式 Git Bash:用 Git for Windows bash 替换 PowerShell 执行器,声明式注册 standard/minimal/code/cordis 的 Git Bash 变体 preset(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.34.1",
|
|
4
4
|
"description": "Windows 上让 agent 的每条 shell 命令改经 Git for Windows bash 执行;物化四个内置预设的 Git Bash 变体,统一 MSYS 盘根路径方言,侧栏终端接管可开关。· Run every agent shell command through Git for Windows bash on Windows; materialize Git Bash variants of the built-in presets, unify the MSYS drive-root path dialect, and adopt the sidebar terminal behind a switch.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
},
|
|
26
26
|
"client": {
|
|
27
27
|
"inject": [
|
|
28
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
29
28
|
"@deepseek-ai/dsh-client-locale",
|
|
30
29
|
"@deepseek-ai/dsh-client-ui-slots",
|
|
31
30
|
"@deepseek-ai/dsh-client-ui-settings"
|
package/src/compositions.js
CHANGED
|
@@ -63,11 +63,23 @@ When ready, call exit_plan_mode with the complete plan markdown, starting with a
|
|
|
63
63
|
* workflow setting is untouched and returns once it is not.
|
|
64
64
|
* @returns {object[]} the declarative plugins list.
|
|
65
65
|
*/
|
|
66
|
-
export function pluginsFor({ kind, gitBash, skillsDir, pythonActive = false }) {
|
|
66
|
+
export function pluginsFor({ kind, gitBash, skillsDir, pythonActive = false, hostExtras = {} }) {
|
|
67
67
|
const win = typeof process !== 'undefined' && process.platform === 'win32'
|
|
68
68
|
const bashDisabled = gitBash ? false : win
|
|
69
69
|
const pwshDisabled = gitBash ? true : !win
|
|
70
70
|
const workflowOn = kind !== 'ptc' && pythonActive !== true
|
|
71
|
+
// dsh 0.2.1 added two rows to every full-tool official preset — time-context
|
|
72
|
+
// (durable clock readings) and tool-schedule (the reminder tools) — plus a
|
|
73
|
+
// toolFilter deny of the four schedule_* tools on the subagent/subagent_fork
|
|
74
|
+
// configs (reminders never reach a subagent). A preset row whose package is
|
|
75
|
+
// absent rejects the WHOLE mount, so these ride a host probe (index.js
|
|
76
|
+
// probeHostExtras, resolved from ctx.baseUrl — the base rows mount from);
|
|
77
|
+
// absent/older hosts keep the byte-identical 0.1.7 row set. The deny list
|
|
78
|
+
// follows toolSchedule alone: denying tools that do not exist is noise.
|
|
79
|
+
const { timeContext = false, toolSchedule = false } = hostExtras
|
|
80
|
+
const subagentDeny = toolSchedule
|
|
81
|
+
? { toolFilter: { deny: ['schedule_create', 'schedule_delete', 'schedule_list', 'schedule_update'] } }
|
|
82
|
+
: {}
|
|
71
83
|
const rows = [
|
|
72
84
|
{
|
|
73
85
|
id: 'persona',
|
|
@@ -82,6 +94,7 @@ export function pluginsFor({ kind, gitBash, skillsDir, pythonActive = false }) {
|
|
|
82
94
|
name: '@deepseek-ai/dsh-agent-instructions',
|
|
83
95
|
config: { maxBytes: 65536 },
|
|
84
96
|
},
|
|
97
|
+
...(timeContext ? [{ id: 'time-context', name: '@deepseek-ai/dsh-time-context' }] : []),
|
|
85
98
|
{ id: 'tool-bash', name: '@deepseek-ai/dsh-tool-bash', ...off(bashDisabled) },
|
|
86
99
|
{ id: 'tool-pwsh', name: '@deepseek-ai/dsh-tool-pwsh', ...off(pwshDisabled) },
|
|
87
100
|
{ id: 'tool-fs', name: '@deepseek-ai/dsh-tool-fs' },
|
|
@@ -91,6 +104,7 @@ export function pluginsFor({ kind, gitBash, skillsDir, pythonActive = false }) {
|
|
|
91
104
|
config: { sampleOverCapGlobResults: false },
|
|
92
105
|
},
|
|
93
106
|
{ id: 'tool-jobs', name: '@deepseek-ai/dsh-tool-jobs' },
|
|
107
|
+
...(toolSchedule ? [{ id: 'tool-schedule', name: '@deepseek-ai/dsh-tool-schedule' }] : []),
|
|
94
108
|
...((kind === 'standard' || kind === 'ptc') ? [
|
|
95
109
|
{ id: 'skill-filesystem', name: '@deepseek-ai/dsh-skill-filesystem' },
|
|
96
110
|
{ id: 'tool-skill', name: '@deepseek-ai/dsh-tool-skill' },
|
|
@@ -136,12 +150,12 @@ export function pluginsFor({ kind, gitBash, skillsDir, pythonActive = false }) {
|
|
|
136
150
|
{
|
|
137
151
|
id: 'tool-subagent',
|
|
138
152
|
name: '@deepseek-ai/dsh-tool-subagent',
|
|
139
|
-
config: { provider: 'spawn', toolName: 'subagent', modelSelectionSettings: true, backgroundMode: 'continuable' },
|
|
153
|
+
config: { provider: 'spawn', toolName: 'subagent', modelSelectionSettings: true, backgroundMode: 'continuable', ...subagentDeny },
|
|
140
154
|
},
|
|
141
155
|
{
|
|
142
156
|
id: 'tool-subagent-fork',
|
|
143
157
|
name: '@deepseek-ai/dsh-tool-subagent',
|
|
144
|
-
config: { provider: 'fork', toolName: 'subagent_fork', backgroundMode: 'continuable' },
|
|
158
|
+
config: { provider: 'fork', toolName: 'subagent_fork', backgroundMode: 'continuable', ...subagentDeny },
|
|
145
159
|
},
|
|
146
160
|
{
|
|
147
161
|
id: 'tool-subagent-codex',
|
package/src/index.js
CHANGED
|
@@ -1628,17 +1628,63 @@ function cleanupLegacyTrees(presetIds) {
|
|
|
1628
1628
|
}
|
|
1629
1629
|
}
|
|
1630
1630
|
|
|
1631
|
+
/**
|
|
1632
|
+
* Probe the dsh 0.2.1 host additions for the variant compositions: every
|
|
1633
|
+
* full-tool official preset gained a `time-context` row (durable clock
|
|
1634
|
+
* readings) and a `tool-schedule` row (the reminder tools). A preset row whose
|
|
1635
|
+
* package is absent rejects the WHOLE mount, so the rows ride this probe: each
|
|
1636
|
+
* is added only when its package resolves from the HOST's module base —
|
|
1637
|
+
* `ctx.baseUrl`, the exact base `prepareProfileEntries` mounts preset rows
|
|
1638
|
+
* from, so the probe can never disagree with the mounter. On dsh <= 0.2.0 both
|
|
1639
|
+
* stay false and the row set stays byte-identical to the 0.1.7 mirror. Probed
|
|
1640
|
+
* once per boot; the profile's package set does not change under a running
|
|
1641
|
+
* host. minimal never gains the rows (the official minimal preset has none).
|
|
1642
|
+
* @param {object} ctx - cordis context (any fiber of the running host).
|
|
1643
|
+
* @param {Function} [resolve] - predicate override for tests; receives a
|
|
1644
|
+
* package specifier, resolves like `require.resolve`, returns boolean.
|
|
1645
|
+
* @returns {Promise<{timeContext: boolean, toolSchedule: boolean}>}
|
|
1646
|
+
*/
|
|
1647
|
+
export async function probeHostExtras(ctx, resolve) {
|
|
1648
|
+
let ok = resolve
|
|
1649
|
+
if (ok === undefined) {
|
|
1650
|
+
try {
|
|
1651
|
+
const { createRequire } = await import('node:module')
|
|
1652
|
+
const req = createRequire(ctx?.baseUrl ?? import.meta.url)
|
|
1653
|
+
ok = (specifier) => {
|
|
1654
|
+
try { req.resolve(specifier); return true } catch { return false }
|
|
1655
|
+
}
|
|
1656
|
+
} catch {
|
|
1657
|
+
ok = () => false
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
const [timeContext, toolSchedule] = await Promise.all([
|
|
1661
|
+
Promise.resolve(safeProbe(ok, '@deepseek-ai/dsh-time-context')).then(Boolean),
|
|
1662
|
+
Promise.resolve(safeProbe(ok, '@deepseek-ai/dsh-tool-schedule')).then(Boolean),
|
|
1663
|
+
])
|
|
1664
|
+
return { timeContext, toolSchedule }
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
/** Run one probe predicate; ANY failure reads as "absent" (a throwing
|
|
1668
|
+
* resolver must degrade the row away, never reject the boot). */
|
|
1669
|
+
function safeProbe(ok, specifier) {
|
|
1670
|
+
try {
|
|
1671
|
+
return ok(specifier)
|
|
1672
|
+
} catch {
|
|
1673
|
+
return false
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1631
1677
|
/**
|
|
1632
1678
|
* Register one variant definition; returns the unregister function. Mount
|
|
1633
1679
|
* failures stay visible through the roster's broken diagnostic instead of
|
|
1634
1680
|
* failing the boot.
|
|
1635
1681
|
*/
|
|
1636
|
-
async function registerVariant(ctx, presetId, { gitBashActive, skillsDir, pythonActive }) {
|
|
1682
|
+
async function registerVariant(ctx, presetId, { gitBashActive, skillsDir, pythonActive, hostExtras = {} }) {
|
|
1637
1683
|
const meta = PRESET_META[presetId]
|
|
1638
1684
|
if (!meta) return undefined
|
|
1639
1685
|
const plugins = meta.kind === 'minimal'
|
|
1640
1686
|
? minimalPluginsFor()
|
|
1641
|
-
: pluginsFor({ kind: meta.kind, gitBash: gitBashActive, skillsDir, pythonActive })
|
|
1687
|
+
: pluginsFor({ kind: meta.kind, gitBash: gitBashActive, skillsDir, pythonActive, hostExtras })
|
|
1642
1688
|
return ctx.agentPresets.register({
|
|
1643
1689
|
id: presetId,
|
|
1644
1690
|
name: meta.name,
|
|
@@ -1671,6 +1717,10 @@ async function runDeclarativeEra(ctx, presetIds, readSuppress) {
|
|
|
1671
1717
|
cleanupLegacyTrees(presetIds)
|
|
1672
1718
|
const gitBashActive = process.platform === 'win32'
|
|
1673
1719
|
const skillsDir = await resolveSkillsDir()
|
|
1720
|
+
// The dsh 0.2.1 additions (time-context / tool-schedule rows) probe once per
|
|
1721
|
+
// boot and ride every (re-)registration below — the profile's package set
|
|
1722
|
+
// cannot change under a running host.
|
|
1723
|
+
const hostExtras = await probeHostExtras(ctx)
|
|
1674
1724
|
/** presetId -> unregister, i.e. exactly what is live right now. */
|
|
1675
1725
|
const live = new Map()
|
|
1676
1726
|
let peerGitBash = false
|
|
@@ -1715,7 +1765,7 @@ async function runDeclarativeEra(ctx, presetIds, readSuppress) {
|
|
|
1715
1765
|
for (const presetId of want) {
|
|
1716
1766
|
if (live.has(presetId)) continue
|
|
1717
1767
|
try {
|
|
1718
|
-
const unregister = await registerVariant(ctx, presetId, { gitBashActive, skillsDir, pythonActive: peerPython })
|
|
1768
|
+
const unregister = await registerVariant(ctx, presetId, { gitBashActive, skillsDir, pythonActive: peerPython, hostExtras })
|
|
1719
1769
|
if (unregister) {
|
|
1720
1770
|
live.set(presetId, unregister)
|
|
1721
1771
|
console.log(TAG + " preset '" + presetId + "' registered declaratively")
|
|
@@ -1732,7 +1782,9 @@ async function runDeclarativeEra(ctx, presetIds, readSuppress) {
|
|
|
1732
1782
|
}
|
|
1733
1783
|
|
|
1734
1784
|
await reconcile()
|
|
1735
|
-
console.log(TAG + ' registered ' + live.size + ' preset(s) declaratively (' + [...live.keys()].join(', ') + ')'
|
|
1785
|
+
console.log(TAG + ' registered ' + live.size + ' preset(s) declaratively (' + [...live.keys()].join(', ') + ')' + (hostExtras.timeContext || hostExtras.toolSchedule
|
|
1786
|
+
? ' [dsh 0.2.1 additions: ' + (hostExtras.timeContext ? 'time-context' : '') + (hostExtras.timeContext && hostExtras.toolSchedule ? ' + ' : '') + (hostExtras.toolSchedule ? 'tool-schedule (subagents denied)' : '') + ']'
|
|
1787
|
+
: ''))
|
|
1736
1788
|
|
|
1737
1789
|
// The peer's capability: `ctx.inject` makes this independent of row order,
|
|
1738
1790
|
// and the child scope's disposer runs when the peer unmounts (or its row is
|
|
@@ -2443,4 +2495,4 @@ export async function apply(ctx, config = {}) {
|
|
|
2443
2495
|
|
|
2444
2496
|
}
|
|
2445
2497
|
// Test surface: pure helpers, no Cordis context required.
|
|
2446
|
-
export const _internal = { PRESET_IDS, PEER_COVERED_PRESET_ID, PEER_CAPABILITY, isDelegatedAgent, dialectApplies, PEER_PYTHON_FIELD, PEER_PYTHON_BACKEND_FIELD, peerFact, peerBackend, pythonBackendActive, effectivePresetIds, translateDispatch, translateMsysPath, translatePathArguments, rewriteCodePaths, scanCodeLiterals, programPrelude, translateGlobArguments, buildTranslateEnv, rewriteErrorContent, rewriteErrorMessage, rewriteFailureMessage, msysEcho, driveToMsys, pathEcho, ERROR_CONTENT_TOOLS, windowsToMsys, rewriteResultPaths, adoptSidebarShell, MARKER_FILE, classify, hashTree, installRegisterShim }
|
|
2498
|
+
export const _internal = { PRESET_IDS, PEER_COVERED_PRESET_ID, PEER_CAPABILITY, isDelegatedAgent, dialectApplies, PEER_PYTHON_FIELD, PEER_PYTHON_BACKEND_FIELD, peerFact, peerBackend, pythonBackendActive, effectivePresetIds, translateDispatch, translateMsysPath, translatePathArguments, rewriteCodePaths, scanCodeLiterals, programPrelude, translateGlobArguments, buildTranslateEnv, rewriteErrorContent, rewriteErrorMessage, rewriteFailureMessage, msysEcho, driveToMsys, pathEcho, ERROR_CONTENT_TOOLS, windowsToMsys, rewriteResultPaths, adoptSidebarShell, MARKER_FILE, classify, hashTree, installRegisterShim, probeHostExtras }
|