@anionex/dsh-computer-use 0.3.2 → 0.3.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +4 -1
  3. package/README.zh.md +4 -1
  4. package/lib/client.js +1 -1
  5. package/lib/client.js.map +1 -1
  6. package/lib/config.js +37 -17
  7. package/lib/config.js.map +1 -1
  8. package/lib/confirmations.js.map +1 -1
  9. package/lib/exposure.js +4 -4
  10. package/lib/exposure.js.map +1 -1
  11. package/lib/index.js +5 -1
  12. package/lib/index.js.map +1 -1
  13. package/lib/leases.js.map +1 -1
  14. package/lib/providers/macos.js +27 -11
  15. package/lib/providers/macos.js.map +1 -1
  16. package/lib/skill.js +13 -2
  17. package/lib/skill.js.map +1 -1
  18. package/lib/tools.js +1 -1
  19. package/lib/tools.js.map +1 -1
  20. package/lib/types/client/index.d.ts +1 -1
  21. package/lib/types/client/index.d.ts.map +1 -1
  22. package/lib/types/config.d.ts +2 -0
  23. package/lib/types/config.d.ts.map +1 -1
  24. package/lib/types/confirmations.d.ts +1 -1
  25. package/lib/types/confirmations.d.ts.map +1 -1
  26. package/lib/types/index.d.ts.map +1 -1
  27. package/lib/types/leases.d.ts +2 -1
  28. package/lib/types/leases.d.ts.map +1 -1
  29. package/lib/types/providers/macos.d.ts +0 -1
  30. package/lib/types/providers/macos.d.ts.map +1 -1
  31. package/lib/types/skill.d.ts +7 -2
  32. package/lib/types/skill.d.ts.map +1 -1
  33. package/lib/types/tools.d.ts.map +1 -1
  34. package/lib/types/types.d.ts +3 -1
  35. package/lib/types/types.d.ts.map +1 -1
  36. package/lib/types/web.d.ts +2 -1
  37. package/lib/types/web.d.ts.map +1 -1
  38. package/lib/types.js.map +1 -1
  39. package/lib/web.js +18 -8
  40. package/lib/web.js.map +1 -1
  41. package/native/macos/Sources/Helper/CursorOverlay.swift +3 -0
  42. package/native/macos/Sources/Helper/main.swift +35 -19
  43. package/native/macos/bin/dsh-computer-use-helper +0 -0
  44. package/native/macos/manifest.json +3 -3
  45. package/package.json +64 -24
  46. package/scripts/model-e2e.mjs +7 -3
  47. package/scripts/session-transcript.mjs +4 -3
  48. package/src/client/index.tsx +4 -2
  49. package/src/config.ts +40 -18
  50. package/src/confirmations.ts +1 -1
  51. package/src/exposure.ts +5 -5
  52. package/src/index.ts +5 -1
  53. package/src/leases.ts +3 -2
  54. package/src/providers/macos.ts +31 -11
  55. package/src/skill.ts +14 -2
  56. package/src/tools.ts +3 -2
  57. package/src/types.ts +2 -1
  58. package/src/web.ts +21 -6
package/src/skill.ts CHANGED
@@ -2,8 +2,14 @@
2
2
 
3
3
  import type { SkillRegistration } from '@deepseek-ai/dsh-skill'
4
4
 
5
- /** Stable Skill name used by progressive exposure and durable restore. */
6
- export const COMPUTER_USE_SKILL_NAME = 'computer-use'
5
+ /** Namespaced entry avoids collisions with filesystem Skills in Agent presets. */
6
+ export const COMPUTER_USE_SKILL_NAME = 'dsh-computer-use'
7
+ /** Existing sessions and slash-command workflows continue to recognize this entry. */
8
+ export const LEGACY_COMPUTER_USE_SKILL_NAME = 'computer-use'
9
+ export const COMPUTER_USE_SKILL_NAMES: ReadonlySet<string> = new Set([
10
+ COMPUTER_USE_SKILL_NAME,
11
+ LEGACY_COMPUTER_USE_SKILL_NAME,
12
+ ])
7
13
 
8
14
  /** Complete model-visible operating and confirmation workflow. */
