dsh-workbuddy-connect 0.7.2 → 0.7.3-rc.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/lib/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as WORKBUDDY_VARIANTS, O as WorkBuddyUpstreamClient, Q as resolveAppVersion, S as CN_VARIANT, a as readHostHeartbeat, b as atRestKeyProviderFor, c as WORKBUDDY_CONNECT_VERSION, l as FALLBACK_WORKBUDDY_AI_MODELS, m as WorkBuddyCredentialStore, o as workbuddyHostHeartbeatPath, r as isHeartbeatProcessAlive, u as FALLBACK_WORKBUDDY_MODELS, w as variantFor } from "./host-heartbeat-DJb8l_4O.js";
2
+ import { C as WORKBUDDY_VARIANTS, O as WorkBuddyUpstreamClient, Q as resolveAppVersion, S as CN_VARIANT, a as readHostHeartbeat, b as atRestKeyProviderFor, c as WORKBUDDY_CONNECT_VERSION, l as FALLBACK_WORKBUDDY_AI_MODELS, m as WorkBuddyCredentialStore, o as workbuddyHostHeartbeatPath, r as isHeartbeatProcessAlive, u as FALLBACK_WORKBUDDY_MODELS, w as variantFor } from "./host-heartbeat-6rsz16S-.js";
3
3
  import { realpathSync } from "node:fs";
4
4
  import { fileURLToPath } from "node:url";
5
5
  //#region src/bin.ts
