devharness 0.9.6 → 0.9.7

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 (60) hide show
  1. package/build/command-recorder-relocation.test.d.ts +2 -0
  2. package/build/command-recorder-relocation.test.d.ts.map +1 -0
  3. package/build/command-recorder-relocation.test.js +76 -0
  4. package/build/command-recorder-relocation.test.js.map +1 -0
  5. package/build/command-recorder.d.ts +1 -0
  6. package/build/command-recorder.d.ts.map +1 -1
  7. package/build/command-recorder.js +19 -1
  8. package/build/command-recorder.js.map +1 -1
  9. package/build/config.d.ts.map +1 -1
  10. package/build/config.js +5 -2
  11. package/build/config.js.map +1 -1
  12. package/build/helpers/paths-relocation.test.d.ts +2 -0
  13. package/build/helpers/paths-relocation.test.d.ts.map +1 -0
  14. package/build/helpers/paths-relocation.test.js +200 -0
  15. package/build/helpers/paths-relocation.test.js.map +1 -0
  16. package/build/helpers/paths.d.ts +35 -0
  17. package/build/helpers/paths.d.ts.map +1 -1
  18. package/build/helpers/paths.js +35 -0
  19. package/build/helpers/paths.js.map +1 -1
  20. package/build/issue-tracker-relocation.test.d.ts +2 -0
  21. package/build/issue-tracker-relocation.test.d.ts.map +1 -0
  22. package/build/issue-tracker-relocation.test.js +193 -0
  23. package/build/issue-tracker-relocation.test.js.map +1 -0
  24. package/build/issue-tracker.d.ts.map +1 -1
  25. package/build/issue-tracker.js +20 -4
  26. package/build/issue-tracker.js.map +1 -1
  27. package/build/mcp-supervisor.js +4 -3
  28. package/build/mcp-supervisor.js.map +1 -1
  29. package/build/self-restart.d.ts +5 -1
  30. package/build/self-restart.d.ts.map +1 -1
  31. package/build/self-restart.js +35 -5
  32. package/build/self-restart.js.map +1 -1
  33. package/build/self-restart.test.js +61 -17
  34. package/build/self-restart.test.js.map +1 -1
  35. package/build/server-manager-relocation.test.d.ts +2 -0
  36. package/build/server-manager-relocation.test.d.ts.map +1 -0
  37. package/build/server-manager-relocation.test.js +115 -0
  38. package/build/server-manager-relocation.test.js.map +1 -0
  39. package/build/server-manager-root-rebind.test.d.ts +2 -0
  40. package/build/server-manager-root-rebind.test.d.ts.map +1 -0
  41. package/build/server-manager-root-rebind.test.js +158 -0
  42. package/build/server-manager-root-rebind.test.js.map +1 -0
  43. package/build/server-manager.d.ts +19 -0
  44. package/build/server-manager.d.ts.map +1 -1
  45. package/build/server-manager.js +98 -4
  46. package/build/server-manager.js.map +1 -1
  47. package/build/supervisor/pidfile.d.ts +33 -6
  48. package/build/supervisor/pidfile.d.ts.map +1 -1
  49. package/build/supervisor/pidfile.js +76 -14
  50. package/build/supervisor/pidfile.js.map +1 -1
  51. package/build/supervisor/pidfile.test.js +37 -1
  52. package/build/supervisor/pidfile.test.js.map +1 -1
  53. package/build/tools/config-tools.d.ts.map +1 -1
  54. package/build/tools/config-tools.js +5 -0
  55. package/build/tools/config-tools.js.map +1 -1
  56. package/build/utils/modal-detection-core.test.js +21 -17
  57. package/build/utils/modal-detection-core.test.js.map +1 -1
  58. package/docs/messages.md +11 -0
  59. package/package.json +1 -1
  60. package/plugin/skills/devharness/SKILL.md +1 -1
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Local server records derive from the state root, so `relocateRoot` has to
3
+ * re-read them: without it the map built at startup keeps serving the
4
+ * previous root's servers, and the next `saveState` writes those records into
5
+ * the new root's file.
6
+ *
7
+ * Global records come from ~/.devharness, which no relocation moves, so they
8
+ * survive the rebind untouched.
9
+ *
10
+ * The relocation runs through `relocateRoot` (the production transaction in
11
+ * paths.ts), not through a hand-registered resource, so a missing
12
+ * registration in ServerManager fails here rather than passing on test-only
13
+ * wiring.
14
+ */
15
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
16
+ import { spawn } from 'child_process';
17
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'fs';
18
+ import { tmpdir } from 'os';
19
+ import { dirname, join } from 'path';
20
+ import { setWorkingDirOverride, initializePaths, getOutputPath, relocateRoot } from './helpers/paths.js';
21
+ import { ServerManager } from './server-manager.js';
22
+ let rootA;
23
+ let rootB;
24
+ let localFileA;
25
+ let localFileB;
26
+ let globalFile;
27
+ let originalGlobalDir;
28
+ function persistedServer(id, cwd, pid = -1) {
29
+ return {
30
+ type: 'native',
31
+ id,
32
+ command: 'node -e "setInterval(() => {}, 60000)"',
33
+ cwd,
34
+ pid,
35
+ autoRun: false,
36
+ startedAt: '2026-08-19T00:00:00.000Z',
37
+ monitorPort: false,
38
+ watch: false,
39
+ watchPaths: [],
40
+ };
41
+ }
42
+ function writeServersFile(filePath, servers, monitoredPorts = []) {
43
+ mkdirSync(dirname(filePath), { recursive: true });
44
+ writeFileSync(filePath, JSON.stringify({ version: 4, servers, monitoredPorts, pendingStartups: [] }, null, 2));
45
+ }
46
+ async function serverIds(manager) {
47
+ return (await manager.getStatus()).map(status => status.id).sort();
48
+ }
49
+ beforeEach(() => {
50
+ rootA = mkdtempSync(join(tmpdir(), 'devharness-sm-rebind-a-'));
51
+ rootB = mkdtempSync(join(tmpdir(), 'devharness-sm-rebind-b-'));
52
+ // Isolate the global store the way server-manager-relocation.test.ts does -
53
+ // saveState() writes the global file unconditionally.
54
+ originalGlobalDir = process.env.CDP_TOOLS_DIR;
55
+ process.env.CDP_TOOLS_DIR = join(rootA, '__global__');
56
+ initializePaths();
57
+ setWorkingDirOverride(rootB);
58
+ localFileB = getOutputPath('servers.json');
59
+ setWorkingDirOverride(rootA);
60
+ localFileA = getOutputPath('servers.json');
61
+ globalFile = getOutputPath('servers.json', { global: true });
62
+ });
63
+ afterEach(() => {
64
+ if (originalGlobalDir === undefined)
65
+ delete process.env.CDP_TOOLS_DIR;
66
+ else
67
+ process.env.CDP_TOOLS_DIR = originalGlobalDir;
68
+ initializePaths();
69
+ rmSync(rootA, { recursive: true, force: true });
70
+ rmSync(rootB, { recursive: true, force: true });
71
+ });
72
+ describe('relocateRoot: local server records follow the root', () => {
73
+ it('serves the new root\'s records and drops the old root\'s', async () => {
74
+ writeServersFile(localFileA, [persistedServer('a-only', rootA)]);
75
+ writeServersFile(localFileB, [persistedServer('b-only', rootB)]);
76
+ const manager = new ServerManager();
77
+ await manager.initialize();
78
+ expect(await serverIds(manager)).toEqual(['a-only']);
79
+ await relocateRoot(rootB);
80
+ expect(await serverIds(manager)).toEqual(['b-only']);
81
+ await relocateRoot(rootA);
82
+ expect(await serverIds(manager)).toEqual(['a-only']);
83
+ }, 20000);
84
+ it('serves nothing local when the new root has no records', async () => {
85
+ writeServersFile(localFileA, [persistedServer('a-only', rootA)]);
86
+ const manager = new ServerManager();
87
+ await manager.initialize();
88
+ await relocateRoot(rootB);
89
+ expect(await serverIds(manager)).toEqual([]);
90
+ }, 20000);
91
+ it('keeps global records, which no relocation moves', async () => {
92
+ writeServersFile(localFileA, [persistedServer('a-only', rootA)]);
93
+ writeServersFile(globalFile, [persistedServer('global-one', rootA)]);
94
+ const manager = new ServerManager();
95
+ await manager.initialize();
96
+ expect(await serverIds(manager)).toEqual(['a-only', 'global-one']);
97
+ await relocateRoot(rootB);
98
+ expect(await serverIds(manager)).toEqual(['global-one']);
99
+ }, 20000);
100
+ });
101
+ describe('relocateRoot: monitored ports follow the root', () => {
102
+ const portA = 39771;
103
+ const portB = 39772;
104
+ it('monitors the new root\'s ports and stops the old root\'s', async () => {
105
+ writeServersFile(localFileA, [persistedServer('a-only', rootA)], [
106
+ { port: portA, level: 'inform', description: 'Server: a-only' },
107
+ ]);
108
+ writeServersFile(localFileB, [persistedServer('b-only', rootB)], [
109
+ { port: portB, level: 'inform', description: 'Server: b-only' },
110
+ ]);
111
+ const manager = new ServerManager();
112
+ await manager.initialize();
113
+ const monitor = manager.getPortMonitor();
114
+ try {
115
+ expect(monitor.isMonitoring(portA)).toBe(true);
116
+ expect(monitor.isMonitoring(portB)).toBe(false);
117
+ await relocateRoot(rootB);
118
+ expect(monitor.isMonitoring(portB)).toBe(true);
119
+ expect(monitor.isMonitoring(portA)).toBe(false);
120
+ }
121
+ finally {
122
+ await monitor.stopAll();
123
+ }
124
+ }, 20000);
125
+ });
126
+ describe('relocateRoot: a running server recorded under the new root', () => {
127
+ let child = null;
128
+ afterEach(() => {
129
+ if (child?.pid) {
130
+ try {
131
+ process.kill(child.pid, 'SIGKILL');
132
+ }
133
+ catch {
134
+ // Already gone - the test that owns it stopped it through ServerManager.
135
+ }
136
+ }
137
+ child = null;
138
+ });
139
+ it('takes the veto, so relocating away from that root is refused', async () => {
140
+ writeServersFile(localFileA, [persistedServer('a-only', rootA)]);
141
+ // A process this ServerManager never started, the way a record left by
142
+ // another session names one: its log fds pin rootB all the same.
143
+ child = spawn('node', ['-e', 'setInterval(() => {}, 60000)'], { stdio: 'ignore' });
144
+ await new Promise(resolve => child.once('spawn', () => resolve()));
145
+ writeServersFile(localFileB, [persistedServer('b-live', rootB, child.pid)]);
146
+ const manager = new ServerManager();
147
+ await manager.initialize();
148
+ await relocateRoot(rootB);
149
+ expect(await serverIds(manager)).toEqual(['b-live']);
150
+ await expect(relocateRoot(rootA)).rejects.toThrow(/b-live/);
151
+ expect(getOutputPath().startsWith(rootB)).toBe(true);
152
+ // Stopping it drops the veto, so the root can move again.
153
+ await manager.stopServer('b-live');
154
+ await relocateRoot(rootA);
155
+ expect(await serverIds(manager)).toEqual(['a-only']);
156
+ }, 20000);
157
+ });
158
+ //# sourceMappingURL=server-manager-root-rebind.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-manager-root-rebind.test.js","sourceRoot":"","sources":["../src/server-manager-root-rebind.test.ts"],"names":[],"mappings":"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"}
@@ -237,6 +237,25 @@ export declare class ServerManager {
237
237
  */
238
238
  private killOrphanProcessesOnPort;
239
239
  private waitForPortRelease;
240
+ /**
241
+ * A running NativeRunner has already opened its stdout/stderr file
242
+ * descriptors against the current root (NativeRunner.start()) - an
243
+ * OS-level fact no relocation can redirect. Registering this for as long
244
+ * as the server is tracked as running turns a relocation attempt into a
245
+ * rejection instead of a server silently logging into a directory nothing
246
+ * else points at any more.
247
+ */
248
+ private registerRunningServerVeto;
249
+ /**
250
+ * Re-read local server records from the relocated root. `getServersFilePath`
251
+ * resolves through `getOutputPath`, so the map built at startup describes
252
+ * the previous root once the root moves; a list served from it names servers
253
+ * belonging to a directory nothing points at any more, and the next
254
+ * `saveState` writes those records into the new root's file. Every running
255
+ * server vetoes the relocation, so no local entry dropped here owns a live
256
+ * process. Global records live under ~/.devharness and stay put.
257
+ */
258
+ private rebindToRoot;
240
259
  /**
241
260
  * Start a server
242
261
  */
@@ -1 +1 @@
1
- {"version":3,"file":"server-manager.d.ts","sourceRoot":"","sources":["../src/server-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server-manager.d.ts","sourceRoot":"","sources":["../src/server-manager.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,7 @@
8
8
  import * as fs from 'fs';
9
9
  import * as net from 'net';
10
10
  import { debugLog } from './debug-logger.js';
11
- import { getOutputPath } from './helpers/paths.js';
11
+ import { getOutputPath, registerRootBound, unregisterRootBound } from './helpers/paths.js';
12
12
  import { atomicWriteFile } from './atomic-write.js';
13
13
  import { configManager } from './config.js';
14
14
  import { ServerFileWatcher } from './server-watcher.js';
@@ -364,6 +364,15 @@ export class PortMonitor {
364
364
  // ============================================================================
365
365
  // Server Manager
366
366
  // ============================================================================
367
+ /**
368
+ * Registry key for a running server's veto. The `server:` prefix keeps a
369
+ * server id from landing on the manager's own `server-manager` entry, which
370
+ * a bare id would replace - the registry is last-write-wins per name, so the
371
+ * collision would drop the rebind with nothing reported.
372
+ */
373
+ function rootBoundServerName(serverId) {
374
+ return `server:${serverId}`;
375
+ }
367
376
  export class ServerManager {
368
377
  servers = new Map();
369
378
  portMonitor = null;
@@ -378,6 +387,14 @@ export class ServerManager {
378
387
  claims;
379
388
  constructor(claimsStore = serverClaims) {
380
389
  this.claims = claimsStore;
390
+ // Local server records derive from the state root, so a relocation leaves
391
+ // this map describing the previous root. registerRootBound is
392
+ // last-write-wins per name, so the rebind belongs to the most recently
393
+ // constructed manager - the one a tool call reaches.
394
+ registerRootBound({
395
+ name: 'server-manager',
396
+ rebind: () => this.rebindToRoot(),
397
+ });
381
398
  }
382
399
  /**
383
400
  * Set the function used to check whether a CDP connection at a given
@@ -465,6 +482,7 @@ export class ServerManager {
465
482
  watchPaths: server.watchPaths,
466
483
  };
467
484
  this.servers.set(server.id, managed);
485
+ this.registerRunningServerVeto(server.id);
468
486
  // The process survived, but any watcher was tied to the previous
469
487
  // ServerManager instance (e.g. before devharness's own supervisor
470
488
  // restarted it) - re-establish it now.
@@ -865,6 +883,77 @@ export class ServerManager {
865
883
  await debugLog('ServerManager', `Port ${port} still in use after ${maxAttempts} attempts`);
866
884
  return false;
867
885
  }
886
+ /**
887
+ * A running NativeRunner has already opened its stdout/stderr file
888
+ * descriptors against the current root (NativeRunner.start()) - an
889
+ * OS-level fact no relocation can redirect. Registering this for as long
890
+ * as the server is tracked as running turns a relocation attempt into a
891
+ * rejection instead of a server silently logging into a directory nothing
892
+ * else points at any more.
893
+ */
894
+ registerRunningServerVeto(serverId) {
895
+ registerRootBound({
896
+ name: rootBoundServerName(serverId),
897
+ rebind: () => { }, // unreachable: this resource's own veto blocks every relocation while registered
898
+ veto: () => `managed server "${serverId}" is running and its log files cannot follow a relocated root`,
899
+ });
900
+ }
901
+ /**
902
+ * Re-read local server records from the relocated root. `getServersFilePath`
903
+ * resolves through `getOutputPath`, so the map built at startup describes
904
+ * the previous root once the root moves; a list served from it names servers
905
+ * belonging to a directory nothing points at any more, and the next
906
+ * `saveState` writes those records into the new root's file. Every running
907
+ * server vetoes the relocation, so no local entry dropped here owns a live
908
+ * process. Global records live under ~/.devharness and stay put.
909
+ */
910
+ async rebindToRoot() {
911
+ for (const [serverId, managed] of [...this.servers]) {
912
+ if (managed.global)
913
+ continue;
914
+ this.stopWatcher(managed);
915
+ unregisterRootBound(rootBoundServerName(serverId));
916
+ this.pendingStartups.delete(serverId);
917
+ this.servers.delete(serverId);
918
+ }
919
+ // Monitored ports are local-scope state (doSaveState writes them to the
920
+ // local file only), so they belong to the root that just went away.
921
+ await this.getPortMonitor().stopAll();
922
+ const persisted = await this.loadState(false);
923
+ for (const server of persisted.servers) {
924
+ const runner = createRunner(server.type || 'native', server.id);
925
+ runner.restore(server);
926
+ this.servers.set(server.id, {
927
+ id: server.id,
928
+ runner,
929
+ autoRun: server.autoRun,
930
+ monitorPort: server.monitorPort,
931
+ global: false,
932
+ watch: server.watch,
933
+ watchPaths: server.watchPaths,
934
+ });
935
+ // A record under this root can name a process another session started
936
+ // and left running; its log fds pin this root exactly as a server
937
+ // started here does, so it takes the same veto.
938
+ if (await runner.isRunning()) {
939
+ this.registerRunningServerVeto(server.id);
940
+ }
941
+ }
942
+ for (const pending of persisted.pendingStartups) {
943
+ if (!this.servers.has(pending.serverId))
944
+ continue;
945
+ this.pendingStartups.set(pending.serverId, {
946
+ serverId: pending.serverId,
947
+ startedAt: new Date(pending.startedAt),
948
+ timeoutAt: new Date(pending.timeoutAt),
949
+ acknowledged: pending.acknowledged,
950
+ reason: pending.reason,
951
+ });
952
+ }
953
+ if (persisted.monitoredPorts.length > 0) {
954
+ await this.getPortMonitor().restoreFromState(persisted.monitoredPorts);
955
+ }
956
+ }
868
957
  /**
869
958
  * Start a server
870
959
  */
@@ -915,6 +1004,7 @@ export class ServerManager {
915
1004
  watchPaths: resolvedWatchPaths,
916
1005
  };
917
1006
  this.servers.set(serverId, managed);
1007
+ this.registerRunningServerVeto(serverId);
918
1008
  if (watch) {
919
1009
  this.startWatcher(managed, resolvedWatchPaths);
920
1010
  }
@@ -1189,6 +1279,8 @@ export class ServerManager {
1189
1279
  if (!managed) {
1190
1280
  throw new Error(`Server "${serverId}" not found. Use list action to see servers.`);
1191
1281
  }
1282
+ // Once stopped, its log fds are closed - nothing left to block a relocation.
1283
+ unregisterRootBound(rootBoundServerName(serverId));
1192
1284
  // Clean up pending startup state
1193
1285
  this.removePendingStartup(serverId);
1194
1286
  // Stop watching and drop any queued/in-flight watch-restart state - a
@@ -1595,10 +1687,11 @@ export class ServerManager {
1595
1687
  await this.stopServer(serverId);
1596
1688
  }
1597
1689
  else {
1598
- // stopServer() (which also closes the watcher) is only called above
1599
- // when running - make sure a leaked watcher/pending state can't
1600
- // outlive removal either way.
1690
+ // stopServer() (which also closes the watcher and drops the relocation
1691
+ // veto) is only called above when running - make sure a leaked
1692
+ // watcher/veto/pending state can't outlive removal either way.
1601
1693
  this.stopWatcher(managed);
1694
+ unregisterRootBound(rootBoundServerName(serverId));
1602
1695
  }
1603
1696
  // stopServer() already drops this server's port monitors when it runs, but
1604
1697
  // removal has to cover the not-running path too - an orphaned block-level
@@ -1699,6 +1792,7 @@ export class ServerManager {
1699
1792
  watch: server.watch,
1700
1793
  watchPaths: server.watchPaths,
1701
1794
  });
1795
+ this.registerRunningServerVeto(server.id);
1702
1796
  await this.claims.claim(server.id, server.cwd, server.global);
1703
1797
  await debugLog('ServerManager', `Adopted server started elsewhere: ${server.id}`);
1704
1798
  }