9
15
  export const COMPUTER_USE_SKILL_CONTENT = `# DSH Computer Use
@@ -127,3 +133,9 @@ export const COMPUTER_USE_SKILL: SkillRegistration = {
127
133
  source: 'runtime',
128
134
  content: COMPUTER_USE_SKILL_CONTENT,
129
135
  }
136
+
137
+ /** Compatibility alias for existing Sessions; preset Skills may shadow it. */
138
+ export const LEGACY_COMPUTER_USE_SKILL: SkillRegistration = {
139
+ ...COMPUTER_USE_SKILL,
140
+ name: LEGACY_COMPUTER_USE_SKILL_NAME,
141
+ }
package/src/tools.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  /** Focused model-facing Computer Use Tool definitions. */
2
2
 
3
+ import type { JsonValue } from '@deepseek-ai/dsh-util-values'
3
4
  import { createUserMessage, type ContentBlock } from '@deepseek-ai/dsh-llm'
4
- import { defineTool, type JsonValue, type ToolDefinition, type ToolRunContext, type ValueSchemaSpec } from '@deepseek-ai/dsh-tools'
5
+ import { defineTool, type ToolDefinition, type ToolRunContext, type ValueSchemaSpec } from '@deepseek-ai/dsh-tools'
5
6
  import {
6
7
  ComputerConfirmationToken,
7
8
  ComputerObservationId,
@@ -38,7 +39,7 @@ function deferVisionHandoff(exec: ToolRunContext, artifact: ComputerArtifact | u
38
39
  'Do not inspect OCR executables or use bash, tesseract, screencapture, or an ad hoc Swift/Python OCR implementation.',
39
40
  ].join(' '),
40
41
  }],
41
- source: { kind: 'plugin', plugin: 'dsh-computer-use' },
42
+ source: { kind: 'tool', callId: exec.callId },
42
43
  }))
43
44
  }
44
45
 
package/src/types.ts CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  import type { Agent } from '@deepseek-ai/dsh-agent'
4
4
  import type { Branded } from '@deepseek-ai/dsh-brand'
5
- import type { CallId } from '@deepseek-ai/dsh-llm'
5
+ import type { ToolRunContext } from '@deepseek-ai/dsh-tools'
6
+ type CallId = ToolRunContext['callId']
6
7
 
7
8
  /** Opaque identifier for one immutable observed UI state. */
8
9
  export type ComputerObservationId = Branded<'ComputerObservationId'>
package/src/web.ts CHANGED
@@ -6,6 +6,7 @@ import { SettingsConflictError, type SettingsDescriptor } from '@deepseek-ai/dsh
6
6
  import type {} from '@deepseek-ai/dsh-host-webserver'
7
7
  import {
8
8
  COMPUTER_USE_SETTINGS_NAMESPACE,
9
+ resolveConfig,
9
10
  type ComputerUseConfig,
10
11
  } from './config.ts'
11
12
  import type { ComputerUseStatus } from './types.ts'
@@ -59,11 +60,17 @@ function requestError(res: ServerResponse, status: number, code: string, message
59
60
  responseJson(res, status, { ok: false, error: { code, message } })
60
61
  }
61
62
 
62
- function sameOriginPost(req: IncomingMessage): boolean {
63
+ function sameOriginPost(req: IncomingMessage, authorizeUnmarkedPost?: (req: IncomingMessage) => boolean): boolean {
63
64
  const fetchSite = req.headers['sec-fetch-site']
64
65
  if (fetchSite === 'cross-site') return false
65
66
  const origin = req.headers.origin
66
- if (origin === undefined) return fetchSite === 'same-origin' || fetchSite === 'same-site' || fetchSite === 'none'
67
+ if (origin === undefined) {
68
+ if (fetchSite === 'same-origin' || fetchSite === 'same-site' || fetchSite === 'none') return true
69
+ // Desktop strips browser origin metadata before forwarding, but injects a
70
+ // Host-issued signed cookie. Verify it through Connection's own fence;
71
+ // mere Cookie header presence is not authentication.
72
+ return fetchSite === undefined && authorizeUnmarkedPost?.(req) === true
73
+ }
67
74
  const host = req.headers.host
68
75
  if (host === undefined) return false
69
76
  try {
@@ -123,7 +130,10 @@ function isSettingsConflict(error: unknown): boolean {
123
130
 
124
131
  /** Same-origin backend used by the optional client Settings section. */
125
132
  export class ComputerUseWebBackend {
126
- constructor(private readonly ctx: Context) {}
133
+ constructor(
134
+ private readonly ctx: Context,
135
+ private readonly authorizeUnmarkedPost?: (req: IncomingMessage) => boolean,
136
+ ) {}
127
137
 
128
138
  /** Current browser-safe Settings and health state. */
129
139
  snapshot(): ComputerUseSettingsSnapshot {
@@ -154,7 +164,7 @@ export class ComputerUseWebBackend {
154
164
  requestError(res, 405, 'method-not-allowed', 'Use GET or POST')
155
165
  return
156
166
  }
157
- if (!sameOriginPost(req)) {
167
+ if (!sameOriginPost(req, this.authorizeUnmarkedPost)) {
158
168
  requestError(res, 403, 'origin-rejected', 'The request must originate from this DSH Web application')
159
169
  return
160
170
  }
@@ -167,6 +177,7 @@ export class ComputerUseWebBackend {
167
177
  try {
168
178
  if (parsed.action === 'save') {
169
179
  if (!this.ctx.settings.writable) throw new Error('settings provider is read-only')
180
+ resolveConfig(parsed.value)
170
181
  await this.ctx.settings.replace(COMPUTER_USE_SETTINGS_NAMESPACE, parsed.value as object, parsed.expectedRevision)
171
182
  } else if (parsed.action === 'health') {
172
183
  await this.ctx.computerUse.health(AbortSignal.timeout(30000))
@@ -184,8 +195,12 @@ export class ComputerUseWebBackend {
184
195
 
185
196
  /** Attach the optional route when a Web host is present. */
186
197
  export function installComputerUseWeb(ctx: Context): void {
187
- const backend = new ComputerUseWebBackend(ctx)
188
- ctx.inject(['webServer'], (webCtx) => {
198
+ ctx.inject(['webServer', 'connection'], (webCtx) => {
199
+ const connection = (webCtx as Context & {
200
+ connection?: { requestRejection?: (req: IncomingMessage) => 401 | 403 | undefined }
201
+ }).connection
202
+ const backend = new ComputerUseWebBackend(webCtx, (req) =>
203
+ typeof connection?.requestRejection === 'function' && connection.requestRejection(req) === undefined)
189
204
  webCtx.effect(() => webCtx.webServer.register({
190
205
  kind: 'exact',
191
206
  path: COMPUTER_USE_SETTINGS_ROUTE,