dsh-codex-style-computer-use 1.2.1 → 1.2.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/README.md +11 -1
- package/README.zh.md +11 -1
- package/lib/approval-attribution.js +39 -0
- package/lib/index.js +2 -0
- package/package.json +1 -1
- package/scripts/patch-approval-attribution.mjs +86 -0
- package/scripts/verify-package.mjs +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# dsh-codex-style-computer-use · Codex-style desktop control
|
|
2
2
|
|
|
3
|
+
**Give DeepSeek eyes and hands for Windows.**
|
|
4
|
+
|
|
5
|
+
Ask your agent to work with desktop apps: see the screen, find controls, click and type. Take over with your own mouse or keyboard whenever needed; the agent waits before continuing. Approval prompts remain enabled by default.
|
|
6
|
+
|
|
3
7
|
Windows desktop computer use for **DeepSeek Harness**: 18 desktop tools plus an Agent activation entry that observe and drive
|
|
4
8
|
native Windows applications through prebuilt C# workers included in the package. No PowerShell 7,
|
|
5
9
|
SDK or install-time builds are needed.
|
|
@@ -8,8 +12,12 @@ English | [中文](README.zh.md)
|
|
|
8
12
|
|
|
9
13
|
Windows only (`os: win32`). Requires Node.js ≥ 22 and the .NET Framework 4.x that Windows ships with.
|
|
10
14
|
|
|
15
|
+
**1.2.3 automatic fix:** normal installation/update now installs the approval-attribution correction for computer-use calls on affected DSH hosts. No manual host patch is required for those calls. Host approvals and audit remain authoritative; follow the host's restart indication after updating an already loaded plugin. See [1.2.3](docs/RELEASE-1.2.3.md).
|
|
16
|
+
|
|
11
17
|
**1.2.1 attention fix:** fixes a missing crypto import that prevented 1.2.0's native `probe` and `raise` requests from reaching the helper. Updating from 1.2.0 is required for this runtime fix; reinstalling 1.2.0 does not fix it. New releases are staged on npm's `next` tag before promotion to `latest`; the market's normal update follows `latest`. See [1.2.1 validation and release status](docs/RELEASE-1.2.1.md).
|
|
12
18
|
|
|
19
|
+
**1.2.2 GitHub pre-release:** includes a separately deployed DSH host approval-attribution patch and 14 regression cases. Plugin input and approval behavior is retained from 1.2.1. See [release contents and deployment scope](docs/RELEASE-1.2.2.md); GitHub publication does not update npm or the market automatically.
|
|
20
|
+
|
|
13
21
|
## What it does
|
|
14
22
|
|
|
15
23
|
- **Observe** — window list, screenshots (region / JPEG / PNG / downscaled), a Set-of-Marks map of
|
|
@@ -31,7 +39,7 @@ under `$DSH_HOME/data/computer-use/`.
|
|
|
31
39
|
|
|
32
40
|
Once the catalog submission is merged and synced, search **computer-use** and select **dsh-codex-style-computer-use**, by **ltmroberthk915** (npm maintainer: **ltmroberthk**). Click **Install**. Later, use **Update** or **Update all** for versions admitted by the host's release policy. The package includes both native helpers; no PowerShell 7 or build permission is needed.
|
|
33
41
|
|
|
34
|
-
Before catalog sync, use **Settings → Plugins → Add plugin
|
|
42
|
+
Before catalog sync, use **Settings → Plugins → Add plugin**. The corrected version is **`dsh-codex-style-computer-use@1.2.1`**; the unversioned name still resolves to 1.2.0 until promotion. Do not paste the GitHub repository URL: that selects the source-download path instead of the small prebuilt npm package. The default non-strict pnpm 11.7.0 configuration can install 1.2.1 immediately; an explicitly strict host policy can require waiting as described below. A newly added bundle can load live on the official Desktop host; check that its tools and skill appear. Restart from the tray when replacing an already loaded version, when the client remains stale, or when DSH reports **restart-required**.
|
|
35
43
|
|
|
36
44
|
### Releases less than 24 hours old
|
|
37
45
|
|
|
@@ -113,6 +121,8 @@ clicked at the wrong place.
|
|
|
113
121
|
|
|
114
122
|
## Approval modes
|
|
115
123
|
|
|
124
|
+
For a host that reports a disabled-prompt automatic refusal as “the user rejected tool”, see the [DSH approval attribution patch and regression test](docs/APPROVAL-ATTRIBUTION.md).
|
|
125
|
+
|
|
116
126
|
`automationMode` is set in the plugin's settings and defaults to `standard`:
|
|
117
127
|
|
|
118
128
|
| Mode | Observation | Actuation |
|
package/README.zh.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# dsh-codex-style-computer-use · Codex 风格桌面操控
|
|
2
2
|
|
|
3
|
+
**让 DeepSeek 看得见,也点得动。**
|
|
4
|
+
|
|
5
|
+
把 Windows 应用里的重复操作交给 AI:看屏幕、找控件、点鼠标、敲键盘。你一碰鼠标键盘,它就让出控制,等你操作完再继续;默认保留操作审批。
|
|
6
|
+
|
|
3
7
|
给 **DeepSeek Harness** 用的 Windows 桌面操控插件:18 个桌面工具加一个 Agent 激活入口,通过一个 C# worker
|
|
4
8
|
观察并驱动原生 Windows 应用。发布包已包含编译好的原生组件,无需安装 PowerShell 7、SDK 或执行编译命令。
|
|
5
9
|
|
|
@@ -7,8 +11,14 @@
|
|
|
7
11
|
|
|
8
12
|
仅支持 Windows(`os: win32`)。需要 Node.js ≥ 22 与 Windows 自带的 .NET Framework 4.x。
|
|
9
13
|
|
|
14
|
+
**1.2.3 自动修复:**正常安装或更新插件,即会为受影响宿主中的 computer-use 调用安装审批归因修正,无需手工修改宿主。审批决定与审计仍由宿主处理;更新已加载插件后按宿主提示重启。详见 [1.2.3](docs/RELEASE-1.2.3.md)。
|
|
15
|
+
|
|
10
16
|
**1.2.1 提醒修复:**补齐 crypto 导入,修复 1.2.0 原生 `probe` / `raise` 请求还未发送就抛错的问题。这次是运行时代码修复,需要从 1.2.0 更新;重复安装 1.2.0 无效。新版本先发布到 npm 的 `next`,再提升为 `latest`,市场普通更新跟随 `latest`。详见 [1.2.1 验证和发布状态](docs/RELEASE-1.2.1.md)。
|
|
11
17
|
|
|
18
|
+
宿主在禁用审批弹窗时仍提示“用户拒绝工具”的问题,详见 [DSH 审批归因补丁与回归测试](docs/APPROVAL-ATTRIBUTION.md)。
|
|
19
|
+
|
|
20
|
+
**1.2.2 GitHub 预发布:**收录独立部署的宿主审批归因补丁和 14 项回归测试。插件输入与审批行为延续 1.2.1,详见 [发布内容及部署范围](docs/RELEASE-1.2.2.md)。GitHub 发布不会自动更新 npm 或市场版本。
|
|
21
|
+
|
|
12
22
|
## 它能做什么
|
|
13
23
|
|
|
14
24
|
- **观察** —— 窗口列表、截图(区域 / JPEG / PNG / 降采样)、可点元素的 Set-of-Marks 编号图,
|
|
@@ -27,7 +37,7 @@
|
|
|
27
37
|
|
|
28
38
|
市场收录同步后,搜索 **computer-use**,选择 **dsh-codex-style-computer-use**,作者 **ltmroberthk915**(npm 维护者 **ltmroberthk**),点击**安装**。以后通过市场的**更新**或**全部更新**安装符合宿主发布策略的版本。两份原生组件都已随包提供,无需 PowerShell 7、SDK 或构建白名单。
|
|
29
39
|
|
|
30
|
-
|
|
40
|
+
目录尚未同步时,在 **设置 → 插件 → 添加插件** 输入修复版 **`dsh-codex-style-computer-use@1.2.1`**。正式标签提升前,省略版本号仍会装到 1.2.0。这里填 npm 包名即可;填写 GitHub 仓库网址会转为下载源码,容易受 GitHub 下载线路影响。默认非严格 pnpm 11.7.0 配置可以直接安装 1.2.1;宿主显式启用严格策略时,才可能需要等待冷却。首次新增 bundle 在官方桌面端可热加载;确认工具与 skill 已出现即可使用。替换已经加载的版本、客户端界面未刷新或界面明确提示 **restart-required / 需要重启** 时,再从托盘完整退出 DSH 并重新打开。
|
|
31
41
|
|
|
32
42
|
### 发布未满 24 小时
|
|
33
43
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Compatibility with hosts that conflate policy refusals and answerer refusals.
|
|
2
|
+
// Delegate first so the host still owns every approval and durable audit pair.
|
|
3
|
+
export function installApprovalAttribution (ctx, log) {
|
|
4
|
+
const tools = ctx.get('tools')
|
|
5
|
+
const original = tools?.serviceAsk
|
|
6
|
+
if (typeof original !== 'function') {
|
|
7
|
+
log.warn('approval attribution: host compatibility seam unavailable')
|
|
8
|
+
return
|
|
9
|
+
}
|
|
10
|
+
const ownDescriptor = Object.getOwnPropertyDescriptor(tools, 'serviceAsk')
|
|
11
|
+
const wrapped = async function (exec, ask) {
|
|
12
|
+
let policy
|
|
13
|
+
if (exec?.name?.startsWith('computer_') && exec.agent) {
|
|
14
|
+
const approval = this.ctx?.get?.('approval')
|
|
15
|
+
if (typeof approval?.effectivePolicy === 'function') policy = approval.effectivePolicy(exec.agent.session)
|
|
16
|
+
}
|
|
17
|
+
const result = await original.call(this, exec, ask)
|
|
18
|
+
// Newer/fixed hosts already provide their own reason. Only repair the exact
|
|
19
|
+
// known legacy attribution; never reinterpret cancellation or a grant.
|
|
20
|
+
if (!exec?.name?.startsWith('computer_') || result?.decision?.kind !== 'deny' ||
|
|
21
|
+
result.decision.reason !== `the user rejected tool "${exec.name}"`) return result
|
|
22
|
+
const reason = (policy === 'never'
|
|
23
|
+
? `tool "${exec.name}" requires approval, but approval prompts are disabled in this session (approval policy: never); the request was automatically rejected without asking the user`
|
|
24
|
+
: `approval for tool "${exec.name}" was rejected by the approval channel`) +
|
|
25
|
+
(ask?.reason ? `; approval required because: ${ask.reason}` : '')
|
|
26
|
+
return { ...result, decision: { ...result.decision, reason } }
|
|
27
|
+
}
|
|
28
|
+
ctx.effect(() => {
|
|
29
|
+
tools.serviceAsk = wrapped
|
|
30
|
+
return () => {
|
|
31
|
+
// Cordis returns a traced callable on get(); compare the stored method,
|
|
32
|
+
// not that newly created callable, to identify our own replacement.
|
|
33
|
+
if (Object.getOwnPropertyDescriptor(tools, 'serviceAsk')?.value !== wrapped) return
|
|
34
|
+
if (ownDescriptor) Object.defineProperty(tools, 'serviceAsk', ownDescriptor)
|
|
35
|
+
else delete tools.serviceAsk
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
log.info('approval attribution: installed for computer-use; host approvals and audit retained')
|
|
39
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { installHumanAttention } from './attention.js'
|
|
2
|
+
import { installApprovalAttribution } from './approval-attribution.js'
|
|
2
3
|
// dsh-computer-use — DSH Cordis plugin
|
|
3
4
|
//
|
|
4
5
|
// Native DSH integration for computer use. Mirrors the @anweat/dsh-browser
|
|
@@ -438,6 +439,7 @@ export function apply (ctx, config) {
|
|
|
438
439
|
return
|
|
439
440
|
}
|
|
440
441
|
if (!config.enabled) return
|
|
442
|
+
installApprovalAttribution(ctx, log)
|
|
441
443
|
registerBundledSkill(ctx, log)
|
|
442
444
|
raiseHuman = enableHumanAttention(ctx, log)
|
|
443
445
|
// THE QUESTION SERVICE, INJECTED LAZILY (merge-design.md §5.3 item 16 — defence in depth).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-style-computer-use",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "Codex-style Computer Use for DeepSeek Harness: Windows desktop control, screenshots, UI Automation, human input handoff, approval gates and prebuilt native workers. Install and update from dsh-market without PowerShell 7 or build steps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { createHash } from 'node:crypto'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
|
|
6
|
+
const automaticReason = 'the request was automatically rejected without asking the user'
|
|
7
|
+
const channelReason = 'was rejected by the approval channel'
|
|
8
|
+
|
|
9
|
+
function replaceOnce (source, before, after) {
|
|
10
|
+
if (source.split(before).length !== 2) throw new Error('Unsupported DSH tools source: missing or ambiguous patch anchor')
|
|
11
|
+
return source.replace(before, after)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Patch the compiled DSH 0.2.1-rc.2 tool runtime; policy and audit stay unchanged. */
|
|
15
|
+
export function patchApprovalAttribution (source) {
|
|
16
|
+
const start = source.indexOf('\tasync serviceAsk(exec, ask) {')
|
|
17
|
+
const end = source.indexOf('\n\t/**', start)
|
|
18
|
+
if (start < 0 || end < start) throw new Error('Unsupported DSH tools source: serviceAsk not found')
|
|
19
|
+
const method = source.slice(start, end)
|
|
20
|
+
const originalReason = '\t\t\t\t\treason: `the user rejected tool "${exec.name}"`'
|
|
21
|
+
if (method.includes(automaticReason) && method.includes(channelReason) &&
|
|
22
|
+
method.includes('const approvalPolicy = approval.effectivePolicy(exec.agent.session);') &&
|
|
23
|
+
!method.includes(originalReason)) return { source, changed: false }
|
|
24
|
+
let patched = replaceOnce(method,
|
|
25
|
+
'\t\tconst outcome = await approval.request({',
|
|
26
|
+
'\t\tconst approvalPolicy = approval.effectivePolicy(exec.agent.session);\n\t\tconst outcome = await approval.request({')
|
|
27
|
+
patched = replaceOnce(patched, originalReason,
|
|
28
|
+
'\t\t\t\t\treason: (approvalPolicy === "never"\n' +
|
|
29
|
+
'\t\t\t\t\t\t? `tool "${exec.name}" requires approval, but approval prompts are disabled in this session (approval policy: never); the request was automatically rejected without asking the user`\n' +
|
|
30
|
+
'\t\t\t\t\t\t: `approval for tool "${exec.name}" was rejected by the approval channel`) + (ask.reason ? `; approval required because: ${ask.reason}` : "")')
|
|
31
|
+
// Replace the obsolete attribution comment; this also keeps the verified
|
|
32
|
+
// compiled module small enough for a separate fixed-layout ASAR deployment.
|
|
33
|
+
const docStart = source.lastIndexOf('\t/**\n\t* Resolve an `ask` decision', start)
|
|
34
|
+
if (docStart < 0) throw new Error('Unsupported DSH tools source: expected serviceAsk documentation')
|
|
35
|
+
const doc = '\t/**\n\t* Resolve asks through approval, retaining fail-closed behavior.\n\t* Snapshot policy before requesting: the never policy skips all answerers.\n\t* A channel rejection alone does not identify a human as its source.\n\t*/\n'
|
|
36
|
+
return { source: source.slice(0, docStart) + doc + patched + source.slice(end), changed: true }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Preserve the original UTF-8 byte length, using trailing whitespace only. */
|
|
40
|
+
export function fixedLengthPayload (original, patched) {
|
|
41
|
+
const size = Buffer.byteLength(original)
|
|
42
|
+
const content = Buffer.from(patched)
|
|
43
|
+
if (content.length > size) throw new Error('Patched source exceeds the original byte length')
|
|
44
|
+
const output = Buffer.alloc(size, 0x20)
|
|
45
|
+
content.copy(output)
|
|
46
|
+
if (content.length < size) output[output.length - 1] = 0x0a
|
|
47
|
+
return output
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function main (args) {
|
|
51
|
+
let input, output, fixedLength = false
|
|
52
|
+
for (let i = 0; i < args.length; i++) {
|
|
53
|
+
if (args[i] === '--input' || args[i] === '--output') {
|
|
54
|
+
const option = args[i], value = args[++i]
|
|
55
|
+
if (!value || value.startsWith('--')) throw new Error(`Missing value for ${option}`)
|
|
56
|
+
if (option === '--input') {
|
|
57
|
+
if (input) throw new Error('Duplicate --input')
|
|
58
|
+
input = path.resolve(value)
|
|
59
|
+
} else {
|
|
60
|
+
if (output) throw new Error('Duplicate --output')
|
|
61
|
+
output = path.resolve(value)
|
|
62
|
+
}
|
|
63
|
+
} else if (args[i] === '--fixed-length') fixedLength = true
|
|
64
|
+
else throw new Error(`Unknown option: ${args[i]}`)
|
|
65
|
+
}
|
|
66
|
+
if (!input) throw new Error('Usage: node scripts/patch-approval-attribution.mjs --input <extracted dsh-tools/lib/index.js> [--output <new file>] [--fixed-length]')
|
|
67
|
+
if (output === input) throw new Error('--output must be a new file; installation replacement is a separate step')
|
|
68
|
+
const original = fs.readFileSync(input, 'utf8')
|
|
69
|
+
const patch = patchApprovalAttribution(original)
|
|
70
|
+
const payload = fixedLength ? fixedLengthPayload(original, patch.source) : Buffer.from(patch.source)
|
|
71
|
+
if (output) fs.writeFileSync(output, payload, { flag: 'wx' })
|
|
72
|
+
const hash = bytes => createHash('sha256').update(bytes).digest('hex')
|
|
73
|
+
console.log(JSON.stringify({
|
|
74
|
+
status: patch.changed ? 'patched' : 'already-patched',
|
|
75
|
+
preview: !output,
|
|
76
|
+
originalBytes: Buffer.byteLength(original), patchedBytes: payload.length,
|
|
77
|
+
originalSha256: hash(Buffer.from(original)), patchedSha256: hash(payload),
|
|
78
|
+
}, null, 2))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
82
|
+
try { main(process.argv.slice(2)) } catch (error) {
|
|
83
|
+
console.error(error.message)
|
|
84
|
+
process.exitCode = 1
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -22,7 +22,7 @@ for (const [source, binary] of [
|
|
|
22
22
|
assert.equal(manifest.platform, 'win32')
|
|
23
23
|
assert.equal(manifest.architecture, 'x64')
|
|
24
24
|
}
|
|
25
|
-
for (const file of ['lib/index.js', 'lib/core/native-runtime.js', 'lib/attention-native.js', 'skills/computer-use/SKILL.md', 'mcp/src/index.js']) assert(fs.existsSync(path.join(root, file)), file)
|
|
25
|
+
for (const file of ['lib/index.js', 'lib/approval-attribution.js', 'lib/core/native-runtime.js', 'lib/attention-native.js', 'skills/computer-use/SKILL.md', 'mcp/src/index.js']) assert(fs.existsSync(path.join(root, file)), file)
|
|
26
26
|
const attention = fs.readFileSync(path.join(root, 'lib/attention-native.js'), 'utf8')
|
|
27
27
|
assert(attention.includes("'./core/native-runtime.js'"), 'attention helper must use the bundled core')
|
|
28
28
|
console.log(`ok package: ${pkg.name}@${pkg.version}; prebuilt helpers verified; no install hooks`)
|