@adhdev/daemon-core 0.8.13 → 0.8.15

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": "@adhdev/session-host-core",
3
- "version": "0.8.13",
3
+ "version": "0.8.15",
4
4
  "description": "ADHDev local session host core — session registry, protocol, buffers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.8.13",
3
+ "version": "0.8.15",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,13 +38,13 @@
38
38
  "author": "vilmire",
39
39
  "license": "AGPL-3.0-or-later",
40
40
  "dependencies": {
41
- "@agentclientprotocol/sdk": "^0.16.1",
42
41
  "@adhdev/session-host-core": "*",
42
+ "@agentclientprotocol/sdk": "^0.16.1",
43
43
  "@xterm/xterm": "^6.0.0",
44
44
  "chalk": "^5.3.0",
45
45
  "chokidar": "^5.0.0",
46
46
  "conf": "^13.0.0",
47
- "node-pty": "^1.1.0",
47
+ "node-pty": "^1.2.0-beta.12",
48
48
  "ws": "^8.19.0"
49
49
  },
50
50
  "bundleDependencies": [
@@ -27,15 +27,7 @@ import {
27
27
  type PtyRuntimeTransport,
28
28
  type PtyTransportFactory,
29
29
  } from './pty-transport.js';
30
- import { sanitizeSpawnEnv, ensureNodePtySpawnHelperPermissions } from './spawn-env.js';
31
-
32
- let pty: any;
33
- try {
34
- pty = require('node-pty');
35
- ensureNodePtySpawnHelperPermissions((msg: string) => LOG.info('CLI', msg));
36
- } catch {
37
- LOG.error('CLI', '[ProviderCliAdapter] node-pty not found. Terminal features disabled.');
38
- }
30
+ import { sanitizeSpawnEnv } from './spawn-env.js';
39
31
 
40
32
  // ─── Types ──────────────────────────────────────────
41
33
 
@@ -759,7 +751,10 @@ export class ProviderCliAdapter implements CliAdapter {
759
751
  );
760
752
  // On Windows, .cmd/.bat shims cannot be spawned directly — must go through cmd.exe
761
753
  const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
762
- const useShell = isWin ? (!!spawnConfig.shell || isCmdShim) : useShellUnix;
754
+ const useShellWin = isCmdShim
755
+ || !path.isAbsolute(binaryPath)
756
+ || isScriptBinary(binaryPath);
757
+ const useShell = isWin ? useShellWin : useShellUnix;
763
758
 
764
759
  if (useShell) {
765
760
  if (!spawnConfig.shell && !isWin) {
@@ -767,6 +762,8 @@ export class ProviderCliAdapter implements CliAdapter {
767
762
  }
768
763
  if (isCmdShim) {
769
764
  LOG.info('CLI', `[${this.cliType}] Using cmd.exe shell for .cmd/.bat shim: ${binaryPath}`);
765
+ } else if (isWin) {
766
+ LOG.info('CLI', `[${this.cliType}] Using cmd.exe shell on Windows: ${binaryPath}`);
770
767
  }
771
768
  shellCmd = isWin ? 'cmd.exe' : (process.env.SHELL || '/bin/zsh');
772
769
  if (isWin) {
@@ -780,6 +777,9 @@ export class ProviderCliAdapter implements CliAdapter {
780
777
  shellArgs = ['-l', '-c', fullCmd];
781
778
  }
782
779
  } else {
780
+ if (isWin && spawnConfig.shell) {
781
+ LOG.info('CLI', `[${this.cliType}] Spawning Windows binary directly without cmd.exe: ${binaryPath}`);
782
+ }
783
783
  shellCmd = binaryPath;
784
784
  shellArgs = allArgs;
785
785
  }
@@ -1,10 +1,20 @@
1
1
  import * as os from 'os';
2
-
3
- let pty: any;
4
- try {
5
- pty = require('node-pty');
6
- } catch {
7
- pty = null;
2
+ import { ensureNodePtySpawnHelperPermissions } from './spawn-env.js';
3
+
4
+ let cachedPty: any | null | undefined;
5
+
6
+ function loadNodePty(): any {
7
+ if (cachedPty !== undefined) return cachedPty;
8
+ try {
9
+ // Keep node-pty out of processes that delegate PTY ownership elsewhere
10
+ // (for example via session-host on Windows), so native PTY crashes do not
11
+ // take down the daemon just by importing this module.
12
+ cachedPty = require('node-pty');
13
+ ensureNodePtySpawnHelperPermissions();
14
+ } catch {
15
+ cachedPty = null;
16
+ }
17
+ return cachedPty;
8
18
  }
9
19
 
10
20
  export interface PtySpawnOptions {
@@ -90,6 +100,7 @@ class NodePtyRuntimeTransport implements PtyRuntimeTransport {
90
100
 
91
101
  export class NodePtyTransportFactory implements PtyTransportFactory {
92
102
  spawn(command: string, args: string[], options: PtySpawnOptions): PtyRuntimeTransport {
103
+ const pty = loadNodePty();
93
104
  if (!pty) throw new Error('node-pty is not installed');
94
105
  // Validate cwd — an invalid directory causes a native crash on Windows
95
106
  // (node-pty error code 267: ERROR_DIRECTORY) that bypasses JS try/catch
@@ -3,12 +3,31 @@
3
3
  */
4
4
 
5
5
  import { loadConfig, saveConfig } from '../config/config.js';
6
+ import type { ADHDevConfig } from '../config/config.js';
6
7
  import * as W from '../config/workspaces.js';
7
8
 
8
9
  export type WorkspaceCommandResult = { success: boolean;[key: string]: unknown };
9
10
 
11
+ function loadWorkspaceConfig(): ADHDevConfig | { error: string } {
12
+ try {
13
+ return loadConfig();
14
+ } catch (e: any) {
15
+ return { error: `Could not load config: ${e?.message || 'unknown error'}` };
16
+ }
17
+ }
18
+
19
+ function persistWorkspaceConfig(config: ADHDevConfig): { ok: true } | { error: string } {
20
+ try {
21
+ saveConfig(config);
22
+ return { ok: true };
23
+ } catch (e: any) {
24
+ return { error: `Could not save config: ${e?.message || 'unknown error'}` };
25
+ }
26
+ }
27
+
10
28
  export function handleWorkspaceList(): WorkspaceCommandResult {
11
- const config = loadConfig();
29
+ const config = loadWorkspaceConfig();
30
+ if ('error' in config) return { success: false, error: config.error };
12
31
  const state = W.getWorkspaceState(config);
13
32
  return {
14
33
  success: true,
@@ -24,11 +43,13 @@ export function handleWorkspaceAdd(args: any): WorkspaceCommandResult {
24
43
  const createIfMissing = args?.createIfMissing === true;
25
44
  if (!rawPath) return { success: false, error: 'path required' };
26
45
 
27
- const config = loadConfig();
46
+ const config = loadWorkspaceConfig();
47
+ if ('error' in config) return { success: false, error: config.error };
28
48
  const result = W.addWorkspaceEntry(config, rawPath, label, { createIfMissing });
29
49
  if ('error' in result) return { success: false, error: result.error };
30
50
 
31
- saveConfig(result.config);
51
+ const saveResult = persistWorkspaceConfig(result.config);
52
+ if ('error' in saveResult) return { success: false, error: saveResult.error };
32
53
  const state = W.getWorkspaceState(result.config);
33
54
  return { success: true, entry: result.entry, ...state };
34
55
  }
@@ -37,12 +58,14 @@ export function handleWorkspaceRemove(args: any): WorkspaceCommandResult {
37
58
  const id = (args?.id || '').trim();
38
59
  if (!id) return { success: false, error: 'id required' };
39
60
 
40
- const config = loadConfig();
61
+ const config = loadWorkspaceConfig();
62
+ if ('error' in config) return { success: false, error: config.error };
41
63
  const removed = (config.workspaces || []).find(w => w.id === id);
42
64
  const result = W.removeWorkspaceEntry(config, id);
43
65
  if ('error' in result) return { success: false, error: result.error };
44
66
 
45
- saveConfig(result.config);
67
+ const saveResult = persistWorkspaceConfig(result.config);
68
+ if ('error' in saveResult) return { success: false, error: saveResult.error };
46
69
  const state = W.getWorkspaceState(result.config);
47
70
  return { success: true, removedId: id, ...state };
48
71
  }
@@ -50,10 +73,12 @@ export function handleWorkspaceRemove(args: any): WorkspaceCommandResult {
50
73
  export function handleWorkspaceSetDefault(args: any): WorkspaceCommandResult {
51
74
  const clear = args?.clear === true || args?.id === null || args?.id === '';
52
75
  if (clear) {
53
- const config = loadConfig();
76
+ const config = loadWorkspaceConfig();
77
+ if ('error' in config) return { success: false, error: config.error };
54
78
  const result = W.setDefaultWorkspaceId(config, null);
55
79
  if ('error' in result) return { success: false, error: result.error };
56
- saveConfig(result.config);
80
+ const saveResult = persistWorkspaceConfig(result.config);
81
+ if ('error' in saveResult) return { success: false, error: saveResult.error };
57
82
  const state = W.getWorkspaceState(result.config);
58
83
  return {
59
84
  success: true,
@@ -70,7 +95,9 @@ export function handleWorkspaceSetDefault(args: any): WorkspaceCommandResult {
70
95
  return { success: false, error: 'id or path required (or clear: true)' };
71
96
  }
72
97
 
73
- let config = loadConfig();
98
+ const configResult = loadWorkspaceConfig();
99
+ if ('error' in configResult) return { success: false, error: configResult.error };
100
+ let config = configResult;
74
101
  let nextId: string;
75
102
 
76
103
  if (pathArg) {
@@ -89,7 +116,8 @@ export function handleWorkspaceSetDefault(args: any): WorkspaceCommandResult {
89
116
  const result = W.setDefaultWorkspaceId(config, nextId);
90
117
  if ('error' in result) return { success: false, error: result.error };
91
118
 
92
- saveConfig(result.config);
119
+ const saveResult = persistWorkspaceConfig(result.config);
120
+ if ('error' in saveResult) return { success: false, error: saveResult.error };
93
121
  const state = W.getWorkspaceState(result.config);
94
122
  return { success: true, ...state };
95
123
  }