@ran-sh/dsh-crew 2.2.17 → 2.2.19

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-crew",
3
- "version": "2.2.17",
3
+ "version": "2.2.19",
4
4
  "description": "Dispatch subtasks to DeepSeek Harness (DSH) agents as native subagents with live progress",
5
5
  "author": {
6
6
  "name": "ZSeven-W"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ran-sh/dsh-crew",
3
- "version": "2.2.17",
3
+ "version": "2.2.19",
4
4
  "type": "module",
5
5
  "main": "./src/hub/entry.mjs",
6
6
  "bin": {
@@ -198,6 +198,23 @@ export function runResolvedDsh(cli, args = [], {
198
198
  };
199
199
  }
200
200
 
201
+ /**
202
+ * Environment for a package-manager child that installs Crew's own runtime.
203
+ *
204
+ * `--prefix`/`--dir` already pin the destination and scripts are disabled, so the
205
+ * child cannot be redirected by a variable — but it must not be *told* about the
206
+ * official Harness home either. Crew's installer is routinely run from inside a
207
+ * DSH session, whose ambient `DSH_HOME` is `~/.dsh`, and the contract these two
208
+ * installers carry is "installs only under the Crew home". Dropping the variable
209
+ * keeps that true by construction instead of by caller discipline, which is what
210
+ * the unit contract asserts and what an operator shell can silently break.
211
+ */
212
+ function packageManagerEnv(env) {
213
+ const child = { ...env };
214
+ delete child.DSH_HOME;
215
+ return child;
216
+ }
217
+
201
218
  /**
202
219
  * Install a reusable DSH CLI into Crew-owned state. This is the only helper
203
220
  * that may invoke a package manager, and callers must explicitly opt into it.
@@ -266,11 +283,12 @@ export function ensureCrewDshRuntime({
266
283
  ? ['add', '--dir', runtimeRoot, '--ignore-scripts', packageSpec]
267
284
  : ['install', '--prefix', runtimeRoot, '--no-package-lock', '--ignore-scripts', '--omit=dev', packageSpec];
268
285
  const invocation = buildDshInvocation(packageManager, packageArgs, { platform, comspec });
286
+ const installEnv = packageManagerEnv(env);
269
287
  const runInstall = () => runner(invocation.command, invocation.args, {
270
288
  encoding: 'utf8',
271
289
  stdio: ['ignore', 'pipe', 'pipe'],
272
290
  shell: invocation.shell,
273
- env: { ...env },
291
+ env: installEnv,
274
292
  });
275
293
  const result = runInstall();
276
294
  const cli = resolveDshCli({ home, env, platform, exists, findCommand, includeCompatibility: false, read });
@@ -457,11 +475,12 @@ export function installDshInto({
457
475
  ? ['add', '--dir', root, '--ignore-scripts', packageSpec]
458
476
  : ['install', '--prefix', root, '--no-package-lock', '--ignore-scripts', '--omit=dev', packageSpec];
459
477
  const invocation = buildDshInvocation(packageManager, packageArgs, { platform, comspec });
478
+ const installEnv = packageManagerEnv(env);
460
479
  const runInstall = () => runner(invocation.command, invocation.args, {
461
480
  encoding: 'utf8',
462
481
  stdio: ['ignore', 'pipe', 'pipe'],
463
482
  shell: invocation.shell,
464
- env: { ...env },
483
+ env: installEnv,
465
484
  });
466
485
  const result = runInstall();
467
486
  if (result.status !== 0) {
@@ -36,7 +36,7 @@ export {
36
36
  // included in the identity contract.
37
37
  const RUNTIME_ID = randomUUID();
38
38
 
39
- export const RUNTIME_VERSION = '2.2.17';
39
+ export const RUNTIME_VERSION = '2.2.19';
40
40
  export const HUB_PROTOCOL_VERSION = 1;
41
41
 
42
42
  export const HUB_CAPABILITIES = Object.freeze([
@@ -145,6 +145,60 @@ function Rotate-LaunchLog {
145
145
  } catch { }
146
146
  }
147
147
 
148
+ # A Crew-launched Harness process resolves its `env:` credential references from
149
+ # its own environment, and the launcher does not only run from a logon session.
150
+ # A terminal, a scheduled task, or an automation/agent shell can start it with a
151
+ # narrow environment, and then the Hub boots and answers every health check while
152
+ # its first job fails with CREDENTIAL_MISSING — the failure arrives long after the
153
+ # launch that caused it. The operator's persisted user scope is merged back in
154
+ # before any Harness process starts, which is what a logon start already had.
155
+ #
156
+ # Only names this process does not define are added, so a logon launch is
157
+ # unchanged and an explicitly exported value always wins over the registry. The
158
+ # skip list is what must not be taken from the user scope alone: its Path is one
159
+ # fragment of a real logon PATH (machine scope contributes the rest), and the rest
160
+ # describe the running process rather than the operator's profile.
161
+ $persistedEnvironmentSkip = @('Path', 'PATHEXT', 'ComSpec', 'SystemRoot', 'windir', 'TEMP', 'TMP', 'PSModulePath')
162
+
163
+ function Get-PersistedUserEnvironment {
164
+ $values = @{}
165
+ try {
166
+ $key = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment')
167
+ if ($key) {
168
+ try {
169
+ foreach ($name in $key.GetValueNames()) {
170
+ if ([string]::IsNullOrWhiteSpace($name)) { continue }
171
+ # GetValue expands REG_EXPAND_SZ, which is what a logon session sees.
172
+ $values[$name] = [string] $key.GetValue($name)
173
+ }
174
+ } finally { $key.Dispose() }
175
+ }
176
+ } catch { }
177
+ return $values
178
+ }
179
+
180
+ function Import-PersistedUserEnvironment {
181
+ $added = @()
182
+ $persisted = Get-PersistedUserEnvironment
183
+ if (-not $persisted) { return $added }
184
+ foreach ($entry in $persisted.GetEnumerator()) {
185
+ $name = [string] $entry.Key
186
+ if (-not $name) { continue }
187
+ if ($persistedEnvironmentSkip -contains $name) { continue }
188
+ if ($null -ne [Environment]::GetEnvironmentVariable($name, 'Process')) { continue }
189
+ [Environment]::SetEnvironmentVariable($name, [string] $entry.Value, 'Process')
190
+ $added += $name
191
+ }
192
+ return $added
193
+ }
194
+
195
+ function Remove-ImportedUserEnvironment {
196
+ param([string[]] $Names)
197
+ foreach ($name in @($Names)) {
198
+ if ($name) { [Environment]::SetEnvironmentVariable($name, $null, 'Process') }
199
+ }
200
+ }
201
+
148
202
  function Resolve-OfficialHarnessCommand {
149
203
  $shim = Get-Command dsh.cmd -CommandType Application -ErrorAction Stop | Select-Object -First 1
150
204
  $root = Join-Path (Split-Path -Parent $shim.Source) 'node_modules\@deepseek-ai\dsh'
@@ -487,14 +541,19 @@ function Open-OfficialFrontend {
487
541
  $stdout = Join-Path $logRoot ('dsh-official-web-{0}.out.log' -f $stamp)
488
542
  $stderr = Join-Path $logRoot ('dsh-official-web-{0}.err.log' -f $stamp)
489
543
  $previousHome = $env:DSH_HOME
544
+ $importedEnvironment = @()
490
545
  try {
491
546
  # The official application owns its normal state; no Crew plugin/profile
492
547
  # registration or repair is performed in this home by the launcher.
493
548
  $env:DSH_HOME = Join-Path $env:USERPROFILE '.dsh'
549
+ $importedEnvironment = Import-PersistedUserEnvironment
494
550
  $arguments = @(('"{0}"' -f $official.Entry), 'web', '--patch', ('"{0}"' -f $frontend.Path), '--host', '127.0.0.1', '--port', '3080')
495
551
  $process = Start-Process -FilePath $official.NodePath -ArgumentList $arguments -WindowStyle Hidden -PassThru `
496
552
  -RedirectStandardOutput $stdout -RedirectStandardError $stderr
497
- } finally { $env:DSH_HOME = $previousHome }
553
+ } finally {
554
+ $env:DSH_HOME = $previousHome
555
+ Remove-ImportedUserEnvironment -Names $importedEnvironment
556
+ }
498
557
  Write-LaunchLog ('Started official Harness on 3080; PID={0}. The official CLI opens the browser. Logs: {1}, {2}' -f $process.Id, $stdout, $stderr)
499
558
  $deadline = (Get-Date).AddSeconds($TimeoutSeconds)
500
559
  $nextProgress = (Get-Date).AddSeconds(5)
@@ -1306,8 +1365,10 @@ function Start-CrewService {
1306
1365
  $stdout = Join-Path $logRoot ('dsh-crew-{0}-{1}-{2}.out.log' -f $Service.Profile, $Service.Port, $serviceRunStamp)
1307
1366
  $stderr = Join-Path $logRoot ('dsh-crew-{0}-{1}-{2}.err.log' -f $Service.Profile, $Service.Port, $serviceRunStamp)
1308
1367
  $previousHome = $env:DSH_HOME
1368
+ $importedEnvironment = @()
1309
1369
  try {
1310
1370
  $env:DSH_HOME = $Service.Home
1371
+ $importedEnvironment = Import-PersistedUserEnvironment
1311
1372
  $arguments = @('--profile', $Service.Profile, '--host', '127.0.0.1', '--port', [string] $Service.Port, '--no-open')
1312
1373
  $launchArguments = if ($dshCliIsNodeEntry) { @($dshCli) + $arguments } else { $arguments }
1313
1374
  $process = Start-Process -FilePath $dshCommand -ArgumentList $launchArguments -WindowStyle Hidden -PassThru `
@@ -1326,6 +1387,7 @@ function Start-CrewService {
1326
1387
  Write-LaunchLog ('Started {0} on port {1}; PID={2}; stdout={3}; stderr={4}' -f $Service.Profile, $Service.Port, $process.Id, $stdout, $stderr)
1327
1388
  } finally {
1328
1389
  $env:DSH_HOME = $previousHome
1390
+ Remove-ImportedUserEnvironment -Names $importedEnvironment
1329
1391
  }
1330
1392
  }
1331
1393