package/lib/client.js CHANGED
@@ -2772,7 +2772,7 @@ window.__ModuleLoader__.load({
2772
2772
  };
2773
2773
  //#endregion
2774
2774
  //#region src/version.ts
2775
- const WORKBUDDY_CONNECT_VERSION = "0.7.2";
2775
+ const WORKBUDDY_CONNECT_VERSION = "0.7.3-rc.1";
2776
2776
  //#endregion
2777
2777
  //#region src/client/WorkBuddyConfigPage.tsx
2778
2778
  /**
@@ -2031,16 +2031,45 @@ const WINDOWS_ELECTRON_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$
2031
2031
  * - **Output is JSON.** PowerShell does the escaping, so paths containing
2032
2032
  * spaces, commas, or quotes no longer depend on column positions, and only
2033
2033
  * the two values this plugin reads are collected.
2034
+ * - **The invocation wraps this script in a call-operator script block.**
2035
+ * Windows PowerShell 5.1 joins every argument after `-Command` into one
2036
+ * command string and parses that string as code, so a script whose text
2037
+ * merely starts with `param` never receives the trailing `-Root` tokens —
2038
+ * they land inside the script text, `$Root` stays empty, and every
2039
+ * fallback query fails as exit 2/3 (#105/#106/#107). See
2040
+ * {@link WINDOWS_POWERSHELL_QUERY_COMMAND}.
2034
2041
  *
2035
2042
  * The root is passed as a `-Root` argument, never interpolated into the
2036
- * command text.
2043
+ * command text, and it must pass {@link WINDOWS_REGISTRY_ROOT_PATTERN}
2044
+ * before the process starts — `-Command` arguments are re-parsed as code, so
2045
+ * only provably inert path characters may ride along.
2037
2046
  */
2038
2047
  const WINDOWS_REGISTRY_RELATIVE_POWERSHELL = "System32\\WindowsPowerShell\\v1.0\\powershell.exe";
2039
2048
  /** Exit code meaning the root key does not exist (a normal, expected outcome). */
2040
2049
  const WINDOWS_POWERSHELL_ROOT_ABSENT = 2;
2041
2050
  /** Exit code meaning the root exists but a part of it could not be read. */
2042
2051
  const WINDOWS_POWERSHELL_ROOT_UNREADABLE = 3;
2043
- const WINDOWS_POWERSHELL_QUERY_SCRIPT = [
2052
+ /**
2053
+ * The `-Command` value actually handed to `powershell.exe`: the query script
2054
+ * wrapped in a call-operator script block.
2055
+ *
2056
+ * Windows PowerShell 5.1 joins every argument that follows `-Command` into
2057
+ * one command string and runs that string as code. A bare `param(...)`
2058
+ * script therefore never binds the trailing `-Root <path>` tokens — they end
2059
+ * up inside the script text, `$Root` is empty, and the query ends as exit
2060
+ * 2/3: discovery incomplete, the app binary is never located, and at-rest
2061
+ * key resolution fails as a silent `signed-out` (#105/#106/#107, three
2062
+ * independent Windows reports on 0.7.2). The call operator makes the binding
2063
+ * explicit: the joined command becomes `& { …script… } -Root <path>`, and
2064
+ * `&` applies the named argument to the script block's `param` block — the
2065
+ * form #106 verified on a real 5.1 machine.
2066
+ *
2067
+ * Exported for the Windows-only integration spec, which replays this exact
2068
+ * text against a real `powershell.exe` 5.1 and derives the pre-fix 0.7.2
2069
+ * argv from it by removing the wrapper. `src/index.ts` does not re-export
2070
+ * it, so it is not part of the package's public API.
2071
+ */
2072
+ const WINDOWS_POWERSHELL_QUERY_COMMAND = `& { ${[
2044
2073
  "param([string]$Root)",
2045
2074
  "[Console]::OutputEncoding=[Text.Encoding]::UTF8;",
2046
2075
  "$ErrorActionPreference=\"Stop\";",
@@ -2054,9 +2083,53 @@ const WINDOWS_POWERSHELL_QUERY_SCRIPT = [
2054
2083
  " if ($null -ne $d -or $null -ne $i) { $out += [pscustomobject]@{ displayName=[string]$d; displayIcon=[string]$i } }",
2055
2084
  "};",
2056
2085
  "ConvertTo-Json -InputObject @($out) -Compress -Depth 3"
2057
- ].join(" ");
2058
- /** One discovery subprocess's own limits; see {@link WorkBuddyAtRestKeyProviderOptions}. */
2086
+ ].join(" ")} }`;
2087
+ /**
2088
+ * The only roots this tool will name on a `-Command` command line.
2089
+ *
2090
+ * `powershell.exe` re-parses everything after `-Command` as code, so a root
2091
+ * is handed over only when it is provably inert in that position: a hive
2092
+ * this file actually queries, then subkey components of plain path
2093
+ * characters — no spaces, quotes, subexpressions, or any other byte that
2094
+ * could change what the joined command does. Production roots are the fixed
2095
+ * {@link WINDOWS_REGISTRY_ROOTS}; anything else is refused before any
2096
+ * process starts, as "we could not check", never as executable text.
2097
+ */
2098
+ const WINDOWS_REGISTRY_ROOT_PATTERN = /^HK(?:LM|CU)(?:\\[A-Za-z0-9._-]+)+$/u;
2099
+ /**
2100
+ * One discovery subprocess's own limits; see {@link WorkBuddyAtRestKeyProviderOptions}.
2101
+ *
2102
+ * Governs the macOS discovery tools (Spotlight, plutil). The Windows registry
2103
+ * readers have their own, larger limit — {@link WINDOWS_REGISTRY_STEP_TIMEOUT_MS}.
2104
+ */
2059
2105
  const WORKBUDDY_DISCOVERY_STEP_TIMEOUT_MS = 3e3;
2106
+ /**
2107
+ * One Windows registry subprocess's own limit: `reg.exe` or the PowerShell
2108
+ * 5.1 fallback.
2109
+ *
2110
+ * Why larger than the macOS step limit: `reg query <root> /s` over a
2111
+ * software-dense uninstall tree takes seconds, not milliseconds. On GitHub's
2112
+ * windows-2022 and windows-2025 runner images (hundreds of installed
2113
+ * programs) the plain HKLM uninstall read exceeds 3s while HKCU finishes in
2114
+ * ~20ms; on a real user machine the PowerShell fallback itself ran
2115
+ * 135–270ms (#106). A 3s cap therefore cuts the HKLM read in half on
2116
+ * ordinary developer machines and reports the product absent when it is
2117
+ * merely slow to enumerate.
2118
+ *
2119
+ * Why this is safe to raise without touching the budget: the whole-discovery
2120
+ * budget ({@link WORKBUDDY_DISCOVERY_BUDGET_MS}, 10s) still bounds what a
2121
+ * user waits for — during a real discovery the budget abort remains the
2122
+ * effective ceiling, so this limit only decides whether a root that would
2123
+ * have finished inside the budget gets to finish, instead of being cut at 3s
2124
+ * mid-enumeration. For direct `queryUninstallRoot` callers (no outer
2125
+ * budget), this limit is the cap.
2126
+ *
2127
+ * Invariant, asserted by tests: never above the discovery budget. The
2128
+ * remaining known bound — a machine where every root is both slow *and*
2129
+ * non-ASCII, needing more than the budget in total — still ends as a safe
2130
+ * "we could not check" rather than a wrong answer.
2131
+ */
2132
+ const WINDOWS_REGISTRY_STEP_TIMEOUT_MS = 1e4;
2060
2133
  const MDFIND_MAX_OUTPUT_BYTES = 1048576;
2061
2134
  const PLUTIL_MAX_OUTPUT_BYTES = 65536;
2062
2135
  /**
@@ -2174,7 +2247,7 @@ function workBuddyWindowsDiscoveryTools() {
2174
2247
  "/s"
2175
2248
  ], {
2176
2249
  maxBuffer: WINDOWS_REGISTRY_OUTPUT_MAX_BYTES,
2177
- timeout: WORKBUDDY_DISCOVERY_STEP_TIMEOUT_MS,
2250
+ timeout: WINDOWS_REGISTRY_STEP_TIMEOUT_MS,
2178
2251
  windowsHide: true,
2179
2252
  encoding: "buffer"
2180
2253
  }, (error, stdout, stderr) => {
@@ -2211,6 +2284,10 @@ function workBuddyWindowsDiscoveryTools() {
2211
2284
  * three roots being absent is normal and must not fail the search.
2212
2285
  */
2213
2286
  const runFallback = (root, signal) => new Promise((resolve, reject) => {
2287
+ if (!WINDOWS_REGISTRY_ROOT_PATTERN.test(root)) {
2288
+ reject(new DiscoveryIncompleteError("the registry root was not a plain HKLM/HKCU path this tool may query"));
2289
+ return;
2290
+ }
2214
2291
  if (powershellPath === void 0) {
2215
2292
  reject(new DiscoveryIncompleteError("SystemRoot is not configured"));
2216
2293
  return;
@@ -2224,12 +2301,12 @@ function workBuddyWindowsDiscoveryTools() {
2224
2301
  "-NoProfile",
2225
2302
  "-NonInteractive",
2226
2303
  "-Command",
2227
- WINDOWS_POWERSHELL_QUERY_SCRIPT,
2304
+ WINDOWS_POWERSHELL_QUERY_COMMAND,
2228
2305
  "-Root",
2229
2306
  root
2230
2307
  ], {
2231
2308
  maxBuffer: WINDOWS_REGISTRY_OUTPUT_MAX_BYTES,
2232
- timeout: WORKBUDDY_DISCOVERY_STEP_TIMEOUT_MS,
2309
+ timeout: WINDOWS_REGISTRY_STEP_TIMEOUT_MS,
2233
2310
  windowsHide: true,
2234
2311
  encoding: "utf8"
2235
2312
  }, (error, stdout) => {
@@ -3938,7 +4015,7 @@ var WorkBuddyCatalog = class {
3938
4015
  };
3939
4016
  //#endregion
3940
4017
  //#region src/version.ts
3941
- const WORKBUDDY_CONNECT_VERSION = "0.7.2";
4018
+ const WORKBUDDY_CONNECT_VERSION = "0.7.3-rc.1";
3942
4019
  //#endregion
3943
4020
  //#region src/host-heartbeat.ts
3944
4021
  /**
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as validAppVersion, A as extractDisplayErrorMessage, B as randomSentinel, C as WORKBUDDY_VARIANTS, D as WORKBUDDY_UPDATE_PATH, F as prepareCnChatBody, G as readCliVersion, H as FALLBACK_CN_APP_VERSION, I as prepareInternationalChatBody, J as WORKBUDDY_APP_VERSION_FILENAME, K as resolveChatIdentity, L as regionOf, M as normalizeCredits, N as parseModelCatalog, O as WorkBuddyUpstreamClient, P as prepareChatBody, Q as resolveAppVersion, R as PROBE_EFFORT_CANDIDATES, S as CN_VARIANT, U as chatUserAgent, V as CN_APP_VERSION_FILENAME, W as fallbackChatIdentity, X as installedAppVersion, Y as appUserAgent, Z as readBundleVersion, _ as desktopAuthCandidatesFor, a as readHostHeartbeat, b as atRestKeyProviderFor, c as WORKBUDDY_CONNECT_VERSION, d as WorkBuddyCatalog, f as WORKBUDDY_AUTH_FILENAME, g as defaultDesktopAuthPath, h as defaultDesktopAuthCandidates, i as processStartTimeMs, j as modelWithCurrentPromotion, k as classifyUpstreamError, l as FALLBACK_WORKBUDDY_AI_MODELS, m as WorkBuddyCredentialStore, n as clearHostHeartbeat, o as workbuddyHostHeartbeatPath, p as WORKBUDDY_AUTH_FILE_ENV, q as validCliVersion, r as isHeartbeatProcessAlive, s as writeHostHeartbeat, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, u as FALLBACK_WORKBUDDY_MODELS, v as parseWorkBuddyAuth, w as variantFor, x as AI_VARIANT, y as workbuddyOwnAuthPath, z as probeModel } from "./host-heartbeat-DJb8l_4O.js";
1
+ import { $ as validAppVersion, A as extractDisplayErrorMessage, B as randomSentinel, C as WORKBUDDY_VARIANTS, D as WORKBUDDY_UPDATE_PATH, F as prepareCnChatBody, G as readCliVersion, H as FALLBACK_CN_APP_VERSION, I as prepareInternationalChatBody, J as WORKBUDDY_APP_VERSION_FILENAME, K as resolveChatIdentity, L as regionOf, M as normalizeCredits, N as parseModelCatalog, O as WorkBuddyUpstreamClient, P as prepareChatBody, Q as resolveAppVersion, R as PROBE_EFFORT_CANDIDATES, S as CN_VARIANT, U as chatUserAgent, V as CN_APP_VERSION_FILENAME, W as fallbackChatIdentity, X as installedAppVersion, Y as appUserAgent, Z as readBundleVersion, _ as desktopAuthCandidatesFor, a as readHostHeartbeat, b as atRestKeyProviderFor, c as WORKBUDDY_CONNECT_VERSION, d as WorkBuddyCatalog, f as WORKBUDDY_AUTH_FILENAME, g as defaultDesktopAuthPath, h as defaultDesktopAuthCandidates, i as processStartTimeMs, j as modelWithCurrentPromotion, k as classifyUpstreamError, l as FALLBACK_WORKBUDDY_AI_MODELS, m as WorkBuddyCredentialStore, n as clearHostHeartbeat, o as workbuddyHostHeartbeatPath, p as WORKBUDDY_AUTH_FILE_ENV, q as validCliVersion, r as isHeartbeatProcessAlive, s as writeHostHeartbeat, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, u as FALLBACK_WORKBUDDY_MODELS, v as parseWorkBuddyAuth, w as variantFor, x as AI_VARIANT, y as workbuddyOwnAuthPath, z as probeModel } from "./host-heartbeat-6rsz16S-.js";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { resolveImageAttachmentAccess, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
4
4
  import { dirname, join, resolve } from "node:path";
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dsh-workbuddy-connect",
3
3
  "displayName": "DSH WorkBuddy Connect",
4
4
  "description": "将 WorkBuddy 桌面 App 包含的模型自动接入 DeepSeek Harness — bring WorkBuddy desktop app models into DeepSeek Harness with zero configuration.",
5
- "version": "0.7.2",
5
+ "version": "0.7.3-rc.1",
6
6
  "author": "corrinehu",
7
7
  "keywords": [
8
8
  "dsh-plugin",